CSS Position
Positioning things on the web is …
I’m bad at writing intros, let’s dive in.
Document flow
flow is the way we refer to the browser laying out elements when there are no changes made to those elements.
Every element has a natural size, and elements in flow affect the location of the elements around it.
Boxes in normal flow are either block or inline, but not both at the same time.
- Inline ones sit in the same direction as text.
- Block ones are stacked along the cross axis.
The display
CSS property can set this.
p {display: block;}span {display: inline;}
There are 2 popular methods to take an element out of flow.
- absolute positioning, which we discuss later
- floating an element
Position
The default value for the CSS position
property is static
.
That’s why you almost never see it written in code, when a position
is set explicitly, it’s usually with a different value.
The most important aspect is if the item gets taken out of flow or not.
Values for position
that keep the element in the document flow:
static
relative
sticky
Values for position
that remove the element from the document flow:
absolute
fixed
Positioned elements can be offset by also defining a value for the top
, right
, bottom
, and left
properties with a distance.
Where that element is offset from is determined by the value you chose for position
.
Relative
Relatively positioned elements remain in flow. They are offset relative to their original position.
That final offset position has no effect on other elements, they are laid out in the regular flow as if nothing happend.
.two {position: relative;top: 50px;left: 50px;}
If you played around with the interactive demo above, you might have noticed setting a bottom
had no effect until you disabled top
.
The top
property takes priority.
bottom
is ignored if CSS sees both properties are set.
The same thing happens with left
and right
.
If CSS sees both, left
gets priority.
Absolute
An absolutely positioned element is removed from flow. Other elements are not affected by where the element is displayed on the page.
The absolute element is offset relative to the nearest positioned ancestor.
In other words: the closest element up the tree with a position
set (that isn’t static
).
If no top
, right
, bottom
, or left
offsets are set, the element is shown where it would be had it been in flow.
Because it was removed from the document flow, that means it will probably overlap the element after it though.
An absolutely positioned element is as small as it can be, based on its content.
.two {position: absolute;top: 50px;left: 50px;}
Contrary to the relative
demo, setting both left
and right
at the same time does work.
It will respect both unless a width
is set.
In that case you’re asking the browser to satisfy two conflicting commands and it will ignore right
again.
When both left and right are defined, and width constraints don’t prevent it, the element will stretch to satisfy both. If the element cannot stretch to satisfy both, the position of the element is overspecified. When this is the case, the left value has precedence when the container is left-to-right; the right value has precedence when the container is right-to-left.
So, position: absolute;
is pretty cool, and unlike that space trek quote, I also deal in absolutes.
One two punch
It is a very popular practice to set position: relative;
on the direct parent of an element with position: absolute;
.
That way the provided offsets will be offsets from that parent, which is usually what you want.
The results might be identical if you didn’t do that, but it’s good to avoid unexpected results.
Tweaking
Setting a top
, right
, bottom
, or left
offset would lose the element’s original position.
If that position is not quite right, adding a margin
is a useful tool.
It will affect the location of the absolutely positioned element but nothing else, as it is out of flow.
Centering
The method of placing an item with offsets makes it a bit awkward to exactly center things.
We don’t need to rely on magic numbers for those values however, a few techniques exist.
Margin
Setting the top
and bottom
to 0, with a margin-top
of auto
and a margin-bottom
of auto
will vertically center the absolutely positioned element.
The same logic can be applied to left
, and right
.
.absolute-center {position: absolute;top: 0;bottom: 0;left: 0;right: 0;margin: auto;width: 100px; /* has to be known for horizontal centering */height: 100px; /* has to be known for vertical centering */}
Transform
A solution that doesn’t need known dimensions leverages the transform
property.
- Move the element’s top left edge to be in the exact center of the parent.
- Scoot the element over by half the size of that element with a
transform
.
.absolute-center {position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);}
Both the margin and transform methods can be seen in this codepen.
Flexbox and grid
This surprised me (because I thought flexbox and grid would have no effect on items that are out of flow), but flexbox and grid can be used to place absolutely positioned elements!
Fixed
Fixed positioning is a specialized form of absolute positioning. The offsets are relative to the viewport, even when the page is scrolled.
Sticky
Elements with position: sticky
are offset relative to nearest scrolling
ancestor.
That enables a bunch of neat applications
.two {position: sticky;top: 50px;}
Sticky elements don’t always have to be offset from the top. Using multiple offsets works too.
The scrolling also doesn’t have to be vertical.
This CodePen has a horizontally scrolling parent with a sticky child that has a right
set.
Conclusion
Positioning allows us to take elements out of the normal document flow.
Some values remove an item from flow entirely, others don’t.
Elements in flow take up space, they affect elements next to them.