Разметка, основанная на абсолютном позиционировании
Rob Swan, 22 июля 2007
За этот месяц мне пришлось два раза столкнуться с необходимостью создания разметки с фиксированной боковой панелью со скроллингом и такой же главной панелью на всю оставшуюся ширину страницы.
Как истинный приверженец CSS я обычно пытаюсь избегать динамических разметок, и, конечно, я не приверженец использования Java Script в разметке, но иногда без них не обойтись.
Проще всего создавать такие разметки с помощью специальных JavaScript инструментов, например, DOJO, но результаты его применения мне показались слишком объемными, и в будущем могли привести к дополнительным трудностям.
Конечно, мы можем получить такую разметку с помощью JavaScript, позиционируя div`ы каждый раз при загрузке и изменении размеров страницы. Но в этом случае тоже не обойдется без головной боли, нужно будет сделать выбор между window.innerHeight, document.documentElement.clientHeight, document.body.clientHeight, и использовать кросс-браузерные обработчики событий.
Мне кажется использование JavaScript для создания необходимой нам разметки это возможное, но не самое элегантное решение, поэтому я хочу получить легкое и простое решение на чистом CSS.
Проблема с процентами
Часто мы используем элементы с динамическими размерами, задавая высоту или ширину в процентах, но с процентами есть одна проблема, их трудно сочетать с другими единицами.
Создав даже относительно неплохую разметку используя проценты, нам будет трудно добавить боковую панель фиксированной ширины, или заголовок фиксированной высоты. Поэтому мы не будем использовать проценты в этой разметке.
Природа div`ов
Я обратился к основам блочной модели, чтобы найти подходящее решение вот, что можно утверждать о div`ах:
Во всех браузерах
divэто прямоугольник.- Только один угол
divможет абсолютно позиционироваться на странице. - Положение диагонально противоположного угла должно определяться высотой и шириной элемента.
- Если высота и ширина динамические, они должны определятся с помощью JavaScript.
Мне показалось, что утверждение «Только один угол div может абсолютно позиционироваться на странице» очень легко подтвердить или опровергнуть, для этого я задал значения для top, left, bottom, right и, несмотря на мои опасения, получил совершенно валидный CSS.
«Конфликтное» абсолютное позиционирование
Я опасался, что если задать top, left, bottom и right то большинство браузеров будут игнорировать два из этих свойств.
Но мои опасения не подтвердились, во всех браузерах, в которых было протестировано это решение за исключением IE5 и IE6, отлично работали все четыре правила, а div растягивался на всю величину окна.

После недолгих поисков выяснилось, что я не первый обнаружил такую возможность.
«В браузерах поддерживающих CSS можно задать все четыре координаты, а ширина и высота будут вычислены автоматически. К несчастью, это не работает в IE», — Autistic Cuckoo
«Технически вы можете задать координаты
rightиleft, а ширина будет вычислена браузером, но IE не поддерживает такую возможность», — css-discuss
В действительности эта возможность CSS была незаслуженно забыта, из-за отсутствия поддержки в IE<5 и IE6, приятно видеть, что в IE7 проблема решена.
Между тем, несовместимость не уменьшает полезности этого решения. Определенная нами в начале статьи природа div остается верной для IE5 и IE6, но для других браузеров в нее нужно внести коррективы.
Во всех браузерах кроме IE
- Div это прямоугольник.
- Все четыре угла div могут абсолютно позиционироваться на странице.
- Если задано положение диагонально противоположных углов, то высота и ширина вычисляются автоматически.
Альтернативное решение для IE
То, что в IE5 и IE6 позиционироваться может только один из углов div, создает нам серьезные проблемы, но Microsoft предлагает нам их решение, это динамические свойства.
Динамические свойства чрезвычайно мощный инструмент, но они поддерживаются только IE, что не позволяет использовать их достаточно широко.
В нашем случае этого достаточно, с их помощью мы можем указать IE, что ширина div равна ширине страницы минус 40px.
В соответствии с этим решением нужно еще раз пересмотреть наши предположения относительно природы div в различных браузерах.
В IE5 и IE6
divэто прямоугольник.- Только один угол
divможет абсолютно позиционироваться на странице. - Положение диагонально противоположного угла должно определяться высотой и шириной элемента.
- Ширина и высота элемента могут быть определены с помощью динамических свойств.
Во всех остальных браузерах
divэто прямоугольник.- Все четыре угла
divмогут абсолютно позиционироваться на странице. - Если задано положение диагонально противоположных углов, то высота и ширина вычисляются автоматически.
Теперь все наши предположения соответствуют действительности и можно приступить к созданию разметки используя чистый (почти) CSS.
Собираем все вместе
Необходимая нам HTML разметка предельно проста:
<body>
<div id="header">
<p>Our header</p>
</div>
<div id="side">
<p>Our side panel</p>
</div>
<div id="right">
<p>Our main panel</p>
</div>
</body>
В современных браузерах
Стили, которые мы будет использовать для большинства современных браузеров, достаточно просты.
- Высоту и ширину элемента
bodyустановим в 100% (Это нужно, чтобы работало наше решение для IE, но от того, что мы установим их в основном файле стилей вреда не будет). - Установим
overflow: hiddenдляbodyиhtmlчтобы убрать скролл бары. - Установим
overflow:autoдля левой и правой панелей иoverflow: hiddenдля заголовка. - Заголовку зададим ширину 100% и фиксированную высоту 80px.
- Для боковой панели установим координаты
top(высота заголовка + отступ),left(отступ слева) иbottom(отступ снизу), и фиксированную ширину 200px. - Для правой панели установим
top(высота заголовка + отступ),left(отступ + ширина боковой панели с отступом),right(отступ) иbottom(отступ)
Все это очень просто перевести в CSS:
<style type=”text/css”>
html {
overflow: hidden;
}
body {
overflow: hidden;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
#header {
padding: 0;
margin: 0;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 80px;
overflow: hidden;
}
#side {
padding: 0;
margin: 0;
position: absolute;
top: 100px;
left: 20px;
bottom: 20px;
overflow: auto;
width: 200px;
}
#main {
padding: 0;
margin: 0;
position: absolute;
top: 100px;
left: 240px;
right: 20px;
bottom: 20px;
overflow: auto;
}
</style>
Создаем заплатку для IE5 и IE6
В IE5 и IE6 свойства bottom и right для главной и боковой панелей игнорируются, при этом левый верхний угол остается в заданной позиции и все, что нам нужно сделать это задать ширину и высоту панелей.
Высота панелей одинакова и равна, высоте страницы минус высоту заголовка и отступы (100%-80px-20px-20px).
Ширина главной панели равна, ширине страницы минус ширину боковой панели и отступы (100%-200px-20px-20px-20px). Боковая панель имеет фиксированную ширину, которая уже задана в основном файле стилей.
С помощью условных комментариев добавим стили доступные только для IE5 и IE6:
<!--[if lt IE 7]>
<style type="text/css">
#side {
height:expression(document.body.clientHeight-120);
/* 80+20+20=120 */
}
#main {
height:expression(document.body.clientHeight-120);
/* 80+20+20=120 */
width:expression(document.body.clientWidth-260);
/* 200+20+20+20=260 */
}
</style>
<![endif]-->
Не забывайте о том, что для того чтобы это работало, мы установили ширину и высоту body равной 100% в главном файле стилей.
Заключение
Теперь у нас есть законченное решение.
Конечно, динамические выражения не проходят валидацию, но они скрыты от большинства браузеров, и хотя они задаются в CSS на самом деле это JavaScript, а значит, не работают, если JavaScript отключен (но эта проблема есть у всех альтернативных решений).
Известные проблемы
Есть маленький, но неприятный баг в Opera 8, там боковая панель корректно отображается при загрузке страницы, но не меняет размер при изменении размеров окна. Учитывая то, что баг исправлен в Opera 9, это не большая проблема.

















Денис Талала 22 июля, 2007 16:21 #
Интересная и полезная статья. Давно столкнулся с этой проблемой, и вот — решение. :)
Денис Талала 22 июля, 2007 18:40 #
Покопался в шаблоне. Мне кажется, что с помощью
tableиtdвсе это можно сделать гораздо проще…gordi 22 июля, 2007 19:58 #
А если поискать?
Два скролл бара вместо одного? Это круто ;)
POSITION: fixed; За и против.
Денис Талала 22 июля, 2007 20:04 #
Мне это показалось неудобным.
gordi 22 июля, 2007 20:14 #
А, что неудобного?
Как минимум лет пять назад это бы прокатило.
Но сегодня рекомендовать подобное не имеет смысла.
Денис Талала 22 июля, 2007 20:16 #
Сами ответили на свой вопрос. :)
gordi 22 июля, 2007 20:21 #
>Но сегодня рекомендовать подобное не имеет смысла.
Имеет отношение к публикации, что расположена чуть выше ;)
Sam 23 июля, 2007 12:40 #
Спасибо
Прочитал в оригинале, но перевода ждал...
zlodie 23 июля, 2007 14:43 #
спасибо.
пригодилось. дело не в двух скроллбарах, а в возможности растянуть контейнер от заданного места и до конца экрана.
Tokolist 23 июля, 2007 22:15 #
Уже все давно решено без expression ;)
http://forum.htmlbook.ru/viewtopic.php?pid=22338#p22338
ЗЫ только обратите внимание на комментарий в ЦСС и хорошо разберитесь в примере на цссплей
ЗЫ ЗЫ чем плох экспрешин думаю все знают... если нет - назову как минимум три причины
Евгений 25 июля, 2007 16:07 #
Tokolist
Конечно, использование JavaScript в разметке это не нормально, но и quirks mode, в котором работает предложенный на CSSPlay пример, тоже не самое элегантное решение, для меня он вообще неприемлем.
Если не сложно хотелось бы услышать, ваши доводы против expression, хотя я сам никогда не стал бы их использовать, самым серьезным недостатком мне кажется то, что JavaScript может быть отключен.
PS Очень неплохим решением этой проблемы было бы надрать задницу разработчикам IE.
Tokolist 26 июля, 2007 23:09 #
> но и quirks mode, в котором работает предложенный на CSSPlay пример, тоже не самое элегантное решение, для меня он вообще неприемлем.
Надеюсь что то что я напишу ниже не превратится в очередной спор :)
В общем, гипотетически людей которые занимаются версткой можно разбить на три категории (ИМХО):
1. люди которые строго следую стандартам и не изменяют этому принципу ни при каких обстоятельствах (даже если заказчик предлагает им хорошие деньги :) )
2. люди которые плюют на стандарты с высокой башни :)
3. люди которые следуют стандартам, но если есть необходимость, то можно слегка плевнуть :) - ведь главное отображение в браузерах, обычный пользователь ведь глубоко плевал на код - он видит "внешнюю" часть страницы.
Так вот, я отношусь к третей категории людей. Поэтому для меня такой вариант приемлем, если другого нет, а надо что-то делать :)
> Если не сложно хотелось бы услышать, ваши доводы против expression
1. скрипты должны быть включены (что и так ясно)
2. это не по стандартам (и то что вы будете использовать CC не значит, что вы верстаете правильно). хотя для данного конкретного случая это не существенно :)
3. говорят, что они замедляют рендеринг страницы, хотя на практике сильного замедления не наблюдал.
Что использовать в данном случае рекомендовать не стану. Скажу только, что я бы или убедил заказчика отказаться от такого или бы использовал вариант без экспрешинов.
Alex 1 августа, 2007 10:56 #
Используя CSS можно сделать значительно более простое решение. Оно основано на использовании свойств display, margin, padding и float.
index.htm
styles.css
удаление отступов у всех элементов, это дело вкуса :) редко так делаю, здесь это лишь для упрощения примера.
gordi 1 августа, 2007 17:19 #
А вы уверены, что предложенное вами работает ;)
Alex 1 августа, 2007 21:21 #
to gordi
как я понял основной вопрос был в размещении бокового блока фиксированной ширины, и растягивающегося блока на всю оставшуюся ширину страницы. приведенный пример полностью решает эту проблемму.
gordi 1 августа, 2007 21:41 #
Вы посмотрите свой код в сборе.
Или я чего-то не понимаю?
Alex 2 августа, 2007 10:08 #
посмотрел, все нормально. если не считать небольшого глюка при вставки кода в текстовый редактор, когда все / заменились на ?. после проведения обратной замены, и приведения таким образом кода в правильный вид, все работает так как нужно. Если всеравно не ясно, пишите в почту superalexey [ухо:)] rambler тчк ru
Роман 13 августа, 2007 11:06 #
Спасибо, удалось решить такую проблему.
нужно было div растянуть на 100%, но он слева отступать должен на 200px.
IE сначало растягивал его на 100% я потом сдвигал на 200px вправо - получались гор. пол. прокрутки. Expression - рулит.
Эх, было бы неинтересно, если бы все браузеры работали одинаково :)
Sam 13 августа, 2007 11:15 #
Кстати, как сделать двухколоночную разметку абсолютным позиционированием, чтобы колонки занимали 100% по высоте (min-height) и при этом ещё и тянулись, когда контента больше, чем 100% высоты экрана?
Serebrennikov 20 сентября, 2007 19:40 #
Спасибо, порадовало, но все же меня эта ситуация с хаками удручает очень сильно.
Евгений 20 сентября, 2007 20:46 #
Условные комментарии и expression не хаки, а документированные возможности, хотя это им привлекательности не добавляет.
Coldman 23 ноября, 2007 12:39 #
при ресайзе окна , должно реально напрягать процесор