Thursday, March 23, 2023
HomeReactWhat The Heck, z-index??

What The Heck, z-index??


In CSS, we’re given a device to explicitly management the stacking order of HTML components: z-index. Parts with the next worth will seem on prime:

Code Playground

As a result of .first.field has a bigger z-index than .second.field, it stacks in entrance. If we take away that z-index declaration, it falls to the again. The code above is editable—give it a shot!

Issues aren’t all the time so easy, nonetheless. Generally, the bigger z-index worth does not win.

Take a look at what is going on on right here:

Code Playground

.tooltip has a a lot bigger z-index than header! So why on earth is the header on prime?

To unravel this thriller, we’ll must find out about stacking contexts, an obscure-yet-fundamental CSS mechanism. On this article, we’ll discover what they’re, how they work, and the way we will use them to our benefit.

In the event you’ve ever used image-editing software program like Photoshop or Figma, you are most likely accustomed to the idea of layers:

3 layers in a Photoshop document: a cat photo (bottom), a moustache (mid), and a halo (top)

Our picture has 3 separate canvases, stacked like pancakes. The underside layer is a cat picture, with 2 layers on prime that add foolish particulars. By flattening these layers, we wind up with a last composition:

A cat photo with a poorly-drawn moustache and halo

In these packages, we will additionally group layers:

The 3 layers from the previous drawing are in a group, “Cat”. Another group, “Dog”, includes a top hat and a dog photo

Like information in a folder, a gaggle permits us to phase our layers. When it comes to stacking order, layers aren’t allowed to “intermingle” between teams: All of canine‘s layers will seem on prime of all of cat‘s layers.

After we export the composition, we do not see the cat in any respect, because it’s behind the canine:

A dog photo with a poorly-drawn top hat

In the case of CSS, issues work in an identical approach: components are grouped into stacking contexts. After we give a component a z-index, that worth is simply in contrast in opposition to different components in the identical context. z-index values should not world.

By default, a plain HTML doc may have a single stacking context that encompasses all nodes. However we will create extra contexts!

There are various methods to create stacking contexts, however this is the most typical:

By combining these two declarations, a secret mechanism is triggered: a stacking context is created, forming a gaggle round this ingredient and all of its kids.

Let’s take one other have a look at our downside from above:

We are able to map out the stacking contexts being created on this snippet:

Our .tooltip ingredient has a z-index of 999999, however that worth is simply related inside the <primary> stacking context. It controls whether or not the tooltip reveals up above or under the adjoining <p> tag, nothing extra.

In the meantime, within the dad or mum context, <header> and <primary> are in contrast. As a result of <primary> has a smaller z-index, it reveals up beneath <header>. All of its kids come alongside for the trip.

How will we resolve our tooltip downside? Nicely, on this case, we do not really must create a stacking context on our <primary>:

Code Playground

With no z-index, <primary> will not create a stacking context. Our hierarchy, then, appears like this:

  • The foundation context

    • <header>

    • <div class="tooltip">

As a result of the header and our tooltip are actually in the identical context, their z-index values face off, and the tooltip emerges because the victor.

An essential distinction: we’re not speaking about dad or mum/little one relationships right here. It does not matter that the tooltip is extra deeply nested than the header. The browser solely cares about stacking contexts.

We have seen how we will create a stacking context by combining relative or absolute positioning with z-index, however it’s not the one approach! Listed below are some others:

  • Setting opacity to a price lower than 1

  • Setting place to fastened or sticky (No z-index wanted for these values!)

  • Making use of a mix-blend-mode aside from regular

  • Including a z-index to a baby inside a show: flex or show: grid container

  • Utilizing remodel, filter, clip-path, or perspective

  • Utilizing will-change with a price like opacity or remodel

  • Explicitly making a context with isolation: isolate (Extra on this quickly!)

There are a number of different methods as nicely. Yow will discover the total checklist on MDN.

This could result in some shocking conditions. Take a look at what’s occurring right here:

Code Playground

primary does not set a z-index anymore, however it makes use of will-change, a property that may create a stacking context all by itself.

To ensure that z-index to work, we have to set place to one thing like relative or absolute, proper?

Not fairly. Take a look at what’s occurring right here:

Code Playground

The second field is lifted above its siblings utilizing z-index. There are not any place declarations wherever within the snippet, although!

Normally, z-index solely works with “positioned” components (components that set place to one thing aside from the default “static”). However the Flexbox specification provides an exception: flex kids can use z-index even when they’re statically-positioned.

An earlier model of this publish mentioned that each one components that create a stacking context can use z-index, however that was incorrect. 😬

There is a Bizarre Factor right here, and I believe it is value pondering about for a minute or two.

In our Photoshop analogy, there’s a clear distinction between teams and layers. All the visible components are layers, and teams might be conjured as structural helpers to comprise them. They’re distinct concepts.

On the net, nonetheless, the excellence is a bit much less clear. Each ingredient that makes use of z-index should additionally create a stacking context.

After we resolve to offer a component a z-index, our purpose is usually to carry or decrease that ingredient above/under another ingredient within the dad or mum stacking context. We aren’t intending to provide a stacking context on that ingredient! However it’s essential that we take into account it.

