CSS Positioning: A walkthrough
Are you having a specific requirement for a navbar to stick to the top of the web page, no matter how much we scroll the page, or you would like to place certain elements in a layout apart from its default behavior? <POSITION> is your answer!!
Every beginner that gets started with Web Development will definitely encounter CSS. To be really good with CSS, you do have to understand the CSS position property and its applications.
This article will look at the different CSS positioning properties and what each property offers and its effects.
What is CSS position property?
Taking the definition right from MDN, our good old legendary documentation…
The position CSS property sets how an element is positioned in a document. The top, left, right and bottom properties determine the final location of positioned elements.
When the <HTML> document is structured, the order in which you create elements in the markup, in the same manner, the elements get displayed on the browser. This is what we refer to as document flow.
By default, the position: static value is applied to each element, reflecting the document's normal flow. For instance, block-level elements take up the entire width and inline elements only take up the content width. The z-index and top, left, right and bottom properties do not affect such an element.
Hey, what is this z-index you are talking about? We shall look into it soon!!
Let’s dive into an example to make these concepts concrete:
In the above example, I have a wrapper container with 3 <div> as child items. I have targeted these child items and applied a position: static. You could try removing the property and see the result remains the same. This proves that the static property is applied by default.
Now taking things to the next level, let’s selectively target the first child item and apply a position: fixed. What you would immediately notice is the other elements will start to take over space where our first child item resided initially, i.e it would become as if the first child item never existed to the other elements.
Effectively position: fixed takes the element out of the document flow, converts it to an inline-block element and the document viewport becomes the positioning context.
When we apply a position value other than static, we are actually changing the document flow of the element as well as the positioning context of the element.
Positioning context simply refers to an element of reference, with which the positions of non-static positioned elements can be adjusted through the top, left, right, and bottom properties.
With these definitions out of our way, let’s also add top:0,left:0 to the first child item and see how it behaves.
Viewport refers to the part of the document that is currently visible on the screen. The positioning context for the header becomes the viewport itself. The header is now situated at 0px from the top and 0px from the left of the viewport. This is how the position needs to be interpreted.
What if you don’t want to position an element for the viewport? What if you want to set any element of interest as a positioning context for other elements? This is where the combination of relative and absolute positioning comes into play!
Let’s now try changing the header to have a position: relative. This sets the header itself as the positioning context and still does not take it away from the document flow. You could notice that no change in the browser as the element still takes its required space.
This means that any top or left property that you apply to relatively positioned elements causes it to move concerning its original position itself. For instance, try applying top:100px,left:0 to that element and you could notice an invisible margin pushing the element from the top 100px below from its original position.
Let’s add a position: sticky and top:20px to our header element.
Sticky positioned elements have a behavior of both relative and fixed position elements. It allows a positioned element to behave as relative positioned until it has scrolled a certain threshold distance after it becomes a fixed element.
In our example, you could notice the header remains relative (the document flow retains) until we have scrolled 20px from the top of the viewport. Then it becomes a fixed element sticky to the top of the viewport and retains this behavior until the parent container remains visible in the viewport. Scroll through the above example to observe these effects.
This property can be used to have a navigation bar to scroll with the page until a certain point, then make it stick to the top of the page.
This property is still relatively modern though and is yet not completely supported by all browsers.
The absolute positioning takes an element out of the document flow and its positioning context depends on an ancestor element that is not statically positioned. Let us deconstruct this statement.
If no ancestor elements have their position explicitly defined, then the absolutely positioned element will take the root element <HTML> as its positioning context/containing block otherwise called the initial viewport.
Let our header now have a position: absolute and modify top:100px,left:0 to observe that effect.
Now we could change the positioning context of the absolutely positioned element by making a closest ancestor element relative positioning. For instance, let's make our parent container relatively positioned.
Try playing with the below code to observe these effects.
What if we have multiple positioned elements that tend to overlap, is there a way to control which elements are on top of others? To demonstrate this situation let’s make our article also an absolutely positioned element.
Some important observations:
- By default, all positioned elements will sit over top on the non-positioned elements (which have position: static)
- When the header and article elements overlap, you would notice the article sitting on top of the header.
Among the positioned elements (like the header and article in our case), the element that appears later in the source order (document markup) sits on top of the other elements appearing earlier. Since our article element appears later in the markup, it tends to sit over the header element.
To override this behavior, this is where Z-index comes into play. Quoting its definition from our MDN docs…
The z-index sets the z-order of a positioned elements and its descendants or flex items. Overlapping elements with a larger z-index cover those with a smaller one.
Z-index controls the positioning of items concerning the z-axis, an imaginary line that runs perpendicular to the screen towards you.
Positioned elements by default, have a z-index of auto which is 0. Applying z-index to elements directly affects how they sit with other elements. Positive values move them up the stack, and negative values put them behind the elements.
Our example is that adding a z-index of 20(say) to our header element should effectively make it sit on top of the article since it has a default z-index of 0.
- Every element has a position: static applied by default which causes the elements to be placed according to the normal document flow.
- The viewport is the positioning context for the fixed element.
- The nearest positioned ancestor is the positioning context for an absolute element.
- The element itself is the positioning context for a relative element.
- The viewport and nearest positioned ancestor are the positioned context for a sticky element based on the threshold distance
- Z- index can be used to control the positioning along the z-axis