25

Here is the situation:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  text-align: right;
  background: green;
  animation: animate 2s infinite alternate linear;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

What's happening?

As you may see we have two div without any complex styling (simply background-color). I am making the second div to overlap the first one by applying a negative margin-top. I am expecting to see one completely overlapping the other but this is not the case. The second div is sliding between the content and the background of the first one and it's a strange behavior for me.

The animation has nothing to do here, I simply use it to better show the behavior. We can simply add negative margin without animation and we will have the same thing:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: right;
  background: green;
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

So my question is : why such behavior?


By the way, we all know that there is some tricky things with CSS that we don't suspect when we face them the first time (like margin-collapsing, background propagation from body to html, white space issue,etc...) but they are clearly explained somewhere and I hope to find an official resource where I can clearly understand this and not only get something like "Maybe this happen because...", "I suspect this related to...", "I think it have something to do with...",etc.


My opinion/explanation about this

I suppose content like text are more important than background and other visual styling so maybe when we have overlapping we place all the text at the top and all the other styling at the bottom, we decide about the order inside each group and then we print the result.

Here is a more complex example:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

div {
  font-size: 39px;
  line-height: 28px;
  margin-bottom: -20px;
  font-weight: bold;
}

body :nth-child(1) {
  background: red;
  border:3px solid brown;
}

body :nth-child(2) {
  background: blue;
  border:3px solid yellow;
  color: #000;
}

body :nth-child(3) {
  background: green;
  border:3px solid orange;
}
<div>
  some content
</div>
<div>
  other content
</div>
<div>
  more content
</div>

We can clearly see that the visual stack is as follow (starting from bottom to top):

  • Styling of the first div(background + border)
  • Styling of the second div(background + border)
  • Styling of the third div(background + border)
  • text content of the first div
  • text content of the second div
  • text content of the third div

Important notice: Before answering, please note that I am not looking for a fix to this or how to avoid this. By simply adding position:relative the behavior disappear and we can play with z-index to decide about stacking. Am looking to understand why such thing happen.

