javascriptcssdomheightbox-sizing

Setting `element.style.height` not working as expected if `element.style.box-sizing` is `border-box`


I am having an understanding problem with the following code:

let myDiv1 = document.getElementById("myDiv1");
alert("Click me to make 'Hello' vanish");
myDiv1.style.height = "0px";

let myDiv2 = document.getElementById("myDiv2");
alert("Click me to make 'World' vanish");
myDiv2.style.height = "0";
.myClass1 {
  box-sizing: border-box;
  overflow: hidden;
  padding-top: 2em;
  padding-bottom: 2em;
  background-color: yellow;
}

.myClass2 {
  box-sizing: content-box;
  overflow: hidden;
  padding-top: 2em;
  padding-bottom: 2em;
  background-color: orange;
}
<body>
  <div id="myDiv1" class="myClass1">
  Hello
  </div>
  <div id="myDiv2" class="myClass2">
  World
  </div>
</body>

I understand the behavior of the second (orange) div: It has box-sizing: content-box;, so its height does not include the padding or the borders. Hence, when its height is set to 0, it shrinks basically by the height of the text "World", but the padding is left as-is. Since the padding exceeds the original text height, the text is still visible in the padding. Only that part of padding which is now outside the div (due to the reduced height) becomes invisible (due to overflow: hidden;).

I do not understand the behavior of the first (yellow) div, though. It has box-sizing: border-box;, so its height does include the padding and the borders. Hence, when its height is set to 0, it should shrink to "real" zero height, meaning that the text, the padding and the borders then should be outside the div and thus should be invisible (due to overflow: hidden;).

Can anybody explain why this is not the case and why the first div behaves just like the second div?

P.S. Tested in Firefox and Chrome, both up-to-date (production channel) at the time of writing this.


Solution

  • border-box tells the browser to account for any border and padding in the values you specify for an element's width and height. If you set an element's width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width. This typically makes it much easier to size elements. ref

    Here is an example to better ilustrate your issue:

    .box {
      display: inline-block;
      padding-top: 2em;
      padding-bottom: 2em;
      border: 2px solid blue;
      background: linear-gradient(red, red) content-box, orange;
      height: 100px;
      animation:move 5s linear infinite alternate;
    }
    
    @keyframes move{
       to {
         height:0;
       }
    }
    <div class="box">
      World
    </div>
    <div class="box" style=" box-sizing: border-box;">
      World
    </div>

    The first example is the trivial one where we decrease the height (red area) until 0 and the animation never stop.

    In the second case the height include the padding and border so before reaching 0 the content area is already 0 that's why the animation seems to stop because we cannot decrease more than 0 and the border/padding already consumed all the space.

    It's logical that when height is equal to 0 both are the same since in the first one we tell the browser that the content area should be 0 (we don't care about padding/border) and in the second case we told the browser to account for the padding/border into the height we specified so we have less room for the content area and since we cannot have less than 0 then its 0.

    In other words, you aren't setting the total height that will be split between the content area, padding and border but you are setting a height and the browser is shrinking it as much as possible to include the border and padding.

    Related for more examples and details: box-sizing: border-box with no declared height/width