clientWidth и clientHeight сообщают ноль, в то время как getBoundingClientRect является правильным

В описании MDN Element.clientWidth это говорит.

Примечание: с тех пор я обновил MDN в соответствии с ответом potatopeelings.

Свойство Element.clientWidth является внутренней шириной элемента в пикселях. Он включает отступы, но не вертикальную полосу прокрутки (если присутствует, если отображается), границу или поле.

Это свойство округляет значение до целого числа. Если вам нужно дробное значение, используйте element.getBoundingClientRect().

Из этого я понимаю, что кроме округления clientWidth должен быть таким же, как getBoundingClientRect().width,

Однако я вижу, что для многих элементов (где display является inline?) clientWidth (и высота) равны нулю, а значения, возвращаемые getBoundingClientRect кажется правильным.

Поиск в stackru приносит некоторые ответы о том, что это происходит до того, как документ находится в состоянии готовности, но я вижу это постоянно, а не только при загрузке страницы.

Это поведение одинаково для всех браузеров, которые я проверял. Где указано, что это должно быть поведение?

Образец:

function str(name, width, height) {
  return name + ': (' + width + ', ' + height + ')';
}

function test() {
  var s = document.getElementById('s');
  var rect = s.getBoundingClientRect();
  document.getElementById('out').innerHTML =
    str('client', s.clientWidth, s.clientHeight) + '<br/>' +
    str('bounding', rect.width, rect.height);
}
 <span id="s">A span</span><br/> <button onclick="test()">Test</button>
<hr />
<div id="out"></div>

3 ответа

Решение

Из спецификации ( http://www.w3.org/TR/cssom-view/)

Атрибут clientWidth должен выполнить эти шаги:

1.Если элемент не имеет связанного блока макета CSS или если блок макета CSS встроен, верните ноль.
...

В дополнение к ответу @potatopeelings:

Встроенные элементы не имеют внутренних или указанных размеров. Например, вы не можете определить ширину для span (если вы не измените это display имущество).

Также clientWidth а также getBoundingClientRect служат различным целям и могут возвращать разные значения. Последний также учитывает преобразования и возвращает размеры элемента в том виде, как он фактически отображается.

.class {
  transform: scale(0.5);
}

Если clientWidth вернул 1000 в этом случае, то ширина getBoundingClientRect будет 500.

Вы можете рассмотреть clientWidth как "сколько места у меня есть в элементе" и getBoundingClientRect как "сколько места элемент занимает на экране". Таким образом, в нашем случае элемент будет иметь достаточно места для размещения двух элементов размером 500 пикселей рядом, и он будет занимать 500 пикселей на экране.

Возвращаемое значение из getBoundingClientRect() является объектом DOMRect, который представляет собой объединение прямоугольников, возвращаемых getClientRects() для элемента; этот метод смотрит на размер ограничительной рамки, даже если элемент встроен (он не имеет ограничения для встроенных элементов, которые имеет clientWidth - specs @potatopeelings links).

function str(name, width, height) {
  return name + ': (' + width + ', ' + height + ')';
}

function test() {
  var s = document.getElementById('s');
  var rect = s.getBoundingClientRect();
  document.getElementById('out').innerHTML =
    str('client', s.clientWidth, s.clientHeight) + '<br/>' +
    str('bounding', rect.width, rect.height);
}
#s{
  display: inline-block
}
<span id="s">A span</span><br/> <button onclick="test()">Test</button>
<hr />
<div id="out"></div>

проверьте разницу при изменении свойства отображения на inline-block или же block,

Другие вопросы по тегам