Jost
  • 199
  • 1
  • 3
  • 16
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • related: https://stackoverflow.com/questions/25055301/why-does-text-on-the-same-layer-overlap-even-when-it-has-an-opaque-background – Danield Feb 15 '18 at 07:47
  • @Danield ah ! i was pretty there was a dup :) [ i also said it in my question but removed the notice since no one get manifested] ... by the way i see you got the same issue, we show you the Spec and even with it you got a bit confused.... and also there is no clear reason why it sould be like that and not like we expected :/ – Temani Afif Feb 15 '18 at 07:56
  • 1
    Yes, it's very counter-intuitive... btw. even though the basic issue was the same I wouldn't call your question a duplicate though because you are also asking WHY the spec has to be like this as well. The WHY wasn't explained in the answer to my question either. I'm quite interested to see if anyone can explain this, thanks! +1 – Danield Feb 15 '18 at 08:45
  • does this behaviour happen only if you use a negative value for a property? or does it happen with positive values as well? – Yvonne Aburrow Feb 19 '18 at 10:49
  • @YvonneAburrow well, this behavior happen when there is overlap, so i don't think you can have overlapping using positve values of margin ... so the only whay i found here is using negtive margin to make them overlap but theorically this will also happen if there is some positive margin somehwere too ;) – Temani Afif Feb 19 '18 at 10:51
  • they could overlap if you were using absolute positioning and z-index – Yvonne Aburrow Feb 19 '18 at 10:51
  • @YvonneAburrow this is another context :) positionned element with z-index are treated differently [you can read the spec carefully] ... here we are in the case where our elements are in-flow with no z-index defined and thus the purpose of the question ... it's a very particular case here ;) – Temani Afif Feb 19 '18 at 10:53
  • OK good point. Pretty sure I've seen lots of guidelines saying "don't use negative margins" - maybe this is why. – Yvonne Aburrow Feb 19 '18 at 10:55
  • @YvonneAburrow maybe, but negative margin are very useful and used everywhere ;) .. if used correctly and combined with padding they can be usefull :) – Temani Afif Feb 19 '18 at 10:57
  • @Danield i guess i found a good use case where such behavior is usefull and i am somehow convinced now :) you can check my answer – Temani Afif Feb 20 '18 at 23:25
  • @TemaniAfif check out my answer, tell me what you think in comments. – Munim Munna Mar 04 '18 at 04:56
  • @TemaniAfif if you get some time, please review my answer – Munim Munna Mar 04 '18 at 12:30
  • @TemaniAfif iam sorry for what i said earlier dont happen again – Arunbal Mar 23 '18 at 08:06
  • Does this answer your question? [Why does text on the same layer overlap - even when it has an opaque background?](https://stackoverflow.com/questions/25055301/why-does-text-on-the-same-layer-overlap-even-when-it-has-an-opaque-background) – Alexander Belokon Dec 01 '20 at 13:21

8 Answers8

35

WARNING: Reading the following information can affect your mental health.

The painting order for the descendants of an element generating a stacking context (see the z-index property) is:

  1. If the element is a root element:
    1. background color of element over the entire canvas.
    2. background image of element, over the entire canvas, anchored at the origin that would be used if it was painted for the root element.
  2. If the element is
    • a block, list-item, or other block equivalent:
      1. background color of element unless it is the root element.
      2. background image of element unless it is the root element.
      3. column rule of the element.
      4. border of element.
    • Otherwise, if the element is a block-level table:
      1. table backgrounds (color then image) unless it is the root element.
      2. column group backgrounds (color then image).
      3. column backgrounds (color then image).
      4. row group backgrounds (color then image).
      5. row backgrounds (color then image).
      6. cell backgrounds (color then image).
      7. cell column rule for multi-column.
      8. all table borders (in tree order for separated borders).
  3. Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then tree order.
  4. For all its in-flow, non-positioned, block-level descendants in tree order:
    • If the element is a block, list-item, or other block equivalent:
      1. background color of element.
      2. background image of element.
      3. column rule of the element.
      4. border of element.
    • Otherwise, the element is a table:
      1. table backgrounds (color then image).
      2. column group backgrounds (color then image).
      3. column backgrounds (color then image).
      4. row group backgrounds (color then image).
      5. row backgrounds (color then image).
      6. cell backgrounds (color then image).
      7. cell column rule (multi-column).
      8. all table borders (in tree order for separated borders).
  5. All non-positioned floating descendants, in tree order. For each one of these, treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context are considered part of the parent stacking context, not this new one.
  6. If the element is an inline element that generates a stacking context, then:
    1. For each line box that the element is in:
      1. Jump to 7.2.1 for the box(es) of the element in that line box (in tree order).
  7. Otherwise: first for the element, then for all its in-flow, non-positioned, block-level descendants in tree order:

    1. If the element is a block-level replaced element, then: the replaced content, atomically.
    2. Otherwise, for each line box of that element:

      1. For each box that is a child of that element, in that line box, in tree order:

        1. background color of element.
        2. background image of element.
        3. column rule of the element.
        4. border of element.
        5. For inline elements:
          1. For all the elements in-flow, non-positioned, inline-level children that are in this line box, and all runs of text inside the element that is on this line box, in tree order:
            1. If this is a run of text, then:
              1. any underlining affecting the text of the element, in tree order of the elements applying the underlining (such that the deepest element’s underlining, if any, is painted topmost and the root element’s underlining, if any, is drawn bottommost).
              2. any overlining affecting the text of the element, in tree order of the elements applying the overlining (such that the deepest element’s overlining, if any, is painted topmost and the root element’s overlining, if any, is drawn bottommost).
              3. the text
              4. any line-through affecting the text of the element, in tree order of the elements applying the line-through (such that the deepest element’s line-through, if any, is painted topmost and the root element’s line-through, if any, is drawn bottommost).
            2. Otherwise, jump to 7.2.1 for that element
        6. For inline-block and inline-table elements:
          1. For each one of these, treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context are considered part of the parent stacking context, not this new one.
        7. For inline-level replaced elements:
          1. the replaced content, atomically.
        8. Optionally, the outline of the element (see 10 below).

        Note, some of the boxes may have been generated by line splitting or the Unicode bidirectional algorithm.

    3. Optionally, if the element is block-level, the outline of the element (see 10 below).

  8. All positioned, opacity or transform descendants, in tree order that fall into the following categories:

    1. All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order. For those with 'z-index: auto', treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context should be considered part of the parent stacking context, not this new one. For those with 'z-index: 0' treat the stacking context generated atomically.

    2. All opacity descendants with opacity less than 1, in tree order, create a stacking context generated atomically.

    3. All transform descendants with transform other than none, in tree order, create a stacking context generated atomically.
  9. Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index order (smallest first) then tree order.

Now seriously, refer to the w3c paint order documentation

In point 4.1, the background of children is painted

In point 4.4, the border of children is painted.

When point 4 is finished, all background and border of your snippet have been painted

Now, in point 7.2.1.5.1.1.3, the text of the children is painted.

This is the behaviour that you are seeing.

Notice also that is easy to change this behaviour. We can activate point 8.2, (setting opacity) and it will paint like you may have expected:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  text-align: right;
  background: green;
  animation: animate 2s infinite alternate linear;
  opacity: 0.9999;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Another snippet, showing several point in the document:

Notice that all the border and background in step 4 are rendered after step 3, and before setp 5. But the text in step 4 is step 7, so is rendered after text in step 5

div {
  width: 200px;
  height: 100px;
  border: solid 10px;
  font-size: 40px;
}

.step3 {
  border-color: red;
  background-color: lightpink;
  z-index: -1;
  position: relative;
  margin-left: 10px;
}

.step41 {
  border-color: brown;
  background-color: yellow;
  margin-left: 30px;
  margin-top: -40px;
}

.step42 {
  border-color: blue;
  background-color: lightblue;
  margin-left: 50px;
  margin-top: -40px;
  color: red;
}

.step43 {
  border-color: green;
  background-color: lightgreen;
  margin-left: 160px;
  margin-top: -150px;
  color: crimson;
}

.step5 {
  float: left;
  background-color: white;
  margin-top: -30px;
}

div:hover {
  position: relative;
}
<div class="step3">Step 3 negative zindex</div>
<div class="step41">step4 In flow, number 1</div>
<div class="step42">In flow, number 2</div>
<div class="step43">In flow, number 3</div>
<div class="step5">step 5 float</div>

I don't know if this counts as an use case : this more natural the initial behaviour the the one set by the elements positioning relative

div {
  width: 100px;
  height: 1.3em;
  border: solid 12px tomato;
  font-size: 18px;
}

div:hover {
  position: relative;
}
<div>a long stretch of text overflowing to the other div</div>
<div></div>
doğukan
  • 23,073
  • 13
  • 57
  • 69
vals
  • 61,425
  • 11
  • 89
  • 138
  • mental health affected :/ .. to be honest i saw this link but never thought to read it at the end ... you also have to reading many time to get the loop of painting, well not super easy ... thanks for this ;) ... and yes about opacity i notice it and i also notice all the properties that created new stacking context like a transformation, etc – Temani Afif Feb 12 '18 at 08:04
  • ok so the main keyword in all this is [ **For all** its in-flow ... ] in the 4.1 as when first reading i understand that for each child we do all the loop but it's not the case ... by the way, i know this is the specification but an idea why this decision ? i know also that the example i provide is a bad code so theorically it difficult to have such situation and thus we cannot complain about the paiting process – Temani Afif Feb 12 '18 at 13:38
  • Yes, note that it's quite a limited case: in-flow, not positioned, not transformed, not floated, without opacity ... I believe that this is meant to provide a special case where you want a kind of *flat* display, where several boxes form the background, and the texts are over all. But this is just my guess – vals Feb 12 '18 at 20:24
  • I have added a snippet showing (or at least trying to show) the different steps in the paint order, specially 3, 4, 5 and part of 7 – vals Feb 14 '18 at 21:56
  • thanks :) am also playing with few things in order to trigger some of the other steps in order to see if i find some other *strange* behavior :) ... by the way as you said we will end up using very particular cases that we will probably never use ... So now am trying to find if it's possible to have a real use case where we can see this and that confirmes it should be like that. – Temani Afif Feb 14 '18 at 22:02
  • Added an use case. (may be a little silly, by the way) – vals Feb 20 '18 at 18:51
  • yeah :/ i also endup with a similar case https://jsfiddle.net/x2fkqgdz/2/ where we can say that's it's logic to have the text showing instead of simple backround and at the end it make as a two background block ... so it can be a nice trick to simulate a gradient :) – Temani Afif Feb 20 '18 at 18:58
  • i think i found a very good use case after a lot of thinking/searching :) i guess this one give a good point to such behavior, you can check my answer ;) – Temani Afif Feb 20 '18 at 23:26
  • @vals what do you think about my answer on this. – Munim Munna Mar 09 '18 at 12:29
