Позиционирование: всему свое место - Вёрстка - Webmascon

| WEBMASCON - журнал для веб-мастеров обновление |06.11.2003

| Вёрстка

Начало
Темы
Архив
Daily
Персоналии
Форумы
Отзывы
О сайте

все статьи на тему Вёрстка

# Позиционирование: всему свое место

© Copyright 2003 Михаил Дубаков Глава 9 из книги 'Создание веб-сайтов: искусство верстки' © перевод, n|a распечатать

1. Часть 1. Позиционирование с помощью таблиц.
2. Часть 2. Позиционирование с помощью CSS.

### Мнимый монументализм абсолютного позиционирования

Очевидным недостатком HTML является отсутствие возможности однозначно и просто позиционировать блок там, где хочется. Например, я хочу, чтобы блок был смещен на 250 пикселей от верхнего края, и на 45 от левого. Конечно, в HTML можно реализовать такое положение блока с помощью таблиц и распорок, но хочется простоты. В CSS такая возможность обеспечивается свойством `position`, самое популярное значение у которого `absolute`. Для задания смещения существуют свойства `top` и `left`. Мое желание с помощью каскадных таблиц стилей реализуется вот так:

`#block {position: absolute; top: 250px; left: 45px}`

А в коде документа очень простой блок:

`<div id="block">
содержание блока
</div>
`

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

`<table cellpadding="0" cellspacing="0">
<tr>
<td width="45"></td>
<td>
<img src="i/0.gif" width="1" height="250"><br>
<div>
содержание блока
</div>
</td>
</tr>
</table>
`

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

Итак, у нас есть три волшебных свойства, которые позволяют точно позиционировать блоки. Возникает вопрос, относительно чего задается смещение? Варианта два: либо относительно окна браузера, либо относительно другого позиционированного блока. Если один блок вложен в другой, и оба из них имеют объявление `position: absolute`, то смещение второго блока будет осуществляться относительно первого. Давайте лучше на примере, а то слишком сложно звучит. Допустим, имеются два блока:

`<div id="left-col">
<div id="news">
</div>
</div>
`

Стили на блоки следующие:

`#left-col {position: absolute; top: 20px; left: 10px}
#news {position: absolute; top: 20px; left: 10px}`

Давайте посмотрим, какими будут абсолютные значения отступов относительно окна браузера. Первый блок будет на 20 пикселей отбит от верхнего края и на 10 от левого. Второй блок будет отбит на 40 пикселей от верхнего края и на 20 от левого. То есть он смещается на указанные значения не от самого окна браузера, а относительно первого блока. А если бы блоки не были вложенными:

`<div id="left-col">
</div>
<div id="news">
</div>
`

То они накладывались бы друг на друга. Надеюсь, сейчас все стало понятно.

У нас есть инструмент, который, по идее, может отлично заменять табличную верстку. Правда, почему бы и нет? Ведь он позволяет с точностью до пикселя позиционировать блоки, не используя распорки. Давайте проверим возможности абсолютного позиционирования на нашем примере. Сейчас мы попытаемся сверстать страницу на основе CSS-блоков и CSS-позиционирования.

Вернитесь к началу главы и посмотрите на рис. 9.1, если еще не запомнили всех деталей. Как ни крути, получается три отдельных главных блока: шапка, основной с тремя колонками и копирайт. Мы уже верстали каждый из этих блоков с помощью таблиц, а сейчас попробуем CSS. Замечу, что сразу я буду создавать блоки согласно спецификации, то есть для браузеров Mozilla и Opera. Адаптацией кода под Internet Explorer займемся немного позже.

Как и при табличной верстке, верхний большой блок лучше разбить на два маленьких. Первый блок назовем top-left, а второй – top-right. Первый блок содержит логотип, а второй оранжевую плашку и слово «новости». Начнем с верхнего левого блока:

`<div id="top-left">
<img src="i/logo.gif" border="0" alt="">
</div>
`

Обратите внимание, что для картинки я уже не указываю атрибуты `width` и `height`, потому что нет таблиц. Уже нет необходимости указывать размеры картинок для того, чтобы таблицы быстрее обрабатывались браузером.

Осталось написать стили для блока. Мы знаем, что ширина блока 517 пикселей, а высота равна высоте логотипа, то есть 74 пикселя. Пишем:

`#top-left {width: 517px; height: 74px}`

