Position: Relatively Confused
Tags: css, design, webdev, beginners
Published: 2021-01-16 20:16:18

The layout of a web page, and how responsive and scalable it is, separates an amateur site from a pro site. One of the first questions on my All Points Bulletin board was related to controlling layout with position:

> What does the `position` property *do*? What do the values `absolute` and `relative` mean? 

When first learning the ins and outs of CSS I was easily confused by the number of options to control the layout of a page. There's CSS Grid, Flexbox, floats and pure positioning. I often lost track of what properties belonged to which, trying to use the `top` property in a flexbox column, or using trial and error to plug in `justify-content`, `align-items`, and `margin` values to center content.

I've learned that a finished website usually has a little bit of everything, and being familiar with the basics is a powerful tool when trying to figure out why an element, or a group of elements, isn’t behaving how you expected.

---

## The Position Property 

The `position` prop specifies the *positioning method* applied to an element. 

There are 5 possible methods: 
- Static
- Relative
- Absolute
- Fixed
- Sticky

Once an element's `position` property is set to anything *but* `static` (the default setting) it will have access to the `top`, `left`, `right` and `bottom` properties - what I'll refer to as the positional properties. 

---

### 1️⃣ **Position: Static**

By default the elements on a web page are displayed in static position. They appear in the viewport according to the document flow and writing method of the browser. Some browsers display left-to-right, right-to-left, or vertically down the page depending on the selected country and language. 

🙋‍♂️ In this example we have a client who has asked us to create a simple dating profile page. The finished page uses basic structure - the elements are laid out in a logical order, from top to bottom as we want them to appear. They follow a flow. 

