Как узнать ширину и высоту окна браузера? Как получить полную ширину и высоту документа, включая прокрученную часть? Как прокрутить страницу с помощью JavaScript?
Для большинства таких запросов мы можем использовать корневой элемент документа document.documentElement
, который соответствует тегу <html>
. Однако есть дополнительные методы и особенности, которые необходимо учитывать.
Ширина/высота окна
Чтобы получить ширину/высоту окна, можно взять свойства clientWidth/clientHeight
из document.documentElement
:
Например, эта кнопка показывает высоту вашего окна:
window.innerWidth/Height
Браузеры также поддерживают свойства window.innerWidth/innerHeight
. Вроде бы, похоже на то, что нам нужно. Почему же не использовать их?
Если есть полоса прокрутки, и она занимает какое-то место, то свойства clientWidth/clientHeight
указывают на ширину/высоту документа без неё (за её вычетом). Иными словами, они возвращают высоту/ширину видимой части документа, доступной для содержимого.
А window.innerWidth/innerHeight
включают в себя полосу прокрутки.
Если полоса прокрутки занимает некоторое место, то эти две строки выведут разные значения:
alert( window.innerWidth ); // полная ширина окна
alert( document.documentElement.clientWidth ); // ширина окна за вычетом полосы прокрутки
В большинстве случаев нам нужна доступная ширина окна: для рисования или позиционирования. Полоса прокрутки «отъедает» её часть. Поэтому следует использовать documentElement.clientHeight/Width
.
DOCTYPE
– это важноОбратите внимание, что геометрические свойства верхнего уровня могут работать немного иначе, если в HTML нет <!DOCTYPE HTML>
. Возможны странности.
В современном HTML мы всегда должны указывать DOCTYPE
.
Ширина/высота документа
Теоретически, т.к. корневым элементом документа является documentElement
, и он включает в себя всё содержимое, мы можем получить полный размер документа как documentElement.scrollWidth/scrollHeight
.
Но именно на этом элементе, для страницы в целом, эти свойства работают не так, как предполагается. В Chrome/Safari/Opera, если нет прокрутки, то documentElement.scrollHeight
может быть даже меньше, чем documentElement.clientHeight
! С точки зрения элемента это невозможная ситуация.
Чтобы надёжно получить полную высоту документа, нам следует взять максимальное из этих свойств:
let scrollHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
alert('Полная высота документа с прокручиваемой частью: ' + scrollHeight);
Почему? Лучше не спрашивайте. Эти несоответствия идут с древних времён. Глубокой логики здесь нет.
Получение текущей прокрутки
Обычные элементы хранят текущее состояние прокрутки в elem.scrollLeft/scrollTop
.
Что же со страницей?
В большинстве браузеров мы можем обратиться к documentElement.scrollLeft/Top
, за исключением основанных на старом WebKit (Safari), где есть ошибка (5991), и там нужно использовать document.body
вместо document.documentElement
.
К счастью, нам совсем не обязательно запоминать эти особенности, потому что текущую прокрутку можно прочитать из свойств window.pageXOffset/pageYOffset
:
alert('Текущая прокрутка сверху: ' + window.pageYOffset);
alert('Текущая прокрутка слева: ' + window.pageXOffset);
Эти свойства доступны только для чтения.
window
также доступны scrollX
и scrollY
По историческим причинам существует два аналога window.pageXOffset
и window.pageYOffset
:
window.pageXOffset
– то же самое, что иwindow.scrollX
.window.pageYOffset
– то же самое, что иwindow.scrollY
.
Прокрутка: scrollTo, scrollBy, scrollIntoView
Для прокрутки страницы из JavaScript её DOM должен быть полностью построен.
Например, если мы попытаемся прокрутить страницу из скрипта, подключенного в <head>
, это не сработает.
Обычные элементы можно прокручивать, изменяя scrollTop/scrollLeft
.
Мы можем сделать то же самое для страницы в целом, используя document.documentElement.scrollTop/Left
(кроме основанных на старом WebKit (Safari), где, как сказано выше, document.body.scrollTop/Left
).
Есть и другие способы, в которых подобных несовместимостей нет: специальные методы window.scrollBy(x,y) и window.scrollTo(pageX,pageY).
-
Метод
scrollBy(x,y)
прокручивает страницу относительно её текущего положения. Например,scrollBy(0,10)
прокручивает страницу на10px
вниз.Кнопка ниже демонстрирует это:
-
Метод
scrollTo(pageX,pageY)
прокручивает страницу на абсолютные координаты(pageX,pageY)
. То есть, чтобы левый-верхний угол видимой части страницы имел данные координаты относительно левого верхнего угла документа. Это всё равно, что поставитьscrollLeft/scrollTop
. Для прокрутки в самое начало мы можем использоватьscrollTo(0,0)
.
В обоих методах вместо координат также может использоваться объект options
, как аргумент:
window.scrollTo(options);
window.scrollBy(options);
options
поддерживает три свойства:
window.scrollTo({
top: 100,
left: 0,
behavior: "smooth"
});
-
top
– то же самое, чтоy
/pageY
-
left
– то же самое, чтоx
/pageX
-
behavior
– определяет, каким образом будет прокручиваться страница:"smooth"
– плавно (не поддерживается в IE и в старых версиях Safari)"instant"
– мгновенно"auto"
– определяется браузером (зависит от CSS-свойства scroll-behavior)
Демонстрация плавной прокрутки страницы:
scrollIntoView
Для полноты картины давайте рассмотрим ещё один метод: elem.scrollIntoView(top).
Вызов elem.scrollIntoView(top)
прокручивает страницу, чтобы elem
оказался вверху.
У него есть один аргумент:
- если
top=true
(по умолчанию), то страница будет прокручена, чтобыelem
появился в верхней части окна. Верхний край элемента совмещён с верхней частью окна. - если
top=false
, то страница будет прокручена, чтобыelem
появился внизу. Нижний край элемента будет совмещён с нижним краем окна.
Кнопка ниже прокрутит страницу так, что она сама окажется вверху:
А следующая кнопка прокрутит страницу так, что она сама окажется внизу
Как и scrollTo
/scrollBy
, scrollIntoView
также принимает объект options
как аргумент (он немного отличается):
this.scrollIntoView(options).
options
поддерживает три свойства:
this.scrollIntoView({
behavior: "smooth",
block: "end",
inline: "nearest"
});
behavior
– анимация прокрутки (smooth
,instant
,auto
)block
– вертикальное выравнивание (start
,center
,end
,nearest
). Значение по умолчанию:start
inline
– горизонтальное выравнивание (start
,center
,end
,nearest
). Значение по умолчанию:nearest
Запретить прокрутку
Иногда нам нужно сделать документ «непрокручиваемым». Например, при показе большого диалогового окна над документом – чтобы посетитель мог прокручивать это окно, но не документ.
Чтобы запретить прокрутку страницы, достаточно установить document.body.style.overflow = "hidden"
.
Попробуйте сами:
Первая кнопка останавливает прокрутку, вторая возобновляет её.
Аналогичным образом мы можем «заморозить» прокрутку для других элементов, а не только для document.body
.
Недостатком этого способа является то, что сама полоса прокрутки исчезает. Если она занимала некоторую ширину, то теперь эта ширина освободится, и содержимое страницы расширится, текст «прыгнет», заняв освободившееся место.
Это выглядит немного странно, но это можно обойти, если сравнить clientWidth
до и после остановки, и если clientWidth
увеличится (значит полоса прокрутки исчезла), то добавить padding
в document.body
вместо полосы прокрутки, чтобы оставить ширину содержимого прежней.
Итого
Размеры:
-
Ширина/высота видимой части документа (ширина/высота области содержимого):
document.documentElement.clientWidth/Height
-
Ширина/высота всего документа со всей прокручиваемой областью страницы:
let scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight );
Прокрутка:
-
Прокрутку окна можно получить так:
window.pageYOffset/pageXOffset
. -
Изменить текущую прокрутку:
window.scrollTo(pageX,pageY)
– абсолютные координаты,window.scrollBy(x,y)
– прокрутка относительно текущего места,elem.scrollIntoView(top)
– прокрутить страницу так, чтобы сделатьelem
видимым (выровнять относительно верхней/нижней части окна).