Этот первый блок даже не надо позиционировать. Действительно, все равно смещения слева и сверху равны нулю. Затем надо сделать черную линию, которая пересекает весь наш блок. Когда мы верстали таблицами, то делали линию с помощью фонового рисунка, высотой 50 пикселей. Он дублировался в ячейке таблицы и таким образом создавалась линия. В CSS есть возможность размножать фоновый рисунок вдоль необходимой оси. Более того, есть возможность точно позиционировать фон, то есть смещать рисунок на необходимое количество пикселей от верхнего края блока. Все это позволяет нам в качестве фонового рисунка взять всего одну черную точку размеров 11 пиксель! Мы смещаем фон на 49 пикселей относительно верхнего края блока:

`#top-left {
background: url(i/bd.gif) repeat-x 0px 49px;
width: 517px; height: 74px}
`

С фоном все в порядке, но логотип надо отбить на 30 пикселей. Раньше мы делали это с помощью атрибута `hspace` тега `<img>`, но теперь для блока top-left можно просто задать левый отступ необходимой ширины:

`#top-left {
background: url(i/bd.gif) repeat-x 0px 49px;
width: 517px; height: 74px;
padding-left: 30px}
`

Но я забыл, что отступы влияют на суммарную ширину блока. То есть мне сейчас надо отнять от значения свойства width ровно 30 пикселей:

`#top-left {
background: url(i/bd.gif) repeat-x 0px 49px;
width: 487px; height: 74px;
padding-left: 30px}
`

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

Создаем правый блок:

`<div id="top-right">
</div>`

Мы знаем, что его ширина 233 пикселя, а высота 32 пикселя. Вот сейчас нам понадобится и позиционирование. Раз ширина первого блока 517 пикселей, то второй блок надо сдвинуть влево ровно настолько же.

`#top-right {
width: 233px; height: 32px;
position: absolute; left: 517px}`

Пока я точно не знаю, какое требуется вертикальное смещение. Поэтому я пока откладываю сам блок и перехожу к его содержимому. Плашку я сделаю на чистом CSS без всяких картинок. Ну, а «новости» придется вставить картинкой. HTML-код будет следующий:

`<div id="top-right">
<div class="rectangle"></div>
<img src="i/news.gif" border="0" alt="">
</div>
`

Теперь надо написать стили на класс rectangle (так я назвал плашку). Ширина плашки ровно 233 пикселя, а общая высота 19. Но я знаю, что блок должен иметь рамку толщиной 1 пиксель, значит значения свойств `height` и `width` надо указывать на 2 пикселя меньше (чтобы компенсировать ширину рамки). Получается вот так:

`.rectangle {
width: 231px; height: 17px;
border: 1px solid #000}
`

После этого остается только задать оранжевый фон:

`.rectangle {
background: #F90;
width: 231px; height: 17px;
border: 1px solid #000}
`

Текущий результат показан на рис. 9.4. Для наглядности блока выделены пунктирной линией:

Рис. 9.4 Нестыковка верхних блоков

Как видите, по умолчанию второй блок позиционируется точно под первым. Мы явно для блока top-right не задали смещение относительно верхнего края, а кроме численных значений свойства `top` и `left` могут принимать значение `auto`. Чтобы лучше разобраться, как оно действует на блок, надо немного углубиться в теорию.

#### Лирическое отступление о нормальном потоке

Начнем с того, что существует понятие нормального потока. Нормальный поток – это способ форматирования блоков браузером по умолчанию, то есть когда нет никаких других схем позиционирования. Табличная верстка относится к нормальному потоку, тогда как CSS-позиционирование — нет.

При форматировании блоков в нормальном потоке браузер руководствуется всего двумя правилами: каждый блоковый элемент начинается с новой строки, каждый строчный элемент переносится на новую строку по мере необходимости. К блоковым элементам относятся `<p>, <table>, <h1>` и т.п. К строчным элементам — `<b>, <i>, <sup>` и т.п. Специально для каскадных таблиц стилей создали два элемента:

- <div> – общий блоковый элемент
- <span> – общий строчный элемент

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

`<div id="news"></div>`

А блок для выделения даты вот так:

`<span class="date"></span>`

Нормальный поток очень простой для понимания. Если вы в коде напишите последовательно два блоковых элемента, то на странице они расположатся ровно друг под другом. Если вы напишите два сроковых элемента, то они расположатся в одну строку.

В нашем случае мы имеем два блока, которые в коде следуют друг за другом. Если бы все происходило в рамках нормального потока (то есть не было указано `position: absolute`), то картина была бы такой, как показано на рис. 9.5

Рис. 9.5 Блоки в нормальном потоке

Больше говорить о нормальном потоке нет смысла, так что вернемся к абсолютному позиционированию.

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

