Установка `element.style.height` не работает должным образом, если `element.style.box-sizing` равно `border-box`

У меня возникла проблема с пониманием следующего кода:

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>

Я понимаю поведение второго (оранжевого) div: у него box-sizing: content-box;, поэтому его высота не включает отступы или границы. Следовательно, когда его высота установлена ​​​​на 0, он сжимается в основном на высоту текста «Мир», но отступы оставляются как есть. Поскольку отступ превышает высоту исходного текста, текст по-прежнему виден в отступе. Только та часть заполнения, которая теперь находится за пределами div (из-за уменьшенной высоты), становится невидимой (из-за overflow: hidden;).

Однако я не понимаю поведение первого (желтого) div. Он имеет box-sizing: border-box;, поэтому его высота действительно включает отступы и границы. Следовательно, когда его высота установлена ​​​​на 0, он должен уменьшиться до «реальной» нулевой высоты, а это означает, что текст, отступы и границы должны быть за пределами div и, следовательно, должны быть невидимыми (из-за overflow: hidden;).

Кто-нибудь может объяснить, почему это не так и почему первый div ведет себя так же, как второй div?

P.S. Протестировано в Firefox и Chrome, оба актуальны (рабочий канал) на момент написания этой статьи.


person Binarus    schedule 13.11.2019    source источник
comment
Вы устанавливаете свойство высоты, поэтому оно никогда не будет устанавливать отступы и границы равными 0. Размер коробки применяется позже после того, как высота определена, чтобы включать границу/отступы в высоту или нет.   -  person Temani Afif    schedule 13.11.2019
comment
@Pointy Это было с самого начала ...   -  person Binarus    schedule 13.11.2019
comment
@Binarus извините, мало кофе   -  person Pointy    schedule 13.11.2019


Ответы (1)


border-box указывает браузеру учитывать любые границы и отступы в значениях, которые вы указываете для ширины и высоты элемента. Если вы установите ширину элемента равной 100 пикселям, эти 100 пикселей будут включать все добавленные вами границы и отступы, а окно содержимого уменьшится, чтобы поглотить эту дополнительную ширину. Обычно это значительно упрощает определение размеров элементов. ref

Вот пример, чтобы лучше проиллюстрировать вашу проблему:

.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>

Первый пример тривиален: мы уменьшаем высоту (красная область) до 0, а анимация никогда не останавливается.

Во втором случае высота включает отступ и границу, поэтому до достижения 0 область содержимого уже равна 0, поэтому анимация, кажется, останавливается, потому что мы не можем уменьшить более 0, а граница/отступ уже заняли все пространство.

Логично, что когда высота равна 0, оба они одинаковы, поскольку в первом случае мы сообщаем браузеру, что область содержимого должна быть равна 0 (нас не волнует отступ/граница), а во втором случае мы говорим браузеру учитывайте отступы/границу по высоте, которую мы указали, чтобы у нас было меньше места для области содержимого, и, поскольку у нас не может быть меньше 0, тогда это 0.

Другими словами, вы не устанавливаете общую высоту, которая будет разделена между областью содержимого, отступом и рамкой, но вы устанавливаете высоту, и браузер уменьшает ее насколько это возможно, чтобы включить граница и отступы.

Связано с дополнительными примерами и подробностями: box-sizing: border-box без объявленной высоты/ширины

person Temani Afif    schedule 13.11.2019
comment
Большое спасибо за ваше четкое объяснение (и анимацию, конечно) - принято и проголосовано. Я уже подозревал об этом, но хотел знать наверняка. Моя проблема заключалась в том, что (в основном в прежние дни) я видел много кода с отрицательными margins, tops и даже paddings (и так далее), и поэтому я думал, что содержимое height в конечном итоге может (должно?) стать отрицательным в этом случае , слишком. Ведь такое поведение лишает главное преимущество border-box (то есть его простоту). - person Binarus; 13.11.2019
comment
@Binarus нет, отрицательные значения не допускаются внутри (высота, отступы, граница), а только снаружи (поле). мне потребовалось бы слишком много времени, чтобы объяснить логическую причину этого, но суть в том, что нет логической иллюстрации чего-то вроде отрицательной высоты, но отрицательное поле можно проиллюстрировать с перекрытием. - person Temani Afif; 13.11.2019