When a stacking context is created, it “flattens” all of its descendants. These kids can nonetheless be rearranged internally, however we have basically locked these kids in.

Let’s take one other have a look at the markup from earlier:

By default, HTML components shall be stacked in response to their DOM order. With none CSS interference, primary will render on prime of header.

We are able to carry header to the entrance by giving it a z-index, however not with out flattening all of its kids. This mechanism is what led to the bug we mentioned earlier.

We should not consider z-index purely as a approach to change a component’s order. We must always additionally consider it as a approach to kind a gaggle round that ingredient’s kids. z-index will not work until a gaggle is shaped.

Hyperlink to this heading

Hermetic abstractions with “isolation”

Considered one of my favorite CSS properties can be one of the obscure. I might wish to introduce you to the isolation property, a hidden gem within the language.

Here is the way you’d use it:

After we apply this declaration to a component, it does exactly 1 factor: it creates a brand new stacking context.

With so many various methods to create a stacking context, why do we’d like one other one? Nicely, with each different methodology, stacking contexts are created implicitly, as the results of another change. isolation creates a stacking context within the purest approach attainable:

  • No must prescribe a z-index worth

  • Can be utilized on statically-positioned components

  • Does not have an effect on the kid’s rendering in any approach

That is extremely helpful, because it lets us “seal off” a component’s kids.

Let’s take a look at an instance. Lately, I constructed this neat envelope part. Hover or focus to see it open:

It consists of a number of layers:

I packaged this impact up in a React part, <Envelope>. It appears one thing like this (inline kinds used for brevity):

(In the event you’re questioning why Flap has a dynamic z-index, it is as a result of it must shift behind the letter when the envelope is open.)

React part is sealed off from its setting, like a spacesuit. This spacesuit, nonetheless, has sprung a leak. Take a look at what occurs once I use it close to a <header> with z-index: 3:

Our <Envelope> part wraps the 4 layers in a div, however it does not create a stacking context. Because of this, these layers can change into “intertwined” with different elements, just like the world’s most boring recreation of Tornado.

By utilizing isolation: isolate on the top-level ingredient inside <Envelope>, we assure that it will be positioned as a gaggle:

Why not create a stacking context the old school approach, with place: relative; z-index: 1? Nicely, React elements are supposed to be reusable; is 1 actually the fitting z-index worth for this part in all circumstances? The fantastic thing about isolation is that it retains our elements unopinionated and versatile.

Increasingly more, I am beginning to imagine that z-index is an escape hatch, much like !essential. That is one trick that enables us to manage stacking order with out pulling the large pink z-index lever.

I am engaged on a follow-up tutorial the place we have a look at another methods to maintain z-index inflation down. Watch this house!

Sadly, I have not discovered a lot tooling to assist debug stacking-context points.

Microsoft Edge has an fascinating “3D view” that enables us to view stacking contexts:

That is an formidable concept, however truthfully I discover it fairly overwhelming. It is laborious to find a particular ingredient on this view, and I do not actually really feel prefer it helps me perceive the stacking contexts in my app.

There’s one different neat trick you should utilize typically: offsetParent.

offsetParent returns the closest ancestor rendered with a place worth aside from static. It crawls up the tree on the lookout for relative / absolute / fastened / sticky ancestors.

This isn’t an ideal answer. Not all stacking contexts use positioned structure, and never all positioned components create a stacking context! That mentioned, in apply, there does are usually a reasonably sturdy correlation between these two issues. On the very least, it is a place to begin.

If you realize of any tooling that may assist right here (or for those who create one!), let me know on Twitter

Replace: Felix Becker reached out to share a VSCode extension that highlights when stacking contexts are created:

A CSS code snippet showing that z-index has no effect, and how to fix it

This extension works on .css and .scss information (no CSS-in-JS assist).

Replace 2: Giuseppe Gurgone reached out to let me find out about this Chrome extension which provides a brand new “z-index” pane to the devtools.

Replace 3: Andrea Dragotta created an unbelievable browser extension that provides a bunch of super-important details about z-index and stacking contexts:

Screenshot of the Chrome devtools with a new pane that shows info about the element's current stacking context

That is an superior device, and I have been utilizing it usually. Set up CSS Stacking Context Inspector:

Stacking contexts are a great instance of how CSS is constructed on “hidden mechanisms”. You possibly can spend years constructing interfaces with CSS with out realizing that they exist.

Except you explicitly take the time to find out about these mechanisms, your psychological mannequin will all the time be lacking items. And in case your psychological mannequin is even barely misaligned, it is solely a matter of time till that discrepancy causes issues.

CSS does not have warnings or error messages. When one thing shocking occurs, there isn’t any clear “subsequent step” to determine what went improper. These disruptions take us out of stream state and shake our confidence. I believe because of this so many front-end builders do not get pleasure from writing CSS.

When you construct up an instinct for the language, although, CSS turns into an absolute pleasure. I love writing CSS these days.

I need to assist different builders uncover this pleasure. I’ve created a complete self-paced on-line course that explains how CSS works at a deeper degree, and teaches the sensible abilities I take advantage of every single day to construct every kind of person interfaces.

It is referred to as “CSS for JavaScript Builders”, and it is accessible now. 😄



Please enter your comment!
Please enter your name here

Most Popular

Recent Comments