`#block2 {position: absolute; left: 0px; top: 0px}`

то в результате второй блок будет наложен на первый. Мы вплотную подобрались к ответу на вопрос, почему в нашем примере второй блок хоть и смещен влево как надо, но по вертикали все равно находится под первым блоком. Дело в том, что значение auto позиционирует блок так, как будто он находится в нормальном потоке. То есть получается, что мы задали смещение слева 517 пикселей, и блок действительно сместился, но смещение сверху мы не задали вообще, а по умолчанию используется `top: auto`. Если мы хотим, чтобы второй блок имел точный отступ сверху, то надо его задать. Методом подбора можно определить, что для правильной стыковки блоков верхнее смещение должно быть 49 пикселей:

`#top-right {
width: 233px; height: 32px;
position: absolute; left: 517px; top: 49px}`

В итоге блоки будут стыковаться совершенно правильно, что и видно на рис. 9.6

Рис. 9.6 Правильная стыковка двух блоков шапки

Подведем промежуточный итог. Если при верстке таблицами мы использовали 5 картинок, то сейчас всего три. Кроме того, одна картинка ну совсем легкая, ведь это одно-пиксельный gif. Сам HTML-код шапки стал более простым:

`<div id="top-left">
<img src="i/logo.gif" width="272" height="74" border="0" alt="">
</div>
<div id="top-right">
<div class="rectangle"></div>
<img src="i/news.gif" width="59" height="9" border="0" alt="">
</div>
`

Если выражать в цифрах, то было 392 байта, стало 206 байт. Но зато появился дополнительный CSS-код объемом 265 байт. Так что если брать вес чистого кода документа, то он увеличился. Но вес картинок был 2,88 Кб, а стал 2,77 Кб. Если все просуммировать, то было 3341 байт, стало — 3307 байт. Конечно, экономия просто смехотворная, но пока на этом не будем заострять внимания. Из положительных моментов можно отметить уменьшение количества используемых картинок, что всегда хорошо, и увеличение логичности кода.

Давайте перейдем к основному блоку. Раз уж мы можем точно задавать месторасположение блоков, то имеет смысл сделать три блока, которые следуют в документе друг за другом:

`<div id="main-left">
</div>
<div id="main">
</div>
<div id="main-right">
</div>
`

Из названия блоков понятно, какой за что отвечает. Код внутри блоков практически не будет отличаться от того, что мы писали при верстке таблицами, за исключением шрифта. Давайте займемся стилями. Ширина левого блока 125 пикселей, высота 80 пикселей. Смещение слева 3 пикселя, а сверху — 96 пикселей. Получается такие стили:

`#main-left {
width: 125x; height: 80px;
position: absolute; left: 3px; top: 96px}
`

С центральным блоком несколько интереснее. Его ширина 364 пикселя, а высота в принципе может изменяться, если будет больше текста. Поэтому высоту пока не будем задавать и посмотрим, что из этого получится. Смещение слева равен ширине левого блока и еще 15 пикселей, то есть получается 140 пикселей. А смещение сверху такое же:

`#main {
width: 364px;
position: absolute; left: 140px; top: 96px}
`

С правым блоком все практически так же. Мы знаем размеры и вычисляем смещения. Единственная разница в шрифте. Текст новостей выводится мелким шрифтом, так что надо его задать:

`#main-right {
font: 10px Verdana;
width: 233px;
position: absolute; left: 517px; top: 96px}
`

Как видите, нет совершенно ничего сложного в абсолютном позиционировании блоков. Знай себе вычисляй смещения и пиши совершенно однотипные стили. Промежуточный результат нашего титанического труда показан ни рис. 9.7

Рис. 9.7 Промежуточный вид блоков

Осталось реализовать только блоки с копирайтом. Вот здесь во всей красе и проявит себя проблема с высотой CSS-блоков. Мы заранее не знаем высоту центрального или левого блока. Конечно, мы ее знаем для нашего макета, но на сайте может быть сколько угодно новостей. Что если администратор сайта решить вывести не две, а четыре новости? Или в первой новости поместит 146 слов вместо 10? Получается, что высота блоков совершенно неопределенная, так что ее нельзя задать жестко. Но это еще полбеды. Главный вопрос, насколько нам необходимо сместить блок копирайта, чтобы на странице все было нормально?

Здесь вырисовывается концептуальное преимущество нормального потока. В нем элементы идут строго друг за другом и совершенно не надо заботиться о всяких смещениях. Когда мы верстали с помощью таблиц, то просто поместили таблицу с копирайтом после всех остальных блоков. Браузер всегда будет ее выводить последней, увеличивая высоту центральной таблицы насколько необходимо.