10

The answer to the question is nowhere near everyone is digging. Because we all have fixed our mind at believing that this is something that leverages user experience anyhow, something intuitive. Have anyone thought this can be for any CPU processing benifit?

Browser rendering engine does not paint an element completely, and then goes on painting the next, because we have GPU technology. The rendering engine paints elements in different stacked layers one over another which are handed over to the GPU who then rasterizes all the layers into a composite layer that shows up on screen.

Browser rendered layers

So, how the layers are created?

  • Rendering engine paints all backgrounds and borders on the base layer.
  • Creates a new layer for an element who has positioning specified. The layer is stacked over the base layer for the GPU to rasterize it. When the element moves the rendering engine only tells the GPU to move the layer, GPU does the rest. CPU is saved from painting overhead.
  • Creates a new layer for an element who has opacity specified. When opacity changes GPU does the rasterizing work.
  • Similarly creates a new layer for inputs, buttons, canvases, videos everything that can cause CPU to paint repeatedly, is transfered to the GPU as a new layer. We are saving a lot CPU processing, right? :)
  • Denies creating any new layer for an element with negative margin :( . This is obvious browser cannot issue new layer for every element with margin, there are a lot of them. Even if it has negative margin it may or may not overlap other element. The only way to be sure is to look into the render tree. What's the point? We are trying to save processing, looking into render tree for every element will ruin it.
  • Issues a new layer for text element. GPU can rasterize text far more efficiently onto a background, so why paint it with CPU on the base layer?? This was the original question. I think everyone can answer it now.

Why text is painted on a separate layer above base layer?

  • CPU does not need to paint the text over background, CPU is happy.
  • When text color or shadows change CPU only paints the text layer, GPU rasterizes it on the background.
  • When the background changes CPU only paints the background layer, GPU rasterizes text over it.
  • When text is scrolled over a fixed background, no painting is needed, CPU only tells GPU to move the text layer, GPU does the rest.
  • And a lot more...

Now let's look into the magics we are encountering due to this.

painting and rasterizing

  • Case 1: When position relative is added to 2nd div it gets a new layer, this new layer is stacked over the base layer and even over the text layer of first div.
  • Case 2: Same thing happens when opacity is applied.
  • Case 3: Any transform style will create a new layer.
  • Case 4: This one is interesting. The margin does not create any layer for the second div, it is painted on the base div after the first div is painted, so it is painted over the first div on the same layer. The text on the first div is on it's own layer that is stacked over the base layer so GPU rasterizes the text over the background of second div.

[source: developers.google.com]

doğukan
  • 23,073
  • 13
  • 57
  • 69
Munim Munna
  • 17,178
  • 6
  • 29
  • 58
  • 2
    It is clear that you have done a great work. But, sorry to say this, I don't think that your conclusions are exact. Explaining why I disagree on this would be too long, and also primarily opinion based, so I don't think it is worthwhile doing it .... Any way, I'll give a vote up for the amount of work that your answer shows. – vals Mar 10 '18 at 08:42
  • Just pointing out the objectional conclusions will help in further research :) – Munim Munna Mar 10 '18 at 08:48
  • Does source (in your answer) explains what you've explained? I think not but may be I'm, overlooking it. Appreciate your effort to explain CPU and GPU interactions so clearly. Thanks a lot! – Ritesh Jagga Nov 01 '20 at 10:30
  • Oh my, `will-change: transform` is such a neat way to create a new **stacking context**! Which brings a question though: _Why don't we have a native way to tell browser to create new stacking context already?_ Before, I was using weird combinations of `position` which however makes life more difficult. `will-change` to the rescue! – Qwerty Jun 22 '22 at 13:23
  • This is such an underrated answer! I was trying to remember all the ways a stacking context is created and I could not figure out why `opacity` was one of them. Looking at it from this perspective makes such sense. Now it's just completely intuitive, no memorization needed! – Qwerty Jun 22 '22 at 13:26
  • 1
    Isn't [isolate](https://developer.mozilla.org/en-US/docs/Web/CSS/isolation) the property you are looking for? – fweth Sep 27 '22 at 10:33
