One quick question

Implement a button as shown below:

Box-shadow can be thought of first, but unfortunately, the design draft is superimposed with two rounded rectangles, the bottom is a solid color background, the top is a translucent color radial gradient, the resulting effect is not able to hold the straw color. So or honest in accordance with the design draft to achieve. Let’s give the button an after pseudo-element.

Codepen. IO/pujiaxun/PE…

To abstract the above question:

.grandfather A
  .father B
    .son C
Copy the code
.grandfather {
  width: 300px;
  height: 200px;
  background-color: # 999;
}

.father {
  width: 200px;
  height: 150px;
  background-color: #acc;
  position: relative;
}

.son {
  width: 100px;
  height: 100px;
  background-color: #c88;
  position: absolute;
  bottom: -40px;
}
Copy the code

The goal is to put child element C (the button’s solid color background) between parent element B’s background and grandfather element A’s background.

I want to add z-index: -1 to C, so that C is behind its parent element B. It didn’t. I could even say I got it all wrong…

Stacking Order

How to solve it? Start with the concept of stacking context. Similar to BFC, a more abstract concept. In a particular cascading context, the browser is set to sort all the elements in the context according to the cascading order rule.

First, before we look at these nouns, we can guess with a lot of CSS experience that a child element, by default, is displayed in the background of the parent element. Nonsense, otherwise they call it background? In the figure below, the green child is above the gray parent, or closer to the user on the Z-axis.

With a little more experience, the inline/inline-block element is a bit taller than the block element. As shown below, the green element is inline-block and the purple (? Rose?) The element is a block offset upward with a negative margin. But as a latecomer to the document flow, he should have been a latecomer, but he was blocked below.

This is where I pull out a cascading ladder

In short, if everyone is a normal block element, it makes common sense to follow the document flow. But if I’m a block higher than you, like I’m inline-block, then you’re not qualified to compete with me, not even depending on who your dad is. Such as below

Intuitively, the purple element is below the green element, so the purple element B should be blocked. Instead, B, as a text node, is inline by default and ranks higher in the ladder than the green block, even though it’s an uncle element (forgive me for the casual naming…).

So how do we use z-index

This brings us back to the cascading context.

A cascading context can be understood as a special segment that can be combined with a Z-index value to form a specific segment. I wrote a little bit more detailed graph (CodePen address)

For example, a cascading context with a Z-index of -1 would have segments at the blue level.

Cascading context

So what exactly is a cascading context?

Like BFC, an element becomes a cascading context when in some special cases. For a simple example, if the element X is absolutely positioned, and z-index: 1000, it forms a cascading context with quite high segments (cascading order).

Once a cascading context is in place, the whole thing changes a bit. All child elements under element X will no longer participate in levels PK outside of element X and will only be compared in the most recent context. (Remember B who bullied his uncle?)

Other than absolute positioning with the Z-index attribute, how else can you form a cascading context? Reference MDN:

  1. The root element (HTML)
  2. The z-index value is not the absolute/relative positioning of “auto”
  3. A z – the index values are not for the “auto” flex project (flex item), i.e., the parent element display: flex | inline – flex
  4. Any element whose property value is less than 1 (see the Specification for opacity)
  5. Elements whose transform property value is not “None”
  6. Elements whose mix-blending-mode attribute value is not “normal”
  7. Filter Elements whose value is not “None”
  8. Elements whose perspective value is not “None”
  9. The isolation property is set to elements of “ISOLATE”
  10. position: fixed
  11. Arbitrary CSS properties are specified in will-change, even if you don’t specify their values directly
  12. -webkit-overflow-scrolling for the elements set to “touch”

It looks a bit like the conditions for the formation of the Compositing Layer.

For one,

There’s a slight problem, the cascading sequence sounds so nice, there’s something missing. An absolutely positioned element also appears to be higher than a normal sibling element (in normal document flow), even if z-index is not set. It’s not a cascading context, right? What segment is it in?

The location element belongs to the z-index: 0/auto segment. But just to explain a little bit, first of all, the definition of W3 is

the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.

Z-index: auto is automatically generated when you use a non-static positioning property such as absolute positioning. There are other cascading contexts such as transform. If z-index is not specified, the default is auto, which is the same position as the positioned element.

What if I just said z-index: auto for a normal element?

Yes, you love learning. The answer is useless, because it is neither stacking contexts nor “amenities”.

A cascading context whose Z-index is auto can be treated as 0. However, when the z-index of the positioning element is auto, it cannot be the same as 0 because it is not a cascading context. Remember, positioning elements with a numeric z-index form a cascading context. It’s just a special case of the definition.

Back to the demand

.grandfather A
  .father B
    .son C
Copy the code
.grandfather {
  position: relative;
  z-index: 0;
}

.father { 
  position: relative;
}

.son { 
  position: absolute;
  bottom: -40px;
  z-index: -1;
}
Copy the code

Grandfather = 0; father = 0; father = 0; father = 0; 0/auto, and a negative z-index for the son element to form a z-index: -1 cascading context, which should be placed after father and before grandfather.

In the beginning, I thought I would just set son to z-index: -1. The result is the following:

Son is blocked by grandfather because the father elements, father and grandfather, are not in a hierarchical context, they are both in a higher hierarchical context (such as the HTML root element). As a result, son is level -1 hierarchical context, not as tall as the grandfather section of ordinary block, so it is blocked.

conclusion

Three types of cascading contexts

  1. HTML root elements naturally have a cascading context, called “root cascading context.”
  2. The “traditional cascading context” of the positioning element whose z-index value is a numeric value.
  3. For other CSS3 attributes, see MDN.

Hierarchical sorting

  1. An element A looks up to the nearest cascading context B, and A only needs to compare it to the descendants of B
  2. A cascading context itself, when compared to other elements in order, is treated as a whole, with no internal consideration
  3. The hierarchy takes precedence, and the hierarchy follows the document flow principle.

Z-index is not necessarily necessary

There are a lot of times when you don’t need to use z-index, as we know from experience that absolutely positioned elements tend to be higher, and now inline elements are pretty good. Not to mention the z-index:1000000000 operation, of course, avoiding z-index abuse is another topic.

Is it that simple

When it comes to implementing the browser, it’s not fun. Each browser will have a variety of tricky differences, fortunately, most of the use is relatively normal, may be combined with position: fixed, a variety of transform, filter, hover pseudo-class, I can only say good luck have fun ~

Reference documentation

In-depth understanding of cascading context and cascading order in CSS

Cascading context _MDN