• Date

  • By

    • Nicky Meuleman
  • Tagged

  • Older post

    Multilingual codeblocks

  • Newer post

    Multithreading in Rust

Table of contents
  1. Document flow
  2. Position
    1. Relative
    2. Absolute
      1. One two punch
      2. Tweaking
      3. Centering
        1. Margin
        2. Transform
        3. Flexbox and grid
    3. Fixed
    4. Sticky
  3. Conclusion

CSS Position

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


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.


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.


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.


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.


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.


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 */

A solution that doesn’t need known dimensions leverages the transform property.

  1. Move the element’s top left edge to be in the exact center of the parent.
  2. 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 positioning is a specialized form of absolute positioning. The offsets are relative to the viewport, even when the page is scrolled.


Elements with position: sticky are offset relative to nearest scrolling ancestor.

That enables a bunch of neat applications

Bacon ipsum dolor amet short loin spare ribs alcatra, fatback rump ribeye cupim sirloin drumstick picanha shankle pork chop strip steak. Ground round filet mignon fatback pork biltong ball tip, tenderloin cow bacon. Short ribs salami andouille, pastrami buffalo bacon venison.
Ham short loin sausage jowl tail chicken. Spare ribs short ribs buffalo sausage pig jerky jowl turducken shankle tail drumstick pork. Spare ribs beef ribs jerky filet mignon tri-tip turkey, capicola meatloaf meatball shank tenderloin cupim chicken. Pastrami turkey leberkas t-bone, tenderloin burgdoggen tri-tip bacon picanha short loin flank bresaola chicken. Boudin bacon turducken pork loin pancetta, ham shoulder pork strip steak chislic sirloin jerky. Rump shoulder venison, strip steak t-bone shankle kielbasa beef boudin cupim ham jerky picanha landjaeger tail. Turducken drumstick brisket salami, frankfurter ham hock spare ribs short ribs chislic tongue pork belly landjaeger andouille pancetta chicken. Ribeye turkey kevin boudin, doner swine pork belly ham chuck. Ham porchetta ham hock, tail drumstick kevin sausage jowl biltong chuck landjaeger bresaola hamburger. Pork ball tip frankfurter salami short ribs. Landjaeger pork belly boudin flank. Pork drumstick filet mignon, chislic bacon frankfurter ball tip venison corned beef alcatra shoulder beef sirloin spare ribs sausage. Ball tip hamburger chislic boudin chicken t-bone tail tri-tip landjaeger ham andouille turducken. Short ribs burgdoggen turducken chicken, pig t-bone rump biltong shankle picanha alcatra pork chop.
.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.


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.

affect other elements' location?absolute positioningNOsomething elseYES

Designed and developed by Nicky Meuleman

Built with Gatsby. Hosted on Netlify.