6

This is because of hierarchy... I will try to explain it a little bit more...

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: right;
  background: green;
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Like at this your example, our hierarchy looks like:

.box
    .box content
.bottom
    .bottom content

So, right now if you don't pass position: relative for example, then it will use normal hierarchy of HTML without checking divs...

You have background implemented at .box and .bottom, so at this case when you add margin-top into .bottom, then:

  • .bottom and .box has same horizontal hierarchy position, but .bottom has bigger vertical, so will overlap .box background
  • .bottom content and .box content has bigger position than .bottom and .box so will overlap each of them
  • .bottom content will overlap .box content because of bigger vertical hierarchy
  • yes that's what i understand in *my opinion section* :) but where i can read about this ? any link to official Spec – Temani Afif Feb 11 '18 at 12:11
  • I think you will not find a best official Spec because this is results of HTML hierarchy... You can only read something like this: http://webreference.com/html/rendering/2.html – Mateusz Pęczkowski Feb 11 '18 at 12:19
  • and that's why am asking :) because if we simply read about hierachy we will understand how elements are inside each othet etc, and thus we will understand how style are applied ... but in this case we can think that both elements are independant and cannot collpase like this. So we can find an explanation when we see this behavior but we should be able to finid something that explain this behavior will happen – Temani Afif Feb 11 '18 at 12:23
  • like margin-collpasing .. you face them and one day someone tell you it happens and you can work with .. but in the Spec you can find a clear description on when and how it happens and all the different cases – Temani Afif Feb 11 '18 at 12:23
  • yeah... I didn't think about it... Never! :D I will search, but if you will find something please share your answer :) I will do also it ;) Very good question :D – Mateusz Pęczkowski Feb 11 '18 at 13:00
  • i guess we got the answer ;) check the other one ... it's the specification and there is a smal keywords that make the difference :) as if you read it rapidly you won't think it will happen like that – Temani Afif Feb 12 '18 at 20:27
  • Yeaaahh... Totally weird stuff ;) – Mateusz Pęczkowski Feb 12 '18 at 20:45