{% codepen https://codepen.io/AElizaBergs/pen/eYdjrNE %}

A page without CSS to explicitly change the ordering or positioning of elements (a page in default `static`) is said to be in **Normal Flow**.

When a page is in Normal Flow, elements are displayed one after another, in block dimension, as they appear in the code. When the page is scrolled the elements scroll with it. 

The positional properties (`top`, `bottom`, `right`, and `left`) **do not** effect an element that is positioned statically.

---

### 2️⃣ **Position: Relative**

When an element is moved by changing its positioning method (using the `position` prop rather than `display`), it's always being moved in reference to something - like another element, or itself. 

Applying `position: relative` sets that reference to *where the element would be in Normal Flow*. At first it won't look like it did much of anything, that's because the element won't move until a positional property tells it to.

🙋‍♂️ Using the same example from above, the client wants us to center his profile image on the page. We could do this by using relative positioning, and a little bit of hackiness. 

{% codepen https://codepen.io/AElizaBergs/pen/abmPmyp %}

The image element, with class name `profile_pic`, was given a relative position and moved 35% to the left of that reference. This isn't the best approach to centering an element, but it works for now.

☝ Keep in mind! The space the element takes in Normal Flow is reserved - surrounding elements will not shift to fit or fill the gap, or make room for the element elsewhere. 

---

### 3️⃣ **Position: Absolute** 

Applying `position: absolute` on an element removes it, and the space it would normally take, from the document flow entirely. The point of reference is set to the elements *nearest positioned ancestor*, and a *new stacking context* is created. This context gives us access to the **`z-index`** property. 

If the element has no positioned ancestor (a parent element whose `position` is anything *but* static/default), the reference points to the document body (the viewport). This is the first behavior that can confuse a developer and cause bugs in a layout. 

🙋‍♂️ The client got back to us - he likes where the page is going, but wants to restructure the top of the page. He's requested that the `profile` element be smaller, and centered at the top of the page. 

{% codepen https://codepen.io/AElizaBergs/pen/BaLvQYj %}

The `image` div was set to `position: relative`, allowing us to center its direct child, the image element, using an absolute positioning trick. 

The basic syntax for this trick looks like this: 

```CSS
.parent {
    position: relative;
}

.child {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
```
☝ It's important to note that a stacking context is created when using a range of other CSS positioning and layout methods - usually with a default value of 0. This can result in elements falling behind others unexpectedly. We set the z-index of the `image` div to -1, putting it further from the user, or behind other elements (like the navigation bar) in the stacking order. 

☝ If an absolutely positioned element isn't appearing where expected, first make sure the element has a positioned ancestor. Most of the the time we don’t want to use the viewport as the reference, and when we do it’s easier and better practice to use `position: fixed` as we’ll see in a moment. Then make sure the positioned ancestor is the element you expect - going up or down a layer if needed. 

----

### 4️⃣ **Position: Fixed**

Fixed positioning allows an element to be positioned according to the viewport. Like `absolute`, the element will be completely removed from the document flow. A positional property, usually `top`, needs to be used to view the element. 

🙋‍♂️ The client's back! They brought us some more content, and they also want a navigation bar that remains visible at all times. We'll use fixed positioning to achieve this.

{% codepen https://codepen.io/AElizaBergs/pen/yLaGzag %}

First, we gave the `nav` element additional styling rules, and applied `position: fixed`, setting the `top` and `left` properties. These instruct the browser to display the element as if it were pinned to the top left corner.  

☝ Are other elements appearing over a fixed element? Remember, when an element's `position` property is set to either `absolute` or `relative`, a new stacking context is created. Try setting the the `z-index` of the fixed element to 1 or higher. 

☝ It is possible to set the reference of a fixed element to something *other* than the viewport, though it’s not considered best practice. To achieve this, a containing parent must have the `perspective`, `transform`, or `filter` property set to anything but the default of `none`.

----

### 5️⃣ **Position: Sticky**

The last positioning method remaining is a bit of a hybrid - acting as both a relatively and a fixed positioned element at different times. An element with `position: sticky` applied toggles, appearing in Normal Flow until a user scrolls to a certain point, when it then becomes fixed. 

🙋‍♂️ The client is thrilled with our work so far, as a final touch he wants to add a contact number to the page. He's asked that it's noticeable and easily located by the user. We'll use sticky positioning to make sure the user can always get ahold of Jack. 

{% codepen https://codepen.io/AElizaBergs/pen/wvzRrea %}

The `phone_number` element was added at the top of the document, styled with some Windows 95-flavored subtlety, and given sticky positioning. When the user first comes to the page it will be nestled right below the nav bar, but as they scroll to read more it will sticky itself safely within view. 

☝ The sticky value is newer, and because of that it has less cross-browser support. Don’t worry too much about that though, the element will revert to fixed position and scroll with the user in the case that the sticky method isn’t supported. Additionally the [WebKit Sticky extension](https://developers.google.com/web/updates/2012/08/Stick-your-landings-position-sticky-lands-in-WebKit) may help. 

----

### A Word on Normal Flow

Good document structure is an integral part of accessibility-minded design. A well structured document is crucial for users that will never see our carefully laid out CSS, but it's just as important to those who do. 

Normal flow is based on how a reader naturally traverses and consumes content. If an element needs to be moved relatively far from where it appears in normal flow, we should first consider adjusting its position in the document itself instead. 

----

The CSS `position` prop is a powerful tool to control the layout of elements on a page, but it's not without its hidden nuances than can result in hard to solve bugs and weird behavior. I encourage you to play with the code in the examples, remove `position` from parent elements, or try new ones to see how they stack. 

🔍 If you're still curious - check out the resources section below! I always come across great articles in the search to answer my own questions. 

----
***Resources:***

- [Getting Started with CSS Layout](https://www.smashingmagazine.com/2018/05/guide-css-layout/), Smashing Magazine
- [CSS Layout: The Position Property](https://www.w3schools.com/css/css_positioning.asp), w3schools
- [Position](https://developer.mozilla.org/en-US/docs/Web/CSS/position), MDN
- [CSS: Position Property](https://www.techonthenet.com/css/properties/position.php), Tech on the Net
- [The Stacking Context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context), MDN
- [What No One Told You About Z-Index](https://philipwalton.com/articles/what-no-one-told-you-about-z-index/), Philip Walton
- [Detailed Positioning](https://learn.shayhowe.com/advanced-html-css/detailed-css-positioning/), Shay Howe

As always - Thank you for reading 🦄