renovations

This commit is contained in:
Ilya Kantor 2015-01-26 23:25:30 +03:00
parent 8be16abadd
commit d3960d16ac
17 changed files with 316 additions and 335 deletions

View file

@ -287,46 +287,11 @@ function getStyle(elem) {
Он основан на свойствах `runtimeStyle` и `pixelLeft`, работающих только в IE. Он основан на свойствах `runtimeStyle` и `pixelLeft`, работающих только в IE.
В следующем примере функция `getIEComputedStyle(elem, prop)` получает значение в пикселях для свойства `prop`, используя `elem.currentStyle` и метод Дина Эдвардса. В [edit src="getiecomputedstyle"]песочнице[/edit] вы можете найти функцию `getIEComputedStyle(elem, prop)`, которая получает значение в пикселях для свойства `prop`, используя `elem.currentStyle` и метод Дина Эдвардса, и пример её применения.
Если вам интересно, как он работает, ознакомьтесь со свойствами с <a href="http://msdn.microsoft.com/en-us/library/ms535889(v=vs.85).aspx">runtimeStyle</a> и <a href="http://msdn.microsoft.com/en-us/library/ms531129%28VS.85%29.aspx">pixelLeft</a> в MSDN и раскройте код. Если вам интересно, как он работает, ознакомьтесь со свойствами с <a href="http://msdn.microsoft.com/en-us/library/ms535889(v=vs.85).aspx">runtimeStyle</a> и <a href="http://msdn.microsoft.com/en-us/library/ms531129%28VS.85%29.aspx">pixelLeft</a> в MSDN и раскройте код.
```js Конечно, это актуально только для IE8- и полифиллов.
//+ src="getIEComputedStyle.js" hide="Раскрыть код"
```
<script src="/files/tutorial/browser/dom/getIEComputedStyle.js"></script>
Рабочий пример (только IE):
```html
<style> #margin-test { margin: 1%; border: 1px solid black; } </style>
<div id="margin-test">Тестовый элемент с margin 1%</div>
<script>
var elem = document.getElementById('margin-test');
if (!elem.getComputedStyle) // старые IE
document.write(getIEComputedStyle(elem, 'marginTop'));
else
document.write('Пример работает только в IE8-');
</script>
```
[pre]
<style> #margin-test { margin: 1%; border: 1px solid black; } </style>
<div id="margin-test">Тестовый элемент с margin 1%</div>
<i>
<script>
var elem = document.getElementById('margin-test');
if (!window.getComputedStyle) // старые IE
document.write(getIEComputedStyle(elem, 'marginTop'));
else
document.write('Пример работает только в IE8-');
</script>
</i>
[/pre]
Современные Javascript-фреймворки и полифиллы используют этот прием для эмуляции `getComputedStyle` в старых IE.
[/smart] [/smart]
@ -343,5 +308,5 @@ function getStyle(elem) {
При этом `currentStyle` возвращает значение из CSS, до окончательных вычислений, а `getComputedStyle` -- окончательное, непосредственно применённое к элементу (как правило).</li> При этом `currentStyle` возвращает значение из CSS, до окончательных вычислений, а `getComputedStyle` -- окончательное, непосредственно применённое к элементу (как правило).</li>
</ul> </ul>
Более полная информация о `style`, включающая другие, реже используемые методы работы с ним, доступна здесь: [CSSStyleDeclaration](https://developer.mozilla.org/en-US/docs/DOM/CSSStyleDeclaration). Более полная информация о свойстве `style`, включающая другие, реже используемые методы работы с ним, доступна [в документации](https://developer.mozilla.org/en-US/docs/DOM/CSSStyleDeclaration).

View file

@ -1,18 +0,0 @@
function getIEComputedStyle(elem, prop) {
var value = elem.currentStyle[prop] || 0
// we use 'left' property as a place holder so backup values
var leftCopy = elem.style.left
var runtimeLeftCopy = elem.runtimeStyle.left
// assign to runtimeStyle and get pixel value
elem.runtimeStyle.left = elem.currentStyle.left
elem.style.left = (prop === "fontSize") ? "1em" : value
value = elem.style.pixelLeft + "px";
// restore values for left
elem.style.left = leftCopy
elem.runtimeStyle.left = runtimeLeftCopy
return value
}

View file

@ -0,0 +1,18 @@
function getIEComputedStyle(elem, prop) {
var value = elem.currentStyle[prop] || 0;
// we use 'left' property as a place holder so backup values
var leftCopy = elem.style.left;
var runtimeLeftCopy = elem.runtimeStyle.left;
// assign to runtimeStyle and get pixel value
elem.runtimeStyle.left = elem.currentStyle.left;
elem.style.left = (prop === "fontSize") ? "1em" : value;
value = elem.style.pixelLeft + "px";
// restore values for left
elem.style.left = leftCopy;
elem.runtimeStyle.left = runtimeLeftCopy;
return value;
}

View file

@ -0,0 +1,24 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="getiecomputedstyle.js"></script>
</head>
<body>
<style>
#margin-test { margin: 1%; border: 1px solid black; }
</style>
<div id="margin-test">Тестовый элемент с margin 1%</div>
<script>
var elem = document.getElementById('margin-test');
if (!window.getComputedStyle) { // старые IE
document.write(getIEComputedStyle(elem, 'marginTop'));
} else {
document.write('Пример работает только в IE8-');
}
</script>
</body>
</html>

View file

@ -2,8 +2,8 @@
[importance 5] [importance 5]
Свойство `elem.scrollTop` содержит размер прокрученной области при отсчете сверху. А как подсчитать его снизу? Свойство `elem.scrollTop` содержит размер прокрученной области при отсчете сверху. А как подсчитать размер прокрутки снизу?
Напишите соответствующее выражение для произвольного элемента `elem`. Напишите соответствующее выражение для произвольного элемента `elem`.
Проверьте: если прокрутки нет или элемент полностью прокручен -- оно должно давать ноль. Проверьте: если прокрутки нет вообще или элемент полностью прокручен -- оно должно давать ноль.

View file

@ -8,7 +8,7 @@
**Всё, кроме `margin`, можно получить из свойств DOM-элемента, а `margin` -- только через `getComputedStyle`.** **Всё, кроме `margin`, можно получить из свойств DOM-элемента, а `margin` -- только через `getComputedStyle`.**
Причём `margin` мы обязаны поставить, так как иначе элемент не будет отодвинут от внешних. Причём `margin` мы обязаны поставить, так как иначе наш элемент при вставке будет вести себя иначе, чем исходный.
Код: Код:

View file

@ -38,7 +38,9 @@ div.style.right = div.style.top = 0;
**Допишите код Валеры, сделав так, чтобы текст оставался на своем месте после того, как `DIV` будет смещен.** **Допишите код Валеры, сделав так, чтобы текст оставался на своем месте после того, как `DIV` будет смещен.**
Сделайте это путем создания вспомогательного `DIV` с теми же размерами (`width`, `height`, `border`, `margin`, `padding`), что и у желтого `DIV`. Используйте только JavaScript, без CSS. Сделайте это путем создания вспомогательного `DIV` с теми же `width`, `height`, `border`, `margin`, `padding`, что и у желтого `DIV`.
Используйте только JavaScript, без CSS.
Должно быть так (новому блоку задан фоновый цвет для демонстрации): Должно быть так (новому блоку задан фоновый цвет для демонстрации):

View file

@ -5,17 +5,15 @@
Поместите мяч в центр поля. Поместите мяч в центр поля.
Исходный документ выглядит так: Исходный документ выглядит так:
[iframe src="source" edit link] [iframe src="source" edit link height=180]
**Используйте JavaScript, чтобы поместить мяч в центр:** **Используйте JavaScript, чтобы поместить мяч в центр:**
[iframe src="solution"] [iframe src="solution" height=180]
<ul> <ul>
<li>Менять CSS нельзя, мяч должен переносить в центр ваш скрипт, через установку нужных стилей элемента.</li> <li>Менять CSS нельзя, мяч должен переносить в центр ваш скрипт, через установку нужных стилей элемента.</li>
<li>Код не должен быть привязан к конкретному размеру мяча.</li> <li>JavaScript-код должен работать при разных размерах мяча (`10`, `20`, `30` пикселей) без изменений.</li>
<li>Обратите внимание: мяч должен быть строго по центру! Независимо от местоположения поля и ширины его рамки.</li> <li>JavaScript-код должен работать при различных размерах и местоположениях поля на странице без изменений. Также он не должен зависеть от ширины рамки поля `border`.</li>
</ul> </ul>
P.S. Да, центрирование можно сделать при помощи чистого CSS, но задача именно на JavaScript. Далее будут другие темы и более сложные ситуации, когда JavaScript будет уже точно необходим, это -- своего рода "разминка".
P.S. Да, это можно сделать при помощи чистого CSS, но задача именно на JavaScript. Далее будет развитие темы и более сложные ситуации, когда JavaScript будет уже точно необходим.

View file

@ -1,23 +1,36 @@
**Вначале рассмотрим неверный вариант.** # Решение через width: auto
Он выглядит так: Вначале рассмотрим решение через "умную" установку CSS-свойства.
Они могут быть разными. Самое простое выглядит так:
```js
elem.style.width = 'auto';
```
Такой способ работает, так как `<div>` по умолчанию распахивается на всю ширину.
Конечно, такое решение не будет работать для элементов, которые сами по себе не растягиваются, например в случае со `<span>` или при наличии `position: absolute`.
Обратим внимание, такой вариант был бы неверен:
```js ```js
elem.style.width = '100%'; elem.style.width = '100%';
``` ```
Если вы его попробуете, то увидите, что элемент начинает вылезать за рамки родителя. По умолчанию в CSS ширина `width` -- это то, что *внутри `padding`*, а проценты отсчитываются от ширины родителя. То есть, ставя ширину в `100%`, мы говорим: "внутренняя область должна занимать `100%` ширины родителя". А в элементе есть ещё `padding`, которые в итоге вылезут наружу.
Так происходит потому, что ширина -- это то, что *внутри `padding`*. То есть, ставя ширину в `100%`, вы говорите: "внутренняя область должна занимать `100%` доступной ширины". А на `padding` остаётся `0%`. В результате поля вылезают наружу. Можно бы поменять блочную модель, указав `box-sizing` через свойство `elem.style.boxSizing`, но такое изменение потенциально может затронуть много других свойств, поэтому нежелательно.
**Правильное решение через `clientWidth`.** # Точное вычисление
Доступную внутреннюю ширину родителя можно получить, вычитая `padding` из `clientWidth`, и присвоить элементу: Альтернатива -- вычислить ширину родителя через `clientWidth`.
Доступную внутреннюю ширину родителя можно получить, вычитая из `clientWidth` размеры `paddingLeft/paddingRight`, и затем присвоить её элементу:
```js ```js
var bodyClientWidth = document.body.clientWidth; var bodyClientWidth = document.body.clientWidth;
var style = window.getComputedStyle ? getComputedStyle(elem, '') : elem.currentStyle; var style = getComputedStyle(elem);
*!* *!*
var bodyInnerWidth = bodyClientWidth - parseInt(style.paddingLeft) - parseInt(style.paddingRight); var bodyInnerWidth = bodyClientWidth - parseInt(style.paddingLeft) - parseInt(style.paddingRight);
@ -26,20 +39,5 @@ var bodyInnerWidth = bodyClientWidth - parseInt(style.paddingLeft) - parseInt(st
elem.style.width = bodyInnerWidth + 'px'; elem.style.width = bodyInnerWidth + 'px';
``` ```
Этот вариант сломается, если в IE<9 значение `padding` указано не в пикселях. Получение пикселей из процентов и других единиц измерения рассмотрено в главе [](/styles-and-classes). Такое решение будет работать всегда, вне зависимости от типа элемента.
**Правильный вариант с CSS.**
**Самое лучшее решение получится, если вспомнить, что элемент и сам рад растянуться по всей доступной ширине, и делает это по умолчанию.**
Достаточно вернуть ему стандартный алгоритм вычисленя ширины, установив `width: auto`:
```js
elem.style.width = 'auto';
```
Но.. **Это не будет работать для элементов, которые сами по себе не растягиваются**, например в случае `position: absolute` или `float`.
Такой элемент можно расширить, используя предыдущее решение.
[edit src="solution"]Документ с обоими решениями[/edit]

View file

@ -1,18 +1,15 @@
# Расширить элемент # Расширить элемент
[importance 3] [importance 4]
В `BODY` есть элемент `DIV` с заданной шириной `width`. В `<body>` есть элемент `<div>` с заданной шириной `width`.
Задача -- написать код, который "распахнет" `DIV` по ширине на всю страницу. Задача -- написать код, который "распахнет" `<div>` по ширине на всю страницу.
Исходный документ (`DIV` -- красный): Исходный документ (`<div>` содержит текст и прокрутку):
[iframe height=220 src="source"] [iframe height=220 src="source"]
P.S. Пользоваться следует исключительно средствами JS, CSS в этой задаче менять нельзя. Также ваш код должен быть универсален и не ломаться, если цифры в CSS станут другими.
P.P.S. При расширении элемент `<div>` не должен вылезти за границу `<body>`.
Расширить нужно точно по ширине, чтобы красный `DIV` не вылез за границы `BODY`.
P.S. Пользоваться следует исключительно средствами JS, при этом не подглядывая в стили. То есть, код должен быть универсален и не ломаться, если цифры в CSS станут другими.
P.P.S. После того, как решите... Будет ли ваше решение работать, если у красного `DIV` стоит `position:absolute`? Если нет, то почему и как его поправить?

View file

@ -2,9 +2,9 @@
<ol> <ol>
<li>`getComputedStyle` не работает в IE8-.</li> <li>`getComputedStyle` не работает в IE8-.</li>
<li>`clientWidth` возвращает число, а `getComputedStyle(...).width` -- в `px`.</li> <li>`clientWidth` возвращает число, а `getComputedStyle(...).width` -- строку, на конце `px`.</li>
<li>`getComputedStyle` не всегда даст ширину, он может вернуть, к примеру, `"auto"` для инлайнового элемента.</li> <li>`getComputedStyle` не всегда даст ширину, он может вернуть, к примеру, `"auto"` для инлайнового элемента.</li>
<li>`clientWidth` соответствует внутренней видимой области элемента, *включая `padding`, а CSS-ширина `width`, при стандартном значении [box-sizing](/box-sizing), соответствует зоне *внутри `padding`*.</li> <li>`clientWidth` соответствует внутренней видимой области элемента, *включая `padding`, а CSS-ширина `width` при стандартном значении `box-sizing` соответствует зоне *внутри `padding`*.</li>
<li>Если есть полоса прокрутки, то некоторые браузеры включают её ширину в `width`, а некоторые -- нет. <li>Если есть полоса прокрутки, то некоторые браузеры включают её ширину в `width`, а некоторые -- нет.
Свойство `clientWidth`, с другой стороны, полностью кросс-браузерно. Оно всегда обозначает размер *за вычетом прокрутки*, т.е. реально доступный для содержимого.</li> Свойство `clientWidth`, с другой стороны, полностью кросс-браузерно. Оно всегда обозначает размер *за вычетом прокрутки*, т.е. реально доступный для содержимого.</li>

View file

@ -2,6 +2,6 @@
[importance 5] [importance 5]
В чём отличия между `getComputedStyle(elem, "").width` и `elem.clientWidth`? В чём отличия между `getComputedStyle(elem).width` и `elem.clientWidth`?
В решении приведены пять отличий. Постарайтесь найти столько же или больше :) Укажите хотя бы три отличия, лучше -- больше.

View file

@ -1,19 +1,79 @@
# Размеры и прокрутка элементов # Размеры и прокрутка элементов
Для того, чтобы показывать элементы правильно, подгонять на нужные места страницы, управлять ими при помощи мыши, необходимо во-первых, знать CSS-позиционирование, а во-вторых -- уметь работать с "геометрией элементов" из JavaScript. Для того, чтобы показывать элементы на произвольных местах страницы, необходимо во-первых, знать CSS-позиционирование, а во-вторых -- уметь работать с "геометрией элементов" из JavaScript.
В этой главе мы поговорим о размерах элементов DOM, способах их вычисления и *метриках* -- различных свойствах, которые содержат эту информацию. В этой главе мы поговорим о размерах элементов DOM, способах их вычисления и *метриках* -- различных свойствах, которые содержат эту информацию.
[cut]
## Образец документа
Мы будем использовать для примера блок, у которого есть рамка (border), поля (padding), отступы (margin) и прокрутка: [cut]
## Не стоит брать width/height из CSS
Какой способ первый приходит на ум, когда есть задача определить ширину/высоту элемента.
Если вы внимательно читали до этого момента, то уж точно знаете, что CSS-высоту и ширину можно установить с помощью `elem.style` и извлечь, используя `getComputedStyle`, которые в подробностях обсуждаются в главе [](/styles-and-classes).
Получение ширины может быть таким:
```js
//+ run
var elem = document.body;
alert( getComputedStyle(elem).width ); // вывести CSS-ширину для body
```
Всегда ли такой подход сработает? Увы, нет!
<ol>
<li>Во-первых, CSS-свойства `width/height` зависят от другого свойства -- `box-sizing`, которое определяет, что такое, собственно, эти ширина и высота. Получается, что изменение этого свойства, к примеру, для более удобной вёрстки, может сломать JavaScript.</li>
<li>Во-вторых, свойства `width/height` могут быть равны `auto`.
Например, для инлайн-элемента:
```html
<!--+ run -->
<span id="elem">Привет!</span>
<script>
*!*
alert( getComputedStyle(elem).width ); // auto
*/!*
</script>
```
</li>
</ol>
Конечно, с точки зрения CSS размер `auto` -- совершенно нормально, но нам-то в JavaScript нужен конкретный размер в пикселях, который мы могли бы использовать для вычислений. Получается, что в данном случае ширина `width` из CSS вообще бесполезна.
## Полоса прокрутки и содержимое
Полоса прокрутки -- причина многих проблем и недопониманий. Как говорится, "дьявол кроется в деталях". Недопустимо, чтобы наш код работал на элементах без прокрутки и начинал "глючить" с ней. Поэтому мы с самого начала будем её учитывать.
При наличии вертикальной полосы прокрутки -- во многих операционных системах и браузерах она забирает себе место у "внутренней части" элемента.
...Но при этом некоторые браузеры отражают реальное уменьшение ширины в результате `getComputedStyle(elem).width`, а некоторые -- нет.
В примере ниже у элемента с текстом в стилях указано `width:300px`. А вот `getComputedStyle` возвращает значение от `280px` до `300px`, в зависимости от ОС и браузера.
[online]
Если ваш браузер в принципе показывает полосу прокрутки (например, под Windows почти все браузеры так делают), то вы можете протестировать это сами, нажав на кнопку в ифрейме ниже:
[/online]
[iframe src="cssWidthScroll" link border=1]
Описанные разночтения касаются только чтения свойства `getComputedStyle(...).width` из JavaScript, визуальное отображение корректно в обоих случаях -- ширина текста при наличии прокрутки в обоих случаях уменьшается.
Этот пример важен, чтобы ещё лучше понять: свойство `width` из CSS не следует использовать в JavaScript. И, конечно, далее мы будем вспоминать о полосе прокрутке там, где она важна.
## Метрики: образец документа
Мы будем использовать для примера вот такой элемент, у которого есть рамка (border), поля (padding), отступы (margin) и прокрутка:
```html ```html
<div id="example"> <div id="example">
...Текст... ...Текст...
</div> </div>
<style> <style>
##example { #example {
width: 300px; width: 300px;
height: 200px; height: 200px;
@ -23,7 +83,7 @@
margin: 20px; /* отступы 20px */ margin: 20px; /* отступы 20px */
overflow: auto; /* прокрутка */ overflow: auto; /* прокрутка */
} }
</style> </style>
``` ```
@ -31,141 +91,25 @@
<img src="css.png"> <img src="css.png">
Вы можете открыть документ [edit src="metric"]по этой ссылке[/edit]. Вы можете открыть этот документ [edit src="metric"]в песочнице[/edit].
## Получение width/height из CSS
Какой способ первый приходит на ум, когда есть задача определить `width/height`? У элементов существует ряд свойств, содержащих их внешние и внутренние размеры. Мы будем называть их "метриками".
Если вы внимательно читали до этого момента, то уж точно знаете, что CSS-высоту и ширину `width/height` можно установить с помощью `elem.style` и извлечь, используя `getComputedStyle()/currentStyle`, которые в подробностях обсуждаются в главе [](/styles-and-classes). Метрики, в отличие от свойств CSS, содержат числа, всегда в пикселях и без единиц измерения на конце.
Решение может быть таким: Вот общая картина:
```js <img src="summary2.png">
//+ run
var elem = document.body;
var style = window.getComputedStyle ? getComputedStyle(elem, "") : elem.currentStyle; На картинке все они с трудом помещаются, но, как мы увидим далее, их значения просты и понятны.
alert(style.width); // вывести CSS-ширину body
```
Всегда ли такой подход сработает? Увы, нет! Будем исследовать их снаружи элемента и вовнутрь.
<ol> ## offsetWidth/Height
<li>Во-первых, CSS-свойства `width/height` зависят от другого свойства -- `box-sizing`, которое определяет, что такое, собственно, эти ширина и высота. По умолчанию они относятся к размеру внутренней части элемента, которая лежит внутри `padding`, а если нужно узнать полную высоту/ширину?</li>
<li>В IE8- могут быть нестыковки с единицами измерения -- как мы помним, `currentStyle` не пересчитывает размеры в пиксели.</li>
<li>И, наконец, самое главное, свойства `width/height` могут быть равны `auto`!
Например, для инлайн-элемента: Эти свойства дают "внешнюю" ширину/высоту элемента, то есть его полный размер, включая рамки `border`, но исключая внешние отступы `margin`.
```html
<!--+ run -->
<span id="elem">Привет!</span>
<script>
alert( getComputedStyle(elem, "").width ); // auto
</script>
```
Конечно, с точки зрения CSS размер `auto` -- совершенно нормально, но нам-то в JavaScript нужен конкретный размер в пикселях, который мы сможем использовать для вычислений.
</li>
</ol>
## Полоса прокрутки
Полоса прокрутки -- причина многих проблем и недопониманий. Как говорится, "дьявол кроется в деталях". Недопустимо, чтобы наш код работал на элементах без прокрутки и начинал "глючить" с ней. Поэтому мы с самого начала будем её учитывать.
**При наличии вертикальной полосы прокрутки -- она забирает себе часть ширины элемента.**
Ширина полосы прокрутки обычно составляет около `14-18px`, в зависимости от браузера и операционной системы. Бывает и `0` для полупрозрачной прокрутки, не отъедающей место. В примере подразумевается, что прокрутка место ест, поэтому внутренняя область будет уже не `300px`, а около `284px`.
**Несмотря на то, что на рисунке полоса прокрутки находится визуально в правом поле -- отнимает место она не у `padding`, а у внутренней области элемента.**
...Но при этом некоторые браузеры отражают это уменьшение ширины в результате `getComputedStyle(...).width`, а некоторые -- нет.
В примере ниже в стилях указано `width:300px`. А вот `getComputedStyle` возвращает `300px/284px`, в зависимости от браузера.
Если ваш браузер в принципе показывает полосу прокрутки (например, под Windows почти все браузеры так делают), то вы можете протестировать это сами, нажав на кнопку в ифрейме ниже:
[iframe src="cssWidthScroll" link border=1]
Описанные разночтения касаются только чтения свойства `getComputedStyle(...).width` из JavaScript, визуальное отображение корректно в обоих случаях -- ширина текста при наличии прокрутки в обоих случаях уменьшается.
**Здесь и далее, мы будем понимать под `width` именно реальную ширину внутренней области (около `284px`), а не результат чтения CSS-свойства `width`, который может быть разным в зависимости от браузера/OS.**
## JavaScript-метрики
В JavaScript существует ряд дополнительных свойств, содержащих размеры элементов. Мы будем называть их "метриками".
**Метрики JavaScript, в отличие от свойств CSS, содержат числа, всегда в пикселях и без единиц измерения на конце.**
### clientWidth/Height
Размер *клиентской зоны*, а именно: внутренняя область плюс `padding`.
<img src="clientWidth.png">
Общая ширина внутри рамки -- это `284 (width) + 20(padding left) + 20 (padding right) = 324`.
Получаем:
```js
clientWidth = 284(width) + 2*20(padding) = 324
clientHeight = 200(height) + 2*20(padding) = 240
```
Обратите внимание, в `clientHeight` входят и верхнее и нижнее поля, несмотря на то, что нижнее поле заполнено текстом.
**Если `padding` нет, то `clientWidth/Height` покажет реальный размер области данных, внутри рамок и полосы прокрутки.**
<img src="clientWidthNoPadding.png">
### scrollWidth/Height
Ширина и высота контента *с учетом прокручиваемой области*.
<ul>
<li>`scrollHeight = 723` -- полная высота, включая прокрученную область</li>
<li>`scrollWidth = 324` -- полная ширина, включая прокрученную область</li>
</ul>
**`scrollWidth/Height` то же самое, что и `clientWidth/Height`, но включает в себя прокручиваемую область.**
<img src="scrollWidth.png">
Эти свойства можно использовать, чтобы "распахнуть" элемент на всю ширину/высоту:
```js
element.style.height = element.scrollHeight + 'px';
```
Нажмите на кнопку, чтобы распахнуть элемент:
<div id="scrollOpen" style="width:300px;height:200px; padding: 0;overflow: auto; border:1px solid black;">текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст</div>
<button style="padding:0" onclick="document.getElementById('scrollOpen').style.height = document.getElementById('scrollOpen').scrollHeight + 'px'">element.style.height = element.scrollHeight + 'px'</button>
### scrollTop/scrollLeft
Размеры текущей прокрученной части элемента -- вертикальной и горизонтальной.
Следующее изображение иллюстрирует `scrollHeight` и `scrollTop` для блока с вертикальной прокруткой.
<img src="scrollTop.png">
[smart header="`scrollLeft/scrollTop` можно изменять"]
**В отличие от большинства свойств, которые доступны только для чтения, значения `scrollLeft/scrollTop` можно изменить, и браузер выполнит прокрутку элемента**.
При клике на следующий элемент будет выполняться код `elem.scrollTop += 10`. Поэтому он будет прокручиваться на `10px` вниз:
<div onclick="this.scrollTop+=10" style="cursor:pointer;border:1px solid black;width:100px;height:80px;overflow:auto">Кликни<br>Меня<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9</div>
[/smart]
### offsetWidth/Height
Внешняя ширина/высота блока, полный размер, включая рамки, исключая внешние отступы `margin`.
В примере выше:
<ul> <ul>
<li>`offsetWidth = 390` -- внешняя ширина блока</li> <li>`offsetWidth = 390` -- внешняя ширина блока</li>
<li>`offsetHeight = 290` -- внешняя высота блока</li> <li>`offsetHeight = 290` -- внешняя высота блока</li>
@ -173,37 +117,15 @@ element.style.height = element.scrollHeight + 'px';
<img src="offsetWidth.png"> <img src="offsetWidth.png">
Эти свойства показывают *внешние* ширину и высоту блока, то как блок выглядит снаружи. ## offsetParent, offsetLeft/Top
### clientTop/Left
Отступ *клиентской области* от внешнего угла блока.
Другими словами, это ширина верхней/левой рамки(border) в пикселях.
<ul>
<li>`clientLeft = 25` -- ширина левой рамки</li>
<li>`clientTop = 25` -- ширина верхней рамки</li>
</ul>
<img src="clientLeft.png">
Казалось бы, зачем еще какие-то свойства, если ширину рамки можно получить напрямую из CSS? Обычно они действительно не нужны.
Но есть две ситуации, когда эти свойства бывают полезны:
<ol>
<li>В случае, когда документ располагается *справа налево* (арабский язык, иврит), свойство `clientLeft` включает в себя еще и ширину *правой* полосы прокрутки.</li>
<li>В IE&lt;8 документ, а точнее -- элемент `document.documentElement` немного смещен относительно верхнего левого угла документа. Несмотря на то, что рамки там нет, сдвиг существует и хранится в `document.body.clientLeft/clientTop` (обычно это 2 пикселя).</li>
</ol>
### offsetParent, offsetLeft/Top
[warn header="Используются редко..."] [warn header="Используются редко..."]
Ситуации, когда эти свойства нужны, можно перечислить по пальцам. Они возникают действительно редко. Как правило, эти свойства используют по ошибке, потому что не знают средств правильной работы с координатами, о которых мы поговорим позже. Ситуации, когда эти свойства нужны, можно перечислить по пальцам. Они возникают действительно редко. Как правило, эти свойства используют по ошибке, потому что не знают средств правильной работы с координатами, о которых мы поговорим позже.
[/warn] [/warn]
**`offsetParent` -- это родительский элемент в смысле отображения на странице.** В `offsetParent` -- ссылка родительский элемент в смысле отображения на странице.
Уточним, что имеется в виду.
Когда браузер рисует страницу, то он высчитывает дерево расположения элементов, иначе говоря "дерево геометрии" или "дерево рендеринга". Когда браузер рисует страницу, то он высчитывает дерево расположения элементов, иначе говоря "дерево геометрии" или "дерево рендеринга".
@ -211,19 +133,21 @@ element.style.height = element.scrollHeight + 'px';
Но, к примеру, если у элемента стоит `position: absolute`, то его расположение вычисляется уже не относительно непосредственного родителя `parentNode`, а относительно ближайшего <a href="http://www.w3.org/TR/CSS21/visuren.html#position-props">позиционированного элемента</a> (т.е. свойство `position` которого не равно `static`), или `BODY`, если таковой отсутствует. Но, к примеру, если у элемента стоит `position: absolute`, то его расположение вычисляется уже не относительно непосредственного родителя `parentNode`, а относительно ближайшего <a href="http://www.w3.org/TR/CSS21/visuren.html#position-props">позиционированного элемента</a> (т.е. свойство `position` которого не равно `static`), или `BODY`, если таковой отсутствует.
Получается, что элемент имеет одного родителя в DOM и другого -- в плане позиционирования, относительно которого он рисуется. Этот элемент и будет в свойстве `offsetParent`. Получается, что элемент имеет в дополнение к родителю в DOM -- ещё одного "родителя" в плане позиционирования, то есть относительно которого он рисуется. Этот элемент и будет в свойстве `offsetParent`.
**Свойства `offsetLeft/Top` задают смещение относительно `offsetParent`.** Свойства `offsetLeft/Top` задают смещение относительно `offsetParent`.
В примере ниже внешний `<div>` является родителем внутреннего по позиционированию, и отступ от него будет в `offsetLeft/Top`:
```html ```html
<div style="position: relative"> <div style="position: relative">
<form>
<div style="position: absolute; left: 180px; top: 180px">...</div> <div style="position: absolute; left: 180px; top: 180px">...</div>
</form>
</div> </div>
``` ```
<img src="offsetLeft.png"> <img src="offsetLeft.png">
</dd>
</dl>
[smart header="Метрики для невидимых элементов равны нулю."] [smart header="Метрики для невидимых элементов равны нулю."]
@ -242,13 +166,102 @@ function isHidden(elem)
<ul> <ul>
<li>Работает, даже если родителю элемента установлено свойство `display:none`.</li> <li>Работает, даже если родителю элемента установлено свойство `display:none`.</li>
<li>Работает для всех элементов, кроме `TR`, с которым возникают некоторые проблемы в разных браузерах. Обычно, проверяются не `TR`, поэтому всё ок :).</li> <li>Работает для всех элементов, кроме `TR`, с которым возникают некоторые проблемы в разных браузерах. Обычно, проверяются не `TR`, поэтому всё ок.</li>
<li>Считает элемент видимым, даже если позиционирован за пределами экрана или имеет свойство `visibility:hidden`.</li> <li>Считает элемент видимым, даже если позиционирован за пределами экрана или имеет свойство `visibility:hidden`.</li>
<li>"Схлопнутый" элемент, например пустой `div` без высоты и ширины, будет считаться невидимым.</li> <li>"Схлопнутый" элемент, например пустой `div` без высоты и ширины, будет считаться невидимым.</li>
</ul> </ul>
[/smart] [/smart]
### clientTop/Left
Отступ внутренней части элемента от внешней.
Другими словами, это ширина верхней/левой рамки(border) в пикселях.
В нашем примере:
<ul>
<li>`clientLeft = 25` -- ширина левой рамки</li>
<li>`clientTop = 25` -- ширина верхней рамки</li>
</ul>
<img src="clientLeft.png">
Казалось бы, зачем еще какие-то свойства, если ширину рамки можно получить напрямую из CSS? Да, можно. Обычно они действительно не нужны.
Но в случае, когда документ располагается *справа налево* (арабский язык, иврит), полоса прокрутки находится слева, и тогда свойство `clientLeft` включает в себя еще и ширину полосы прокрутки.
## clientWidth/Height
Эти свойства -- размер внутренней зоны элемента внутри рамок `border`.
Она включает в себя как ширину содержимого `width`, так и поля `padding`:
<img src="clientWidth.png">
Как видно на рисунке выше, `clientWidth` в нашем документе складывается из ширины области содержимого (`284px`) плюс левый и правый `padding` (по `20px`), то есть всего `324px`.
Аналогично, `clientHeight` -- это высота области содержимого (`200px`) плюс верхний и нижний `padding` (по `20px`), то есть `240px`. На рисунке выше нижний `padding` заполнен текстом, но это неважно: по правилам он всегда входит в `clientHeight`.
**Если `padding` нет, то `clientWidth/Height` в точности равны размеру области содержимого, внутри рамок и полосы прокрутки.**
<img src="clientWidthNoPadding.png">
Поэтому в тех случаях, когда мы точно знаем, что `padding` нет, их используют для определения внутренних размеров элемента. И, в отличие от `getComputedStyle(elem).width`, эти свойства всегда работают верно.
## scrollWidth/Height
Эти свойства -- аналоги `clientWidth/clientHeight`, но с учетом прокрутки.
Свойства `clientWidth/clientHeight` относятся только к видимой области элемента, а `scrollWidth/scrollHeight` добавляют к ней прокрученную по горизонтали/вертикали.
На рисунке выше:
<ul>
<li>`scrollHeight = 723` -- полная высота, включая прокрученную область</li>
<li>`scrollWidth = 324` -- полная ширина, включая прокрученную область</li>
</ul>
<img src="scrollWidth.png">
Эти свойства можно использовать, чтобы "распахнуть" элемент на всю ширину/высоту:
```js
element.style.height = element.scrollHeight + 'px';
```
[online]
[pre no-typography]
Нажмите на кнопку, чтобы распахнуть элемент:
<div id="scrollOpen" style="width:300px;height:200px; padding: 0;overflow: auto; border:1px solid black;">текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст</div>
<button style="padding:0" onclick="document.getElementById('scrollOpen').style.height = document.getElementById('scrollOpen').scrollHeight + 'px'">element.style.height = element.scrollHeight + 'px'</button>
[/pre]
[/online]
## scrollLeft/scrollTop
Свойства `scrollLeft/scrollTop` -- ширина/высота невидимой, прокрученной в данный момент, части элемента слева и сверху.
Следующее иллюстрация показывает значения `scrollHeight` и `scrollTop` для блока с вертикальной прокруткой.
<img src="scrollTop.png">
[smart header="`scrollLeft/scrollTop` можно изменять"]
В отличие от большинства свойств, которые доступны только для чтения, значения `scrollLeft/scrollTop` можно изменить, и браузер выполнит прокрутку элемента.
[online]
При клике на следующий элемент будет выполняться код `elem.scrollTop += 10`. Поэтому он будет прокручиваться на `10px` вниз:
<div onclick="this.scrollTop+=10" style="cursor:pointer;border:1px solid black;width:100px;height:80px;overflow:auto">Кликни<br>Меня<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9</div>
[/online]
[/smart]
## Итого ## Итого
У элементов есть следующие метрики: У элементов есть следующие метрики:
@ -264,13 +277,7 @@ function isHidden(elem)
<li>`offsetLeft/offsetTop` -- позиция в пикселях левого верхнего угла блока, относительно его `offsetParent`.</li> <li>`offsetLeft/offsetTop` -- позиция в пикселях левого верхнего угла блока, относительно его `offsetParent`.</li>
</ul> </ul>
Все свойства, кроме `scrollLeft/scrollTop` доступны только для чтения. Изменение этих свойств заставляет браузер прокручивать элемент. Все свойства, доступны только для чтения, кроме `scrollLeft/scrollTop`. Изменение этих свойств заставляет браузер прокручивать элемент.
Краткая схема: В этой главе мы считали, что страница находится в режиме соответствия стандартам. В режиме совместимости -- некоторые старые браузеры требуют `document.body` вместо `documentElement`, в остальном всё так же. Конечно, по возможности, стоит использовать только режим соответствия стандарту.
<img src="summary.png">
**Прокрутку *элемента* можно прочитать или изменить через свойства `scrollLeft/Top`.**
В этой главе мы считали, что страница находится в режиме соответствия стандартам. В режиме совместимости -- всё так же, но некоторые старые браузеры требуют `document.body` вместо `documentElement`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View file