3

One way to ask the question would be: could it be handled differently and still manage the different features required by CSS, especially the float property?

What the spec says is that for a stacking context (basically the top block of a part of the DOM tree that is positioned), you paint the elements in that order:

  1. background of the top element of the stacking context
  2. elements with z-index negative

Until now it makes sense, then you have

  1. all backgrounds and border of all the block level elements (basically elements that are display: block but not positioned) in the tree under the top element.
  2. then all floated elements of all the tree under the top element.
  3. This steps in an else from step 2 so it doesn't really interfere with this specific case.
  4. Then all in-flow elements (or non floating elements) of all the tree under top element (it's not just the texts that are rendered in 7, it's all inline elements. If your inline elements has a background, it'll mask what's behind).

The "problem" with this is that is that the in-flow elements are not rendered in the order of the tree. The background of an element lower in the tree can be rendered before an in-flow element upper in the tree. What is implied in the question is that we kind of expect something more like:

  1. render all backgrounds and border and in-flow elements of all the block level elements in tree order.

That would generate the elements in a more intuitive way. So why then separate the in-flow elements from the rest. Why is the step 5 before step 7? It's clear that if you do it that way, then you have a problem with your floating elements. They must be placed before the rest of the flow, because that's what they are, elements that are taken out of the flow. So step 5 makes sense, you need to consider floating elements before non floating elements.

