Understanding positioning in CSS
Tags: css, beginners, webdev
Published: 2019-12-18 09:39:48

---
title: Understanding positioning in CSS
published: true
date: 2019-12-18 00:00:00 UTC
tags: css, beginners, webdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/8g5jclkqa6ifjjo9rxy2.png
canonical_url: https://www.chenhuijing.com/blog/understanding-positioning-in-css/
---
CSS layout is not just one individual CSS property or even module. Everything on the web [is a box](https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#visual-model-intro). And the layout of these boxes are determined the following:

- box dimensions and type
- positioning scheme (normal flow, float, and absolute positioning)
- relationships between elements in the document tree
- external information (e.g., viewport size, intrinsic dimensions of images, etc.)

From this bit of information alone, we can pick out the following CSS modules (including those in draft status):

- [CSS Display Module Level 3](https://www.w3.org/TR/css-display-3/) (CR)
- [CSS Box Model Module Level 3](https://www.w3.org/TR/css-box-3/) (WD)
- [CSS Positioned Layout Module Level 3](https://www.w3.org/TR/css-position-3/) (WD)
- [CSS2.1 section 9.5 Floats](https://www.w3.org/TR/CSS21/visuren.html#floats) (REC)

The point I’m making here is, if you’d like to be fully equipped to build any layout you can imagine with CSS, I suggest understanding these different CSS modules and how they interact with each other. It definitely helped me out when I did so.

In all fairness, I really dug into all of it when I was preparing for my CSS Day talk back in 2018, which was pretty much 45 minutes about boxes. All [talk details on Notist](https://noti.st/huijing/B3BMi1/box-alignment).

## Positioning schemes

After boxes are generated, the way they are laid out depends on which positioning scheme they fall into:

- Normal flow
- Floats
- Absolute positioning

![Boxies in normal flow](https://www.chenhuijing.com/assets/images/posts/css-positioning/normal.svg)

Normal flow is the default, where boxes are laid out one after another, and will not overlap or intrude into each others’ space. All boxes will be on the same stacking context as well.

![Boxies with a floated friend](https://www.chenhuijing.com/assets/images/posts/css-positioning/float.svg)

Boxes that are floated are considered _out-of-flow_. When a box is floated, it is first laid out according to normal flow, but then is taken out the flow and shifted as far to the left or right as possible (depending on the float value).

Content will then flow along the side of the floated box. But the floated boxes still remain on the same stacking context as the non-floated ones.

![Boxies with an absolutely positioned friend](https://www.chenhuijing.com/assets/images/posts/css-positioning/absolute.svg)

An absolutely positioned box is completely removed from normal flow altogether, and its position is assigned with respect to its containing block.

The positioning algorithms used to calculate the position of a box on the page is determined by the `position` and `float` properties. I’ll try my best to explain this in a way that makes sense. But first, let’s look at them individually.

## The `position` property

There are several values for this property, with `sticky` being added in Level 3 of the Positioned Layout Module, and currently supported in most major browsers even though it is still in a working draft status.

### `position: static`

The default position value of any box. This results in the box being laid out in normal flow and the properties of `top`, `bottom`, `left` and `right` (also known as box offset values) will have no effect because the box is considered **not positioned**.

![Default layout of unpositioned boxes](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-static.svg)

### `position: relative`

Applying a `position` of `relative` to a box makes it **positioned** , and now the `top`, `bottom`, `left` and `right` values will have some effect.

The box will initially be laid out according to normal flow, then depending on the aforementioned box offset values, will be offset relative to its normal position.

![Relatively positioned box with top and left offsets](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-relative.svg)

If there are other non-positioned boxes next to this positioned box, they will **not** be affected even if offset values are present. This means there may be the possibility of overlap.

Also, if the offset causes the box to have overflow, this may result in scrolling, which would affect layout. When a box becomes relatively positioned, it becomes the new containing block for its children.

### `position: sticky`

A sticky positioned box works similarly to that of a relatively positioned box. The difference is that the offset is computed to the nearest ancestor with a **scrolling box** , or the viewport if none such ancestor exists.

So a little while ago, my friend, Yong Jun asked the question of why applying `position: sticky` alone on a box is insufficient to achieve the sticky effect. The box, without any offsets, behaves as though it was in normal flow, because it is.

Only when the offset values are something other than `auto` will the box start to behave differently from a relatively positioned box. The wording in the specification comes across slightly cryptic to me, but my understanding is that there is an intersection between the sticky box and its containing box when you apply a box offset value.

![Initial position of sticky positioned box](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-sticky1.svg)

This intersection is called a _sticky-constraint rectangle_ and is used to contain the location of the sticky box. The specification uses the term “projects above/below/outside” but I’m not sure if my understanding is the same as what the specification authors intended.

![Position of sticky positioned box after scrolling takes place](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-sticky2.svg)

What I do know is that when you define an offset value, the offset will never push the sticky box outside its containing block, but the sticky box is free to move within the containing block as the page is scrolled, hence the perception of it being pinned to the relevant edges.

### `position: absolute`

An absolutely positioned box is explicitly offset with respect to its containing block, and the box does not participate in the normal flow at all. Its later siblings will not know about its existence in the greater layout.

![Position of absolutely positioned box](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-absolute.svg)

Contents of an absolutely positioned box do not flow around any other boxes and may overlap other boxes, and depending on the stack level of the boxes, content may be obscured by the overlap.

### `position: fixed`

A fixed position box behaves similarly to an absolutely positioned box. The key distinction is that the containing block is always the viewport.

![Position of fixed positioned box](https://www.chenhuijing.com/assets/images/posts/css-positioning/position-fixed.svg)

## Box offset values

Traditionally, the box offset values most developers are familiar with are `top`, `bottom`, `left` and `right`. And I don’t think it’s a generalisation to say that most developers from the West don’t give a second thought to writing modes that are anything other than horizontal top-to-bottom.

But when you use a writing mode that is right-to-left, for example, or vertical writing, then these physical values of `top`, `bottom`, `left` and `right` make less sense. For example, the top of your content may not be the physical top of the browser viewport.

As someone who grew up exposed to writing systems in different directions from the Western default, this was not hard for me to wrap my head around, but that may not be the case for many folks from the West.

{% twitter 1192315547335180288 %}

This is why I appreciate it when influential folks in our industry start talking about these lesser known aspects of web development, especially on the internationalisation side of things, because they have a wider reach and can help something considered obscure become more mainstream.

### Logical box offset values

Because the specification is still in Editor's Draft status, the syntax may change moving forward. Even now, the current browser implementation is different from what is in the specification, so be sure to double-check with [MDN: CSS Logical Properties and Values](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties) on the most updated syntax.

The matrix of writing directions and their corresponding values for a box’s physical sides and logical sides are as follows (the table has been lifted from the specification as of time of writing):

![Mapping of physical and logical box offset values](https://dev-to-uploads.s3.amazonaws.com/i/hnfty5rebb1zgqk2t0yh.png)

The logical top of a container uses `inset-block-start`, while the logical bottom of a container uses `inset-block-end`. The logical left of a container uses `inset-inline-start`, while the logical right of a container uses `inset-inline-end`.

This is probably easier to visualise with a diagram (or live code if your browser supports it). The following is for `horizontal-tb`:

 ![Logical box offset values for horizontal-tb with ltr](https://www.chenhuijing.com/assets/images/posts/css-positioning/tb-ltr.png) 

![Logical box offset values for horizontal-tb with rtl](https://www.chenhuijing.com/assets/images/posts/css-positioning/tb-rtl.png)

The following is for `vertical-rl`:

 ![Logical box offset values for vertical-rl with ltr](https://www.chenhuijing.com/assets/images/posts/css-positioning/rl-ltr.png)

![Logical box offset values for vertical-rl with ltr](https://www.chenhuijing.com/assets/images/posts/css-positioning/rl-rtl.png)

The following is for `vertical-lr`:

 ![Logical box offset values for vertical-lr with ltr](https://www.chenhuijing.com/assets/images/posts/css-positioning/lr-ltr.png)

![Logical box offset values for vertical-lr with ltr](https://www.chenhuijing.com/assets/images/posts/css-positioning/lr-rtl.png)

## Wrapping up

I suggest opening this CodePen in a full browser window and playing around with the examples and CSS values to get a feel of how everything fits together (or you could select the 0.5x option in the embed).

{% codepen https://codepen.io/huijing/pen/PowbeXJ %}

There are plenty of useful resources that cover CSS positioning, so if my explanation doesn’t work for you, try someone else’s article or the specification directly. It is definitely worth the effort in the long run to figure out this important aspect of CSS layout for yourself.

- [CSS Positioned Layout Module Level 3 Working Draft](https://www.w3.org/TR/css-position-3/)
- [MDN: Positioning](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Positioning)
- [CSS Position Sticky - How It Really Works!](https://medium.com/@elad/css-position-sticky-how-it-really-works-54cd01dc2d46)
- [5 Things You Might Not Know About the CSS Positioning Types](https://scotch.io/bar-talk/5-things-you-might-not-know-about-the-css-positioning-types)
- [Advanced Positioning](https://internetingishard.com/html-and-css/advanced-positioning/) (slightly older article so no `sticky` in here)
- [CSS Positioning 101](https://alistapart.com/article/css-positioning-101/) (slightly older article so no `sticky` in here)