@ -1,4 +1,4 @@
# Получить прокрутки документа # TODO: перенеси меня в координаты? Тут координат еще не было
[importance 5] [importance 5]

View file

@ -1,7 +1,11 @@
# Размеры и прокрутка страницы # Размеры и прокрутка страницы
Многие метрики для страницы работают совсем не так, как для элементов. Поэтому рассмотрим решения типичных задач для страницы отдельно. Многие метрики для страницы работают совсем не так, как для элементов.
Поэтому мы рассмотрим решения типичных задач для страницы отдельно.
[cut] [cut]
## Ширина/высота видимой части окна ## Ширина/высота видимой части окна
Свойства `clientWidth/Height` для элемента `document.documentElement` позволяют получить ширину/высоту видимой области окна. Свойства `clientWidth/Height` для элемента `document.documentElement` позволяют получить ширину/высоту видимой области окна.
@ -12,49 +16,69 @@
Этот способ -- кросс-браузерный. Этот способ -- кросс-браузерный.
## Ширина/высота всей страницы, с учётом прокрутки [warn header="Не `window.innerWidth/Height`"]
Все браузеры, кроме IE8-, также поддерживают свойства `window.innerWidth/innerHeight`. Они хранят текущий размер окна.
Если прокрутка на странице присутствует, то полные размеры страницы можно взять в `document.documentElement.scrollWidth/scrollHeight`. Выглядят они короче, чем `document.documentElement.clientWidth`, однако есть один нюанс.
Свойства `clientWidth/Height` берут в расчёт полосу прокрутку, а эти свойства -- нет.
Если справа часть страницы занимает полоса прокрутки, то эти строки выведут разное:
```js
//+ run
alert( window.innerWidth ); // вся ширина окна
alert( document.documentElement.clientWidth ); // ширина минус прокрутка
```
Обычно нам нужна именно *доступная* ширина окна, например, чтобы нарисовать что-либо, то есть за вычетом полосы прокрутки. Поэтому используем `document.documentElement.clientWidth`.
[/warn]
## Ширина/высота страницы с учётом прокрутки
Если прокрутка на странице заведомо присутствует, то полные размеры страницы можно взять в `document.documentElement.scrollWidth/scrollHeight`.
Проблемы с этими свойствами возникают, когда *прокрутка то есть, то нет*. В этом случае они работают некорректно. Проблемы с этими свойствами возникают, когда *прокрутка то есть, то нет*. В этом случае они работают некорректно.
В браузерах Chrome/Safari и Opera при отсутствии прокрутки значение `document.documentElement.scrollHeight` в этом случае может быть даже меньше, чем `document.documentElement.clientHeight` (нонсенс!). Эта проблема -- именно для `document.documentElement`, то есть для всей страницы. С обычными элементами здесь всё в порядке. В браузерах Chrome/Safari и Opera при отсутствии прокрутки значение `document.documentElement.scrollHeight` в этом случае может быть даже меньше, чем `document.documentElement.clientHeight` (нонсенс!).
Надёжно определить размер с учетом прокрутки можно, взяв максимум из двух свойств: Эта проблема возникает именно для `document.documentElement`, то есть для всей страницы. С обычными элементами здесь всё в порядке.
Надёжно определить размер страницы с учетом прокрутки можно, взяв максимум из нескольких свойств:
```js ```js
//+ run //+ run
var scrollHeight = document.documentElement.scrollHeight; var scrollHeight = Math.max(
var clientHeight = document.documentElement.clientHeight; document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
*!* document.body.clientHeight, document.documentElement.clientHeight
scrollHeight = Math.max(scrollHeight, clientHeight); );
*/!*
alert('Высота с учетом прокрутки: ' + scrollHeight); alert('Высота с учетом прокрутки: ' + scrollHeight);
``` ```
## Прокрутка страницы [#page-scroll] Почему так? Лучше и не спрашивайте, это одно из редких мест, где просто обходятся ошибки в браузерах. Глубокой логики здесь нет.
### Получение текущей прокрутки ## Получение текущей прокрутки [#page-scroll]
Значение текущей прокрутки страницы хранится в свойствах `window.pageXOffset/pageYOffset`. Значение текущей прокрутки страницы хранится в свойствах `window.pageXOffset/pageYOffset`.
Но эти свойства: ```js
//+ run
alert('Текущая прокрутка сверху: ' + window.pageYOffset);
alert('Текущая прокрутка слева: ' + window.pageXOffset);
```
Эти свойства:
<ul> <ul>
<li>Не поддерживаются IE<9</li> <li>Не поддерживаются IE8-</li>
<li>Их можно только читать, а менять нельзя.</li> <li>Их можно только читать, а менять нельзя.</li>
</ul> </ul>
Поэтому для кросс-браузерности рассмотрим другой способ -- свойство `document.documentElement.scrollLeft/Top`. Если IE8- не волнует, то для чтения прокрутки лучше способа нет, рецепт готов.
<ul> Альтернативный вариант -- это свойства `document.documentElement.scrollLeft/Top`, но они не работают в Safari/Chrome/Opera, которые используют `document.body` (это неправильно).
<li>`document.documentElement` содержит значение прокрутки, если стоит правильный DOCTYPE. Это работает во всех браузерах, кроме Safari/Chrome.</li>
<li>Safari/Chrome используют вместо этого `document.body` (это баг в Webkit).</li>
<li>В режиме совместимости (если некорректный DOCTYPE) некоторые браузеры также используют `document.body`.</li>
</ul>
Таким образом, для IE8+ и других браузеров, работающих в режиме соответствия стандартам, получить значение прокрутки можно так: Так что кросс-браузерный вариант с учётом IE8:
```js ```js
//+ run //+ run
@ -63,73 +87,39 @@ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
alert("Текущая прокрутка: " + scrollTop); alert("Текущая прокрутка: " + scrollTop);
``` ```
### С учётом IE7- и Quirks Mode [#getPageScroll] ## Изменение прокрутки: scrollTo, scrollBy, scrollIntoView [#window-scroll]
Если дополнительно нужна поддержка IE<8, то там тоже есть важная тонкость. Документ может быть смещен относительно начальной позиции (0,0). Это смещение хранится в `document.documentElement.clientLeft/clientTop`, и мы должны вычесть его. [warn]
Если дополнительно добавить возможность работы браузера в Quirks Mode, то надёжный способ будет таким:
```js
//+ run
var html = document.documentElement;
var body = document.body;
var scrollTop = html.scrollTop || body && body.scrollTop || 0;
scrollTop -= html.clientTop;
alert("Текущая прокрутка: " + scrollTop);
```
Итого, можно создать кросс-браузерную функцию, которая возвращает значения прокрутки и поддерживает в том числе IE8-:
```js
var getPageScroll = (window.pageXOffset != undefined) ?
function() {
return {
left: pageXOffset,
top: pageYOffset
};
} :
function() {
var html = document.documentElement;
var body = document.body;
var top = html.scrollTop || body && body.scrollTop || 0;
top -= html.clientTop;
var left = html.scrollLeft || body && body.scrollLeft || 0;
left -= html.clientLeft;
return { top: top, left: left };
}
```
### Изменение прокрутки: scrollTo, scrollBy, scrollIntoView [#window-scroll]
[smart]
Чтобы прокрутить страницу при помощи JavaScript, её DOM должен быть полностью загружен. Чтобы прокрутить страницу при помощи JavaScript, её DOM должен быть полностью загружен.
[/smart] [/warn]
На обычных элементах свойства `scrollTop/scrollLeft` можно изменять, и при этом элемент будет прокручиваться. На обычных элементах свойства `scrollTop/scrollLeft` можно изменять, и при этом элемент будет прокручиваться.
Никто не мешает точно так же поступать и со страницей. Во всех браузерах, кроме Chrome/Safari можно осуществить прокрутку установкой `document.documentElement.scrollTop`, а в Chrome/Safari -- использовать для этого `document.body.scrollTop`. И будет работать. Никто не мешает точно так же поступать и со страницей. Во всех браузерах, кроме Chrome/Safari/Opera можно осуществить прокрутку установкой `document.documentElement.scrollTop`, а в указанных -- использовать для этого `document.body.scrollTop`. И будет работать.
Но есть и другое, полностью кросс-браузерное решение -- специальные методы прокрутки страницы [window.scrollBy(x,y)](https://developer.mozilla.org/en/Window.scrollBy) и [window.scrollTo(pageX,pageY)](https://developer.mozilla.org/en/Window.scrollTo).
Но есть и другое, полностью кросс-браузерное и универсальное решение -- специальные методы прокрутки страницы [window.scrollBy(x,y)](https://developer.mozilla.org/en/Window.scrollBy) и [window.scrollTo(pageX,pageY)](https://developer.mozilla.org/en/Window.scrollTo).
<ul> <ul>
<li>**Метод `scrollBy(x,y)` прокручивает страницу относительно текущих координат.** <li>Метод `scrollBy(x,y)` прокручивает страницу относительно текущих координат.
[online]
Например, кнопка ниже прокрутит страницу на `10px` вниз: Например, кнопка ниже прокрутит страницу на `10px` вниз:
<button onclick="window.scrollBy(0,10)">window.scrollBy(0,10)</button> <button onclick="window.scrollBy(0,10)">window.scrollBy(0,10)</button>
[/online]
</li> </li>
<li>**Метод `scrollTo(pageX,pageY)` прокручивает страницу к указанным координатам относительно документа.** Он эквивалентен установке свойств `scrollLeft/scrollTop`. <li>Метод `scrollTo(pageX,pageY)` прокручивает страницу к указанным координатам относительно документа.
Чтобы прокрутить в начало документа, достаточно указать координаты `(0,0)`: Он эквивалентен установке свойств `scrollLeft/scrollTop`.
Чтобы прокрутить в начало документа, достаточно указать координаты `(0,0)`.
[online]
<button onclick="window.scrollTo(0,0)">window.scrollTo(0,0)</button> <button onclick="window.scrollTo(0,0)">window.scrollTo(0,0)</button>
[/online]
</li> </li>
</ul> </ul>
## scrollIntoView
Для полноты картины рассмотрим также метод [elem.scrollIntoView(top)](https://developer.mozilla.org/en/DOM/element.scrollIntoView). Для полноты картины рассмотрим также метод [elem.scrollIntoView(top)](https://developer.mozilla.org/en/DOM/element.scrollIntoView).
Метод `elem.scrollIntoView(top)` вызывается на элементе и прокручивает страницу так, чтобы элемент оказался вверху, если параметр `top` равен `true`, и внизу, если `top` равен `false`. Причем, если параметр `top` не указан, то он считается равным `true`. Метод `elem.scrollIntoView(top)` вызывается на элементе и прокручивает страницу так, чтобы элемент оказался вверху, если параметр `top` равен `true`, и внизу, если `top` равен `false`. Причем, если параметр `top` не указан, то он считается равным `true`.
@ -170,12 +160,11 @@ var getPageScroll = (window.pageXOffset != undefined) ?
<li>Для получения размеров страницы с учётом прокрутки: <li>Для получения размеров страницы с учётом прокрутки:
```js ```js
var scrollHeight = document.documentElement.scrollHeight; var scrollHeight = Math.max(
var clientHeight = document.documentElement.clientHeight; document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
*!* document.body.clientHeight, document.documentElement.clientHeight
scrollHeight = Math.max(scrollHeight, clientHeight); );
*/!*
``` ```
</li> </li>
@ -184,9 +173,9 @@ scrollHeight = Math.max(scrollHeight, clientHeight);
**Прокрутка окна:** **Прокрутка окна:**
<ul> <ul>
<li>Прокрутку окна можно *получить* как `window.pageYOffset` (для горизонтальной -- `window.pageXOffset`) везде, кроме IE<9. <li>Прокрутку окна можно *получить* как `window.pageYOffset` (для горизонтальной -- `window.pageXOffset`) везде, кроме IE8-.
Для кросс-браузерности используется другой способ: На всякий случай -- вот самый кросс-браузерный способ, учитывающий IE7- в том числе:
```js ```js
//+ run //+ run
@ -194,7 +183,8 @@ var html = document.documentElement;
var body = document.body; var body = document.body;
var scrollTop = html.scrollTop || body && body.scrollTop || 0; var scrollTop = html.scrollTop || body && body.scrollTop || 0;
scrollTop -= html.clientTop; // IE<8 scrollTop -= html.clientTop; // в IE7- <html> смещён относительно (0,0)
alert("Текущая прокрутка: " + scrollTop); alert("Текущая прокрутка: " + scrollTop);
``` ```