So what if they were rendered in step 4, like this:

  1. all backgrounds and border, then floating and then non floating elements of all the block level elements in tree order.

You still have a problem, because of what is expected of floating elements. See this snippet:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: left;
  background: green;
  
}
<div class="box">
  <span>some content some content some content some content some content some content some content some content some content some content</span>
<span style="float: left; background: navy">
  floated content box<br>
  floated content box<br>
  floated content box<br>
  floated content box
  </span>
  
 
  
  
</div>
<div class="bottom">
  <span style="background-color:turquoise;">other content</span>
  <span style="float: left; background-color:bisque;">
  floated content bottom<br>
  floated content bottom<br>
  floated content bottom
  </span>
  
 
  
</div>

You'll see that the float elements don't have any impact on the height of the block elements, which is expected, else the result would be weird, not at all what's expected of a floating element. So if the floating element in the upper block was rendered before the background of the lower element then the background would be over the floating element. So rendering backgrounds, then float, then in-flow in the tree order doesn't work either. You need to place all float elements of all the tree before you get to the normal flow.

So you're pretty much stuck with this way of handling the render, meaning you have to check all your elements in one context to position floating elements, then position the rest of the normal flow. It has this strange side effect, but considering the complexity of the different positioning expected by the CSS specs, I'm not sure there's another way to do it.

EDIT:

I think this behavior is clearly specified in the specs, see here: https://www.w3.org/TR/CSS2/visuren.html#floats

The contents of floats are stacked as if floats generated new stacking contexts, except that any positioned elements and elements that actually create new stacking contexts take part in the float's parent stacking context. A float can overlap other boxes in the normal flow (e.g., when a normal flow box next to a float has negative margins). When this happens, floats are rendered in front of non-positioned in-flow blocks, but behind in-flow inlines.

Which means exactly what I've illustrated, meaning that it's expected for floating element to overlap in-flow blocks, and be rendered in front of such backgrounds.

