Category Archives: CSS

CSS

CSS – Centering an absolutely positioned element horizontally

This quick hint is one I find useful often in developing web-based applications, especially when creating system messages or dialog style popups.  Centering divs horizontally is actually really simple, as long as you know how.

What we’re after is something like this:-

centered-end

As you can see, the element has been centered horizontally and in my example just contains some sample text. I won’t go into any further detail as the contents are down to you, so here is the simple HTML for our centered div element;-

<div id="message">
    <h3>This is a popup message</h3>
</div>

Very simple, but it will do the trick for now. Ok, I’ll now step you through the CSS. Here’s the CSS we need to style and center the div element.

#message {
    width: 300px;
    height: 100px;
    border: 1px solid Black;
    background-color: White;
    padding: 20px;
    position: absolute;
    top: 50px;
    left: 50%;
    margin-left: -150px;
}
What it does

Ok, here we go with an explanation of how this works:-

First of all, we set a width and an height that we’re happy with.

width: 300px; /*Make sure this is divisible by two*/
height: 150px;

For me a width of 300px and height of 150px will do just fine, but you might want to change these depending on your needs. The important thing is that the width is easily divisible by two, as we’ll rely on this fact a little later.

Next, I’ve just set a simple border around the div element so that it stands out, and added a white background color.

border: 1px solid Black;
background-color: White;

The reason behind the white background color is simple. Without it, the background of the element is transparent, which means that if our dialog/message is positioned above any other content it will show through.

Ok. Next step is to add a little padding just to tidy things up a little (personal preference here, depending on what content you have in your div element).

padding: 20px;

Right then, here’s the clever bit – changing the position of the element to absolute:-

position: absolute;

Setting the position property to absolute takes the element out of the normal document flow, and this is where the magic happens. By setting top, left, right or bottom properties of an absolutely positioned element you can dictate exactly where you want it to appear within its container (in this case, the body). So with that in mind, let’s move our element. We’ll start by changing the top property of the document so it sits 150px away from the top of its container:-

top: 150px;

You can set this value to anything that you’re happy with, I’ve just stuck with 150px for this example. Now, we need to work on horizontally centering the element. This is the neat and nifty trick you need to be able to do this. First of all, let’s set the ‘left’ property to 50%:-

left: 50%;

Doing this sets the left edge of the div element to the dead center of the screen, and the beauty of using a percentage value means that, even if the browser window is resized, the left edge of the element will always be at the center of its container.

Finally, here comes the science. Because we’ve centered the left edge of the element, we now need to move the element so that its center is instead in the middle. How do we go about doing this? Earlier I mentioned that the width should be divisable by two exactly, and here’s why. Using a bit of maths we can figure that the center of a 300px element will be half of the width, or 150px. Make sense so far?

Ok, so what we need to do is to use a negative margin-left property which is half the width of the div (in this case, 150px as calculated). This will shift the element 150px to the left (the opposite direction of the margin due to the negative value) and therefore will put the center point of the element at 50% of the width of its container.

margin-left: -150px;

And that does exactly what we need.

It’s important to remember two things when centering divs in this way:-

  1. Set the position property to absolute
  2. Make sure you add a negative margin-left property of half the width of the element you are centering.

The rest is down to personal preference. You might even want to maybe add a box-shadow to the element to make it seem even more like it is floating above your content, like the example below:-

centered and floating

I kept things simple here and just added box-shadow: 8px 8px 15px Black but (depending on the browser you use, of course) you can be as creative as you like.

And that’s it! Simple when you know how. I often use this technique and ‘hide’ elements using display: none so that they can be revealed using a bit of jQuery when I want to alert users to something. How you use it is up to you!

There’s a working example here for you to look at and play with.

CSS

CSS – Collapsing margin confusion

Here’s a slightly confusing one for you.  The image below displays two divs, with class ‘parent’ and another ‘child’.  The markup and CSS is below the image.

image-1

Html
<div class="parent">
    <div class="child">
    <div>
<div>
Css
.parent {
    height: 100px;
    width: 100px;
    background-color: Black;
}

.child {
    height: 50px;
    width: 50px;
    background-color; Gray;
}

