Размеры и скорллинг HTML-документа

Продолжим рассматривать метрики и начнем с вопроса определения ширины и высоты всего клиентского окна браузера. Для этого можно обратиться к элементу-тегу html и посмотреть его значения свойств:

  • clientWidth – ширина клиентской области (за вычетом полосы вертикального скроллинга);
  • clientHeight – высота клиентской области (за вычетом полосы горизонтального скроллинга).

Например, так:

let html = document.documentElement;
console.log(html.clientWidth, html.clientHeight);

Другой способ – это обратиться к свойствам innerWidth/innerHeight объекта window:

  • window.innerWidth – полная ширина окна браузера вместе с полосой прокрутки (если она есть);
  • window.innerHeight – полная высота окна браузера вместе с горизонтальной полосой прокрутки (если она есть).

Например, добавим в документ вот такой список:

<ul style="font-size: 20px">
<li>offsetParent<li>offsetLeft
<li>offsetTop<li>offsetWidth
<li>offsetHeight<li>clientTop
<li>clientLeft<li>clientWidth
<li>clientHeight<li>scrollWidth
<li>scrollHeight<li>scrollLeft
<li>scrollTop<li>innerHeight
<li>innerWidth
</ul>

так, чтобы у нас появилась вертикальная полоса прокрутки. И дополнительно выведем в консоль свойства:

console.log(window.innerWidth, window.innerHeight);

Как видите, ширина окна в innerWidth не учитывает полосу прокрутки, а свойство clientWidth – учитывает. Вот этот момент следует иметь в виду при разработке скриптов.

Высота и ширина HTML-документа

Теперь предположим, что мы хотим определить всю ширину и высоту документа, загруженного в браузер. Формально, для этого следует обратиться опять же к тегу-элементу html и просмотреть его свойства scrollWidth/scrollHeight:

let html = document.documentElement;
console.log(html.scrollWidth, html.scrollHeight);

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

let scrollHeight = Math.max(
      document.body.scrollHeight, document.documentElement.scrollHeight,
      document.body.offsetHeight, document.documentElement.offsetHeight,
      document.body.clientHeight, document.documentElement.clientHeight
);
 
console.log(scrollHeight);

Почему это так работает? Думаю, этого никто не знает. И эта проблема наблюдается только для всего документа. Для отдельного элемента все работает через свойства scrollWidth/scrollHeight. А для всей страницы приходится использовать такой своеобразный «костыль» (как говорят программисты). Просто запомните этот момент: для корректного определения высоты (или ширины) всего документа в браузере, нужно брать максимальное значение среди этих свойств (для ширины будут соответствующие свойства, где вместо Height следует записать Width).

Получение текущего положения прокрутки

Далее, чтобы определить положение прокрутки всего документа, можно опять же воспользоваться объектом html и посмотреть значения его свойств scrollLeft/scrollTop, о которых мы говорили на предыдущем занятии. Например, так:

let html = document.documentElement;
console.log(body.scrollTop);

И, в общем то этим можно пользоваться без каких-либо проблем. Но в большинстве старых браузеров это свойство следовало получать при обращении к элементу body так:

console.log(document.body.scrollTop);

А в новых – это, наоборот, не работает. Но мы можем сделать все очень надежно, воспользовавшись свойствами:

  • window.pageXOffset – смещение документа в окне браузера по оси Ox;
  • window.pageYOffset – смещение документа в окне браузера по оси Oy.

Например:

console.log(window.pageYOffset);

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

Прокрутка (скроллинг) документа

Теперь посмотрим, как же все-таки осуществлять прокрутку всего документа. Во-первых, следует помнить, что прокрутка документа работает только после загрузки всей HTML-страницы, когда построено DOM-дерево. До этого рассматриваемые ниже методы скроллинга работать не будут. Так что, вот это имейте в виду.

Далее, в современных браузерах прокручивать документ можно через свойства объекта html:

  • document.documentElement.scrollTop
  • document.documentElement.scrollLeft

В некоторых старых браузерах этот вариант будет работать через body:

  • document.body.scrollTop
  • document.body.scrollLeft

Поэтому, для написания надежного кода, лучше использовать специальные методы скроллинга объекта window:

  • window.scrollBy(offX, offY) – прокручивает страницу относительно её текущего положения на смещения offX, offY пикселей;
  • window.scrollTo(pageX, pageY) – прокручивает страницу до указанных координат pageX и pageY.

Например, вот такой скрипт:

setInterval(function() {
    window.scrollBy(0, 5); 
}, 100);

будет прокручивать страницу вниз на 5 пикселей каждые 100 мс. А если прописать вот так:

setInterval(function() {
    window.scrollTo(0, 5);
}, 100);

то мы будем все время переходить в одну и ту же позицию на 5 пикселей по вертикальному скроллингу (вручную переводим вниз, он возвращается). И, например, строка:

window.scrollTo(0, 0);

будет возвращать нас просто к началу документа.

Для полноты картины давайте рассмотрим ещё один метод scrollIntoView, который имеет следующий синтаксис:

elem.scrollIntoView(top = true);

Данный метод существует у всех объектов-тегов DOM-дерева и прокручивает документ так, чтобы elem оказался вверху окна браузера (если значение top=true), или внизу, при значении top=false. Пусть, в начале документа имеется заголовок:

<h1 id="header_1">Список свойств метрики</h1>

и мы хотим прокрутить документ, чтобы он стал виден вверху страницы:

setTimeout(function() {
    header_1.scrollIntoView();
});

Обратите внимание, что мы вызвали этот метод через планировщик отложенного вызова – функцию setTimeout с нулевой задержкой. Если мы просто в скрипте напишем:

header_1.scrollIntoView();

то это работать не будет. Как мы отмечали в самом начале, все методы скроллинга работают после полной загрузки документа и построения DOM-дерева. И, вызывая scrollIntoView через setTimeout, мы как раз и выполняем это условие.

Запрет прокрутки документа

Наконец, бывают ситуации, когда нам нужно запретить прокручивать документ в браузере пользователю. В частности, эта необходимость возникает при отображении какого-либо блока поверх документа и мы не хотим, чтобы при этом работал общий скроллинг. Например, как в этой игре: при отображении блока div, имитирующего диалоговое окно, у всего документа отсутствуют полосы прокрутки.

Это делается очень простой конструкцией:

document.body.style.overflow = "hidden";

И теперь, при обновлении документа у нас пропадает вертикальная полоса прокрутки. Для восстановления полос, свойство overflow нужно сбросить, присвоив ей пустую строку:

document.body.style.overflow = "";

Итак, на этом занятии мы с вами рассмотрели способы определения размеров клиентского окна браузера, HTML-документа в целом и способы его прокрутки.

Видео по теме