Сейчас мы не может использовать преимущества нормального потока, потому что при абсолютном позиционировании блоки полностью из него вырываются. Если мы решим оставить последний блок в нормальном потоке, то он будет отображаться в самом верху, словно больше на странице нет никаких блоков. С другой стороны, мы не можем задать ему какое-либо точное смещение, потому что не знаем высоты центральных блоков. Как решить проблему?

Единственный корректный вариант решения: динамически изменять смещение в зависимости от максимальной высоты центральных блоков. Для этого необходимо знать JavaScript и DOM. Честно говоря, я не люблю такие обходные решения, но в данном случае больше никакого реального варианта нет. Давайте это подтвердим, попробовав некоторые теоретически возможные способы.

Можно заключить центральные блоки и копирайт в один общий блок. Кажется, что в таком случае получится расположить копирайт непосредственно под центральным блоком. Уверенность связана со свойством bottom. Данное свойство задает смещение относительного нижнего края контейнера, то есть в нашем случае если задать смещение 0 относительно нижнего края общего блока, все должно получиться. Структура кода будет такая:

`<div id="general">
<!-- Три центральных блока -->
<div id="main-left"></div>
<div id="main"></div>
<div id="main-right"></div>
<!-- Блок с копирайтом -->
<div id="bottom-left"></div>
</div>
`

Стили для двух новых блоков будут вот такими:

`#general {
width: 760px;
top: 96px; position: absolute}
#bottom-left {
width: 233px; height: 40px;
position: absolute; left: 0px; bottom: 0px}
`

Кажется, что высота общего блока должна автоматически подстраиваться под высоту самого высокого блоки из трех вложенных. Но этого не происходит по той причине, что блоки находится вне нормального потока. Получается, что высоту общего блока надо задавать жестко, так что мы вернулись к общей проблеме. Если высоту задать жестко, то возможны случаи, когда содержимое блоков превышает заданную высоту и будет накладываться на блок bottom-left. На рис. 9.8 как раз показан случай, когда содержимое превышает заданную высоту блока.

Рис. 9.8 Наложение блока main на блок bottom-right

Для наглядности блок general выделен серым фоном, и все блоки взяты в пунктирные рамки.

Если попытаться вынести блок с копирайтом из блока general и в стилях тоже указать `bottom: 0px` (смещение относительно нижнего края окна браузера будет нулевым), то все равно проблема с высотой не решится, потому что содержимое блока может превышать высоту всего окна браузера, и это не редкость.

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

Если все обобщить, то получается, что на основе абсолютного позиционирования можно легко верстать сайты, у которых нет такого нижнего блока. Сразу скажу, что такое бывает нечасто, но все же бывает.

Фактически, проблема заключается в привязке одного блока к другому. То есть если бы мы могли при абсолютном позиционировании сказать блоку bottom-right, что он всегда должен располагаться под блоком general, проблему удалось бы снять. Я не знаю, что помешало разработчикам стандарта CSS реализовать какое-нибудь специальное свойство, которое позволяло бы это делать. Например, можно было бы сделать для свойства `position` функцию `after`, в которую передавать id блока. Тогда проблема с позиционированием блока bottom-left решалась элементарно:

`#bottom-left {
width: 233px; height: 40px;
position: after(#general); left: 0px}
`

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

Возможно, в каскадных таблицах стилей есть другой вид позиционирования, который позволяет решить проблему с нижним блоком? Действительно, вид позиционирования имеется, но насколько он решает проблему, надо еще посмотреть. В следующей части будет рассмотрена плавающая модель.

1. Часть 1. Позиционирование с помощью таблиц.
2. Часть 2. Позиционирование с помощью CSS.

Михаил Дубаков

Обсудить (45)

Ссылки по теме
Глава 7. Блоки в документах | рус. назад к списку статей

Рекомендую

Михаил Дубаков
Веб-мастеринг средствами CSS
на http://www.ozon.ru/?context=detail&id=1099692&partner=webmascon
на http://www.books.ru/shop/books/27425?partner=webmascon
Почитайте Главу 5
Отзывы о книге

Начало | Темы | Архив | Daily | Персоналии | Форумы | Отзывы | О сайте

|  | Автор и администратор ресурса - Александр Качанов Webmascon Project открыт в 1999 году
© 1999-2002, переводы, Александр Качанов © 1999-2002, Webmascon © дизайн | matepuana.com |  |