Julien Grégoire
  • 16,864
  • 4
  • 32
  • 57
  • Good point but I agree at only 50% :) Because the issue with float here is the overflow, so if the spec was like I wanted it will be hidden by bottom element and I will find this at first place logical because we had an issue which is the overflow and we need to fix it by clearing float correctly. I agree at 50% because your answer is almost the same as mine in term on conclusion. Here you conclude implicitly that we may face overflow (either by float or by text going bigger) and it's more important to show content above background then the opposite. – Temani Afif May 01 '18 at 21:49
  • The difference between your answer and mine (https://stackoverflow.com/a/48895817/8620333) is that something like this is visible at dev stage, so if the spec was like I wanted and the float are hidden, we can see this and correct the code by doing the necessary changes, that's why I don't agree at 100% with your point because a developer should be aware about the result and adjust. But in my answer we may face situation where the CSS will change on the client side to create the overflow; thus we should give priority to content. Of course, this is only a pesonal conclusion :) – Temani Afif May 01 '18 at 21:54
  • @TemaniAfif See my edit, I think this behavior is clearly expected in the CSS specs, it is the expected behavior, so the render guideline seems to me to be the only way (or at least the most straightforward way) to implement the specs. But, yes, all of this is speculation, there might be more to it. It's just a different approach to try to understand this behavior. – Julien Grégoire May 01 '18 at 22:34
  • yes I know it's cleary expected in the specs :) and that what I also said: we face thing **we** don't expect and then we read about them in the spec that give you the correct expected way. This was clear to me when I read the spec but my real question is why they decided like this? So yes things are very well explained in the spec and all this behavior is logical and normal but sometimes we might ask "why they decide to make it like that?" "what was their reasons?". – Temani Afif May 01 '18 at 22:43
2

The answer of @vals highlighted where this behavior is explained in the specification BUT provided only 80% of the answer as I am still looking for the why?. Since this behavior is somehow counter-intuitive I tried to find real use cases where this behavior should be like that and not like I expected.

After doing a lot of search, I ended with the logical conclusion that a good web developer should be aware about anything specified within the specification and shouldn't leave a place to random/unexpected behavior especially when it comes to behavior well explained by the specification and not the browser specific ones.

So we write code, we face strange things, we learn about them, we adjust our code ... we do this until we have something working as expected.


Since a web developer has a full control on his development, I was asking my self is there any external tools that may affect his CSS and the rendering of his web page that he cannot control?

Yes, and one of them is related to accessibility.I am not talking about the guidelines a web developer should follow but about some widget in some website that allow you to increase font-size, change contrast, etc in order to help you better read content. This kind of widget can be integrated anywhere using add-ons.

Here a simplified example where a user can increase the font-size and where the above behavior is useful as it will keep the text content above thus we can easily read it:

$('button').click(function() {
   $('body').css('font-size','22px');
})
body {
 font-size:14px;
 max-width:500px;
}
section {
  height: 80px;
  background: red;
  padding:5px;
  border-top: 40px solid blue;
  color:#fff;
}
div {
  height:80px;
  background:url(https://lorempixel.com/g/400/400/) center/cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Make font bigger</button>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<div>
</div>

In this code the developer used a font-size equal to 14px which can be difficult to read for some people so it's logical that we want to increase it. If we do it, we will have the strange behavior BUT if it wasn't like that the content will be hidden and thus we can no more read it!

This situation gives a good reason for such decision and as I said in the question: the content is more important than the styling behind in this case especially when it comes to external tools that change the initial behavior.

The intention of increasing the font-size here is to highlight the content and not the background or border which confirm that the painting order should be like that in order to meet this requirement.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • 1
    Interesting point ... yes, it could be this the reason. But, of course, it's difficult to know for sure; unless you happen to talk with the people in the w3c group at the time. – vals Feb 22 '18 at 18:29
  • @vals yes right but i atleast i found a *real* case where i would be surprised if the content was hidden ;) – Temani Afif Feb 22 '18 at 19:00
  • @vals, so the developer has to be dumb enough to set fixed 80px height for the sections and intelligent enough to leave 40px margin between sections so that the overflown text can show without moving over to next section, I wonder how many of them will end up doing that. Would painting the text later be useful if there was no margin? I don't think the spec was even thinking of these rare cases to facilitate. Besides *A developer shouldn't leave a place to random/unexpected behavior especially when it comes to common/generic behavior and not browser specific ones*. – Munim Munna May 02 '18 at 08:19
  • @MunimMunna Well, I think that the point of Temani is more about the usual margin that you always leave to make the page look uncluttered, not a margin that you leave thinking about this case. But, as I said before, knowing what was the real idea of the w3c when they wrote the standard is mainly opinion based, and difficult to prove. – vals May 02 '18 at 19:40
  • @vals yeah, it is opinion based, but i was saying, if there is no margin then painting the text later cannot do any good. And it is unlikely w3c wrote the spec to facilitate such extremely rare scenario where painting text later works out nicely. But who knows! – Munim Munna May 02 '18 at 19:47
0

The key to understand why ? is behind understanding the browser painting layers

yesterday I asked the same question and seeking why ?

the first assumption on my question is :

there is an overlapping

but I figure out there is no overlapping at all even when visually we feel that!!

this is better to called intersecting

the moment that I start to shift my mind to believe that was intersection when I read this table on MDN about z-index :

**Layer**           **Description**
Bottom layer    Farthest from the observer
Layer -X        Layers with negative z-index values
Layer 0         Default rendering layer
Layer X         Layers with positive z-index values
Top layer       Closest to the observer

The fact that there is no new stacking context

assure that the elements have been painted on the same layer which is (Layer 0) which mean intersecting not overlapping and this is the point.

the browser wants to finish all backgrounds first? because he know

  • it's on the same layer
  • it's the first thing to draw then drawing text
Ayman Morsy
  • 1,279
  • 1
  • 10
  • 28
-1

It is important to note that for this case, each div has its height due to its content. let's say for a moment that the resulting height is 20px.

then, if you say that the first div will have margin-top: 20px, the second div, which was declared after the first, starts from where the first div ends.

so, the initial position of the second would be the margin-top of the first plus the height of the first. let's say that gives 40px.

so, the starting position of the second would be 40px for this case. when you say that the margin-top of the second div is -15px, the initial position would be 40px-15px. so, if you want the second to overlap the first one, you should place the margin-top equal to the negative of the height of the first.

  • did you understand what the question is about? – Temani Afif Feb 21 '18 at 18:19
  • wow.. actually yes, but you clearly say that you were not looking for an answer like position: relative, and thats the behavior your seeing there. to clarify: all elements have css properties with default values. you know that, right? the property position, have the default value of static. Thats what you are seeing there. You can read a bit about that. SO if you want the elements to take the relative position with respect to the other, then use position relative. please read a bit about it here: [link](https://www.w3schools.com/cssref/pr_class_position.asp) – Lisandro Gelder Feb 23 '18 at 12:16
  • well so you didn't undestand the question :) ... i know everything about position and all the different values and i know how to use relative and all the stuffs, well i know pretty well CSS ;) .... but read the question clearly, am looking to understand where the behavior i saw is specified [ and the answer of vals answered this] then am looking WHY such decision of this behavior ... please read carefully the question, comments and all answer before answering – Temani Afif Feb 23 '18 at 12:22
-1

What happens is that you have 2 overlapping 'boxes' that need to be rendered on the same z layer, layer 0. However, in Introduction to the CSS basic box model, explaining the border area, it says that:

When there is a background (background-color or background-image) set on a box, it extends to the outer edge of the border (i.e. extends underneath the border in z-ordering).

I assume that border and content are both in 'foreground'.

So, the specification of drawing all the boxes on the same layer, combined with the specification of drawing the background underneath the foreground, I guess it results in drawing all the backgrounds underneath all the foregrounds.

Inside each 'sub-layer' the overlapping is according to the HTML order.

To understand why the DIVs in the post are on the same layer, one should read The stacking context.

To 'understand' why the backgroung goes underneath the foreground, one should read Introduction to the CSS basic box model.

edixon
  • 991
  • 6
  • 16
  • I had an attempt on each but they didn't seemed in the right direction. I needed to understand what happens so most reading was on MDN. Once I understood that the 3 DIVs need to be on the same layer, I understood what happens in the post. – edixon May 01 '18 at 12:33
  • To understand why the 3 DIVs are on the same layer, one should read [The stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context) – edixon May 01 '18 at 12:35
  • first there is only 2 Div and the first answer already provided all the details, so am not sure you read it and read the other too. And the main question is "Why?" this behavior, we already have the explanation of it – Temani Afif May 01 '18 at 12:37