There are five kinds of positioning that you can have in a webpage. Let's list them here.
Static is the default positioning system in css. Each other positioning system allows you to do something interesting, but at the expense of some trade-off. The trade-offs are different for each system, so this is both a review of each positioning scheme, but also a review of its trade-offs.
Static is by far the easiest to understand. By default, it figures out how big each block element's content is and then proceeds to stack each of those elements atop each other.
How's this look?
Check it!
By default, this displays something like the div to the right: the two paragraphs are stacked atop each other much like the text in this page.
The space between each of the paragraphs is their margin, most paragraphs, by default, have a top and bottom margin.
Not all things have a margin by default. You should never assume anything about these default values, instead, if you find yourself relying on a value you have not set, you should set it yourself so that you are not surprised if the default should one day change.
#a, #b { margin:0; }
paragraph one
paragraph two
Setting the margin for each paragraph to zero causes them to stack directly on top of each other. This is pretty much what we had expected before margin came into play.
Margins are great, you can do quite a bit with only margins if you're creative. Let's start with an example.
#c, #d, #e { height:50px; width:83px; font-family:helvetica; } #d { height:30px; margin-left:200px; margin-top:-50px; } #e{ height:80px; margin-left:100px; margin-top:-30px; }
i'm c!i'm di'm e
Suppose I have three divs. I can set their width and height. I can also move them around horizontally and vertically. Let's see what's happening in the css:
So the moral here is that in static positioning, even with margins, each div knows only about the div before it.
In vanilla static positioning, the height of the container is equal to the heights of all the container's children. That means that if you have 3 divs, each with a height of 50, the container will be 150px tall.
However, when you throw margins into the mix, you have to factor those into the total height of the container.
In the last example, the heights of all three divs is 160px. Add the margins together and you get -80px. This should make the container 80px tall, as tall as e.
Suppose things change a bit... what happens if e is only 20px tall? What happens to the height of the container?
#f, #g, #h { height:50px; width:83px; font-family:helvetica; } #g { height:30px; margin-left:200px; margin-top:-50px; } #h { height:20px; /* 60px shorter now! */ margin-left:100px; margin-top:-30px; }
i'm fi'm gi'm h
Everything in this case is the same, so let's redo the math: all the heights add up to 50+30+20 = 100px
. But, don't forget about the margins, those add up to -50 + -30 = -80
. Add those two: 100-80 = 20px
, which is exactly how tall the container to the right is.
This is a bit of a bummer because 20px is much shorter than the largest div here (f) which is 50px tall.
It's that last div's bottom location that specifies how tall the container is.
This is just something to be aware of so you don't get bitten in the future by seemingly inconsistent behavior. You can use css bits like min-height to keep this being an issue, but it's good to know the quirks.
As things go, static positioning is very powerful and works much of the time, so there's no reason not to use it. If that last div is guaranteed to get larger and larger (#h{height:auto; min-height:50px;}
)
Absolute is typically the easiest to grasp because you don't have to dilly dally with remembering margin values, instead, you move elements around the page however you please.
In this sense, it juts works with a slight exception: let's see an example of plain .
#abs_1{ width:100px; height: 50px; position:absolute; left:60px; top:80px; } #abs_2{ width:40px; height:30px; position:absolute; left:130px; top:40px; }
#1#2
Notice that the div abs_1
moves over 60px to the right and then 80px from the top of the white square to the right. At the same time, abs_2
moves 130px to the right and 40px down.
Notice that in this case, both divs do their own thing, neither knows about what the other is doing. This may seem great, but there are at least two things you want to be aware of:
abs_2
for whatever reason increases in size, it will overlap abs_1Let's try another example, but this time with containment, which was what ended up being weird with margins in the past example.
There is a key thing to keep in mind, notice how #abs_1
and #abs_2
are positioned with respect to the upper right hand corner of that white square.
Let's see what's really happening:
.static_box{ width:100px; /* height not set */ padding:5px; outline-color:red; margin-left:100px; } #abs_child1, #abs_child2{ width:50px; height:50px; } #abs_child1{ }
child 1child 2
Well, this is unsurprising. The two divs are stacked atop each other (remember, no absolute positioning yet!)
.static_box{ width:100px; /* height not set */ padding:5px; outline-color:red; margin-left:100px; } #abs_child3, #abs_child4 { width:50px; height:50px; } #abs_child3{ position:absolute; left:0; top:0; }
child 3child 4
Notice that the second that #abs_child3
is positioned absolutely it does two things:
#abs_child3
no longer takes up space in .abs_box
.#abs_child3
moves to the upper left hand corner of the white box... not the red one.So the moral here: an absolutely positioned element takes up no height. Whatever space it might have taken up in a static layout is completely ignored as if it never existed in the static layout.
There's another thing too: why does it go to the upper left hand corner of the white box and not the red one?
Remember #abs_child3 up there? Why does it move to the upper right hand corner of that white square and not, for example, the whole webpage?
The answer is this:
elements are positioned with respect to their containing block. For static elements, that's its first parent (i.e. .static_box
) but for absolutely positioned elements, the containing block is the first ancestor whose position is not static.
For emphasis, I'll repeat that
...for absolutely positioned elements, the containing block is the first ancestor whose position is not static.
Challenge question: what does this say about the white box?
These are not intuitive, so i suggest you play around more with this. As a challenge, think about what's going on with those white demo squares and inspect them to see if you're right.
Relative positioning it turns out is remarkable simple to figure out. It occupies space like a static element, but setting its top or left will cause it to move relative to its original position.
There's a catch, though. Let's see it.
#rel_1{ height:50px; width:100px; position:relative; }
i'm #rel_1
Unlike absolute positioning, it still occupies space, so that white box to the right increases in size as #rel_1 increases. If this seems an awful lot like static positioning, it's because not much has changed yet, so let's try something else.
#rel_2{ /* can you feel it?*/ height:50px; width:100px; position:relative; top:80px; }
i'm #rel_2
So looking over to that white div, it's got the same height as it did before, but looking over at #rel_2
, you'll notice that it seems to have broken out of the white box.
This is the one peculiarity of relative positioning.
At first we're tempted to think of it as static positioning on steroids (which seems right), but there's a catch. When we used margins to move stuff around, those margins actually affected the height of the element (and its containing block).
With relative positioning, the content is free to move around wherever it pleases, but it still occupies the space it would have taken up if it hadn't been moved.
This paragraph, for example, still takes up space in the left column of the page, but it appears on the right hand column of the page because it is relatively positioned and moved over to the left.
As you can imagine, this could be really confusing if you were trying to debug some quirky behavior.
The float property, initially the align
attribute on img
elements, is a combination of two print ideas: anchored objects and text wrap. The fact that it takes only two words to make this happen should instill some sort of alarm.
It is important to realize that this float idea began its life as a way of laying out images because you will then realize why it can be challenging to use it as a layout technique. This shouldn't discourage you from using it for layout, but caveat emptor and all that.
.float_1, .float_1 .image{ margin:5px; padding:5px; min-height:20px; } .float_1 p{ outline-color:green; margin:0; } .float_1 .image{ outline-color:red; width:60px; height:40px; }
Here's some text
Ok, so this is pretty unremarkable. I'm using this as a way of showing the classic HTML 1 situation where you have an image and some text. Now, say you want to marry these two in css: you have no real recourse except to apply the float property
So let's do it and see what happens
.float_2, .float_2 .image{ margin:5px; padding:5px; min-height:20px; } .float_2 p{ outline-color:green; margin:0; } .float_2 .image{ outline-color:red; width:60px; height:40px; float:left; }
some text
Some things to look at here:
So basically, all content until the bottom of the image is affected by the fact that it is floating.
By default, all elements after or below the floated element respect its float property. You can change this by setting the clear
css property. This tells the element to ignore any floats.
Let's see what happens if we clear the bottommost div
.float_3, .float_3 .image{ margin:5px; padding:5px; min-height:20px; } .float_3 p{ outline-color:green; margin:0; } .float_3 .image{ outline-color:red; width:60px; height:40px; float:left; } .f3_clear{ clear:left; /* ignores .image's float */ }
some text
Some things to think about:
clear
can have three different values: left/right/both
. Clearing right, for instance, would have done nothing. Clearing both would always work.When you use the float property for layout, you will often find yourself clearing defensively. When you use the float property for text-wrapping you will probably only clear headings, if at all.
The first question you may have is how to get the second div to wrap around the red image. There are two ways.
In the first case, what you do is place a cleared div just before closing the containing element. In effect, this creates an object that ignores the float (like the div above) and is also still enclosed in the containing div. Here's how that plays out.
.float_4, .float_4 .image{ margin:5px; padding:5px; min-height:20px; } .float_4 p{ outline-color:green; margin:0; } .float_4 .image{ outline-color:red; width:60px; height:40px; float:left; } .f4_clear{ clear:left; /* ignores .image's float */ }
some text
Notice that the cleared div at the bottom extends the reach of the parent div! This is great! It also means you have to add an extra piece of markup along the way. This may or may not be a big issue for you.