As you can see, the ‘child’ div sits inside the ‘parent’, flush with the top and left edges. What you expected to see? Good.

Now, what happens if we decide that the child should have a margin of 20px? What do you expect the result will be? Your ‘child’ css should look like this:-

.child {
    height: 50px;
    width: 50px;
    background-color: Gray;
    margin: 20px;
}

Here is what I expected to see…

image-2

But, here is what actually happened…

image-3

The left margin is as expected, but what has happened to the top? Rather than there being a nice black space above our child element, both divs have moved 20 pixels down…why is this?

The explanation

The reason behind this seemingly odd behaviour is actually by design, and is explained away by collapsing margins. For further information, let’s have a look at this quote from the ‘Collapsing Margins’ section of the Box Model page of the CSS specificiation:

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

Let’s decipher that a little more. The adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a SINGLE margin. In our example, that is what seems to have happened. The ‘parent’ element has no defined margin, so the margin of the child element has combined to form just one margin, which is active outside of its parent element, and has therefore has moved the parent down as well.

All making sense so far? What about the left hand side though? Why has the margin applied correctly there but not at the top?  The reason for this is that this behaviour only occurs vertically.

So, how can we fix this, especially when we wanted (or expected) things to look differently on screen?

There are actually three ways that I’m aware of to get around this:

1)  Use padding instead of margin

By getting rid of the margin and instead adding padding to the parent element, things will behave in the way you expect, but with a side effect (in some browsers).  Here is the revised CSS:-

.parent {
    height: 100px;
    width: 100px;
    background-color: Black;
    padding: 20px;
}

.child {
    height: 50px;
    width: 50px;
    background-color; Gray;
}

And this is how things look (in Chrome, anyway):-

image-4

So, what’s happened here? The whole parent box has increased in size by 20px….argh, not what we want, really, is it? Why has this happened.

The answer is down to another one of CSS’ quirks, but again is by design. According to the specification, the width or height of an element is defined by the width or height of the content, and the border, margins and padding are added on afterwards. You need to take this into account when using it, or things can go a little wonky..  If you’re using some other browsers however (IE6/7, I’m looking at you), the behaviour is as we initially expected, which can make things all the more confusing.  Keep an eye out for this issue when developing, people.  (Specifically, this link explains the situation in IE)

2)  Add a border to the parent element

Changing your CSS to this:-

.parent {
    height: 100px;
    width: 100px;
    background-color: Black;
    border: 1px solid Black;
}

.child {
    height: 50px;
    width: 50px;
    background-color; Gray;
    margin: 20px;
}

Will result in this:-

image-5

Which I’m sure you’ll agree looks much more like it! Only problem with this however is that the 1px border we’ve created has now added to the overall width and height of the element. If you check with a tool like Chrome’s inspector, you’ll see that the height and width of the element are now 102px (100px + 1px + 1px). Argh! Again!

image-6

Once again, the reason behind this behaviour is the same as above. The overall width of the element is the sum of the content, padding, border and margins. The defined value of 100px is only the width of the ‘content’, the other areas are added afterwards, which makes it seem like the whole element is larger than expected. Again, a bit of a pain, but if you work around it you can avoid any problems.

3) Make changes to the overflow property.

Adding overflow: auto; to the css of the parent element will make things behave as you expected. The CSS should look like this:-

.parent {
    height: 100px;
    width: 100px;
    background-color: Black;
    overflow: auto;
}

.child {
    height: 50px;
    width: 50px;
    background-color; Gray;
    margin: 20px;
}

And this will result in this onscreen as you originally wanted:-

image-2

Perfect, isn’t it? The overflow property set to anything other than ‘visible’ makes this work as it should, but it’s worth noting that this behaviour might also be different depending on whether or not you’re using IE.

As usual with CSS and HTML, especially when dealing with multiple browsers, there is usually more than one way to skin a cat. In fact, there are likely more ways of getting around this issue than the three I’ve discussed in this post, but I’m learning too. I’ll likely revisit this subject again at some point and would certainly like to investigate the idiosyncracies of the box model a little more in future posts. In the meantime I hope this has been of some use.

I’ve set up a simple test case for this on Codepen here, if you’d like to play around more. Comments, as always, are more than welcome.