en.javascript.info/8-css-for-js/5-position/article.md
2015-03-12 10:26:02 +03:00

374 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Свойство "position"
Свойство `position` позволяет сдвигать элемент со своего обычного места. Цель этой главы -- не только напомнить, как оно работает, но и разобрать ряд частых заблуждений и граблей.
[cut]
## position: static
*Статическое позиционирование* производится по умолчанию, в том случае, если свойство `position` не указано.
Его можно также явно указать через CSS-свойство:
```css
position: static;
```
Такая запись встречается редко и используется для переопределения других значений `position`.
Здесь и далее, для примеров мы будем использовать следующий документ:
```html
<!--+ autorun height=200 no-beautify -->
<div style="background: #fee; width: 500px">
Без позиционирования ("position: static").
<h2 style="background: #aef; margin: 0">Заголовок</h2>
<div>А тут - всякий разный текст... <br/>
... В две строки!</div>
</div>
```
В этом документе сейчас все элементы отпозиционированы статически, то есть никак.
[summary]
Элемент с `position: static` еще называют *не позиционированым*.
[/summary]
## position: relative
*Относительное позиционирование* сдвигает элемент относительно его обычного положения.
Для того, чтобы применить относительное позиционирование, необходимо указать элементу CSS-свойство `position: relative` и координаты `left/right/top/bottom`.
Этот стиль сдвинет элемент на 10 пикселей относительно обычной позиции по вертикали:
```css
position: relative;
top: 10px;
```
```html
<!--+ autorun height=200 no-beautify -->
*!*
<style>
h2 {
position: relative;
top: 10px;
}
</style>
*/!*
<div style="background: #fee; width: 500px">
Заголовок сдвинут на 10px вниз.
<h2 style="background: #aef; margin: 0;">Заголовок</h2>
<div>А тут - всякий разный текст... <br/>
... В две строки!</div>
</div>
```
### Координаты
Для сдвига можно использовать координаты:
<ul>
<li>`top` - сдвиг от "обычной" верхней границы</li>
<li>`bottom` - сдвиг от нижней границы</li>
<li>`left` - сдвиг слева</li>
<li>`right` - сдвиг справа</li>
</ul>
Не будут работать одновременно указанные `top` и `bottom`, `left` и `right`. Нужно использовать только одну границу из каждой пары.
**Возможны отрицательные координаты** и координаты, использующие другие единицы измерения. Например, `left: 10%` сдвинет элемент на 10% его ширины вправо, а `left: -10%` -- влево. При этом часть элемента может оказаться за границей окна:
```html
<!--+ autorun height=200 no-beautify -->
*!*
<style>
h2 {
position: relative;
left: -10%;
}
</style>
*/!*
<div style="background: #fee; width: 500px">
Заголовок сдвинут на 10% влево.
<h2 style="background: #aef; margin: 0;">Заголовок</h2>
<div>А тут - всякий разный текст... <br/>
... В две строки!</div>
</div>
```
**Свойства `left/top` не будут работать для `position:static`**. Если их все же поставить, браузер их проигнорирует. Эти свойства предназначены для работы только с позиционированными элементами.
## position: absolute
Синтаксис:
```css
position: absolute;
```
Абсолютное позиционирование делает две вещи:
<ol>
<li>**Элемент исчезает с того места, где он должен быть и позиционируется заново.** Остальные элементы, располагаются так, как будто этого элемента никогда не было.</li>
<li>**Координаты `top/bottom/left/right` для нового местоположения отсчитываются от ближайшего позиционированного родителя**, т.е. родителя с позиционированием, отличным от `static`. Если такого родителя нет -- то относительно документа.</li>
</ol>
Кроме того:
<ul>
<li>**Ширина элемента с `position: absolute` устанавливается по содержимому.** Детали алгоритма вычисления ширины [описаны в стандарте](http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width).</li>
<li>**Элемент получает `display:block`**, который перекрывает почти все возможные `display` (см. [Relationships between 'display', 'position', and 'float'](http://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo)).</li>
</ul>
Например, отпозиционируем заголовок в правом-верхнем углу документа:
```html
<!--+ autorun height=200 no-beautify -->
*!*
<style>
h2 {
position: absolute;
right: 0;
top: 0;
}
</style>
*/!*
<div style="background: #fee; width: 500px">
Заголовок в правом-верхнем углу документа.
<h2 style="background: #aef; margin: 0;">Заголовок</h2>
<div>А тут - всякий разный текст... <br/>
... В две строки!</div>
</div>
```
Важное отличие от `relative`: **так как элемент удаляется со своего обычного места, то элементы под ним сдвигаются, занимая освободившееся пространство**. Это видно в примере выше: строки идут одна за другой.
Так как при `position:absolute` размер блока устанавливается по содержимому, то
широкий `Заголовок` "съёжился" до прямоугольника в углу.
Иногда бывает нужно поменять элементу `position` на `absolute`, но так, чтобы элементы вокруг не сдвигались. Как правило это делают, меняя соседей -- добавляют `margin/padding` или вставляют в документ пустой элемент с такими же размерами.
[smart header="Одновременное указание `left/right`, `top/bottom`"]
**В абсолютно позиционированном элементе можно одновременно задавать противоположные границы.**
Браузер растянет такой элемент до границ.
```html
<!--+ autorun height=50 no-beautify -->
<style>
*!*
div {
position: absolute;
left: 10px; right: 10px; top: 10px; bottom: 10px;
}
*/!*
</style>
<div style="background:#aef;text-align:center">10px от границ</div>
```
[/smart]
[smart header="Внешним блоком является окно"]
Как растянуть абсолютно позиционированный блок на всю ширину документа?
Первое, что может прийти в голову:
```css
/*+ no-beautify */
div {
position: absolute;
left: 0; top: 0; /* в левый-верхний угол */
width: 100%; height: 100%; /* .. и растянуть */
}
```
Но это будет работать лишь до тех пор, пока у страницы не появится скроллинг!
Прокрутите вниз ифрейм:
[iframe src="position-100-wrong" height=200 link]
**Вы увидите, что голубой фон оканчивается задолго до конца документа.**
Дело в том, что в CSS `100%` относится к ширине внешнего блока ("containing block"). А какой внешний блок имеется в виду здесь, ведь элемент изъят со своего обычного места?
В данном случае им является так называемый (["\"initial containing block\""](http://www.w3.org/TR/CSS21/visudet.html#containing-block-details)), которым является окно, *а не документ*.
**То есть, координаты и ширины вычисляются относительно окна, а не документа.**
Может быть, получится так?
```css
/*+ no-beautify */
div {
position: absolute;
left: 0; top: 0; /* в левый-верхний угол, и растянуть.. */
right: 0; bottom: 0; /* ..указанием противоположных границ */
}
```
С виду логично, но нет, не получится!
Координаты `top/right/left/bottom` вычисляются относительно *окна*. Значение `bottom: 0` -- нижняя граница окна, а не документа, блок растянется до неё. То есть, будет то же самое, что и в предыдущем примере.
[/smart]
## position: absolute в позиционированном родителе
Если у элемента есть позиционированный предок, то `position: absolute` работает относительно него, а не относительно документа.
То есть, достаточно поставить родительскому `div` позицию `relative`, даже без координат -- и заголовок будет в его правом-верхнем углу, вот так:
```html
<!--+ autorun height=200 -->
*!*
<style>
h2 {
position: absolute;
right: 0;
top: 0;
}
</style>
*/!*
<div style="background: #fee; width: 500px; *!*position: relative*/!*">
Заголовок в правом-верхнем углу DIV'а.
<h2 style="background: #aef; margin: 0;">Заголовок</h2>
<div>А тут - всякий разный текст... <br/>
... В две строки!</div>
</div>
```
Нужно пользоваться таким позиционированием с осторожностью, т.к оно может перекрыть текст. Этим оно отличается от `float`.
Сравните:
<ul>
<li>Используем `position` для размещения элемента управления:
```html
<!--+ autorun height=80 no-beautify -->
<button style="position: absolute; right: 10px; opacity: 0.8">
Кнопка
</button>
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
```
**Часть текста перекрывается.** Кнопка более не участвует в потоке.
</li>
<li>Используем `float` для размещения элемента управления:
```html
<!--+ autorun height=80 no-beautify -->
<button style="float: right; margin-right: 10px; opacity: 0.8;">
Кнопка
</button>
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
```
**Браузер освобождает место справа, текст перенесён.** Кнопка продолжает находиться в потоке, просто сдвинута.
</li>
</ul>
## position: fixed
Это подвид абсолютного позиционирования.
Синтаксис:
```css
position: fixed;
```
Позиционирует объект точно так же, как `absolute`, но относительно `window`.
Разница в нескольких словах:
**Когда страницу прокручивают, фиксированный элемент остается на своем месте и не прокручивается вместе со страницей.**
В следующем примере, при прокрутке документа, ссылка `#top` всегда остается на своем месте.
```html
<!--+ autorun untrusted height=200 -->
<style>
*!*
#top {
position: fixed;
right: 10px;
top: 10px;
background: #fee;
}
*/!*
</style>
*!*<a href="#" id="top">Наверх (остается при прокрутке)</a>*/!*
Фиксированное позиционирование.
<p>Текст страницы.. Прокрути меня...</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>
<p>Много строк..</p><p>Много строк..</p>
```
## Итого
Виды позиционирования и их особенности.
<dl>
<dt>`static`</dt>
<dd>Иначе называется "без позиционирования". В явном виде задаётся только если надо переопределить другое правило CSS.</dd>
<dt>`relative`</dt>
<dd>Сдвигает элемент относительно текущего места.
<ul>
<li>Противоположные границы `left/right` (`top/bottom`) одновременно указать нельзя.</li>
<li>Окружающие элементы ведут себя так, как будто элемент не сдвигался.</li>
</ul>
</dd>
<dt>`absolute`</dt>
<dd>Визуально переносит элемент на новое место.
Новое место вычисляется по координатам `left/top/right/bottom` относительно ближайшего позиционированного родителя. Если такого родителя нет, то им считается окно.
<ul>
<li>Ширина элемента по умолчанию устанавливается по содержимому.</li>
<li>Можно указать противположные границы `left/right` (`top/bottom`). Элемент растянется.</li>
<li>Окружающие элементы заполняют освободившееся место.</li>
</ul>
</li>
</dd>
<dt>`fixed`</dt>
<dd>Подвид абсолютного позиционирования, при котором элемент привязывается к координатам окна, а не документа.
При прокрутке он остаётся на том же месте.</dd>
</dl>
## Почитать
CSS-позиционирование по-настоящему глубоко в спецификации <a href="http://www.w3.org/TR/CSS2/visuren.html#positioning-scheme">Visual Formatting Model, 9.3 и ниже</a>.
Еще есть хорошее руководство <a href="http://www.barelyfitz.com/screencast/html-training/css/positioning/">CSS Positioning in 10 steps</a>, которое охватывает основные типы позиционирования.