Кросс-браузерный семантически корректный резиновый макет с тремя колонками (сайдбары справа)
Очередной раз попав не туда, куда надо из Google, я натолкнулся на статью "Трехколоночный макет на CSS с одинаковой высотой колонок". Да, трехколоночные макеты (да еще и резиновые!) очень популярны, я смотрю
Но, несмотря на популярность таких макетов, многие верстальщики почему-то не хотят учиться и городят целый огород на div'ах.
В указанной статье приводится следующая разметка (я убрал пустые строки и изменил форматирование):
<div id="wrapper">
<div id="header"></div>
<div id="container">
<div id="sub-container">
<div id="wrpr">
<div id="content">
<div id="text"></div>
</div>
<div id="left"></div>
</div>
</div>
<div id="right"></div>
</div>
<div id="footer"></div>
</div>
</body>
Что мы видим: пример, как верстать не надо. Может быть, сказано слишком резко, но на мой взгляд, суп из div'ов (с глубиной вложенности 6) ничем не лучше табличной вёрстки (табличная вёрстка будет даже компактнее). Кроме того, большая часть этого супа не несёт семантической нагрузки. И вообще, при верстке нужно руководствоваться принципом KISS, но это моё сугубо личное мнение.
Попробуем переделать.
Начнём с разметки:
<div id="header"></div>
<div id="container">
<div id="content" class="column"></div>
<div id="col1" class="column"></div>
<div id="col2" class="column"></div>
</div>
<div id="footer"></div>
</body>
Как я уже отмечал в предыдущих статьях, названиям классов и атрибутам id нужно давать семантически значимые имена, но в качестве тестового примера пойдут и такие.
Простая разметка — простые стили:
margin: 0;
padding: 0;
border: 0;
width: 100%;
}
html { /* Для IE6 и IE7 */
overflow: auto;
}
body {
min-width: 50em; /* #container.paddingRight + #col1.offsetWidth + #col2.offsetWidth */
}
#container {
overflow: hidden;
padding-right: 25em; /* #col1.offsetWidth + #col2.offsetWidth */
position: relative;
}
/*\*/
* html #container {
height: 1%;
}
/**/
.column {
position: relative;
float: left;
padding-bottom: 1002em !important;
margin-bottom: -1000em !important;
overflow: hidden;
}
#content {
width: 100%;
}
#col1 {
width: 10em;
margin-right: -100%;
}
#col2 {
width: 15em;
margin-right: -100%;
margin-left: 10em; /* #col1.offsetWidth */
}
#footer {
clear: both;
}
Для краткости презентационные стили (aka расцветка) опущены.
Тестовая страница доступна здесь. Кстати, разметка получилась даже проще, чем здесь
Но макет не был бы так хорош, если бы не позволял с лёгкостью добавлять отступы, границы и бордюры. В статье "IE7/8 и общий случай двухколоночной резиновой вёрстки" я показывал, как получаются формулы для вычисления значений границ и иже с ними (вспоминаем про эквивалентность преобразований), поэтому здесь приведу только конечный результат:
| Элемент | Свойство | Формула |
|---|---|---|
| body | min-width | (#container.offsetWidth - #container.width) + (#content.offsetWidth - #content.width) + #col1.offsetWidth + #col2.offsetWidth |
| #container | padding-right | (#content.offsetWidth - #content.width) + #col1.offsetWidth + #col2.offsetWidth |
| #content | margin-left | =#container.paddingLeft |
| #col1 | margin-left | =#content.marginRight |
| #col2 | margin-left | #col1.offsetWidth + #col2.желаемый_marginLeft |
| #col1, #col2 | margin-right | -100% |
В #container.paddingRight входит желаемый #col2.marginRight (но у Opera есть некоторые проблемы с его отображением).
Из-за того, что все колонки имеют равную высоту, отобразить border-bottom у них не представилось возможным.
Для IE8 добавляются следующие изменения:
#col1.marginLeftустанавливается в сумму горизонтальных отступов, границ и бордюров элемента#content;#col2.marginLeftувеличивается на величину#col1.marginLeft.
Тестовая страница для экспериментов находится здесь.
margin: 0;
padding: 0;
border: 0;
font: 12px Verdana, Tahoma, Arial, Helvetica, sans-serif;
width: 100%;
}
html {
overflow: auto;
}
body {
min-width: 81em; /* (38.5 + 0.5 + 2*1 + 2*1) + (2*1 + 2*1 + 0.5) + (10 + 2*1 + 2*1) + (15 + 0.5 + 2*1 + 2*1) = 43 + 4.5 + 14 + 19.5 = 57 + 24 */
}
#container {
overflow: hidden;
padding-right: 38.5em; /* (2*1 + 2*1 + 0.5) + (10 + 2*1 + 2*1) + (15 + 0.5 + 2*1 + 2*1) + желаемый margin-right для #col2 (0.5em) */
position: relative;
padding-left: .5em;
padding-top: .5em;
padding-bottom: .5em;
margin: 1em;
border: 1em solid black;
}
/*\*/
* html #container {
height: 1%;
}
/**/
.column {
position: relative;
float: left;
padding-bottom: 1002em !important; /* Фактически, padding-bottom = 2em */
margin-bottom: -1000em !important;
overflow: hidden;
}
#content {
width: 100%;
border: 1em solid green;
padding: 1em;
margin-right: .5em;
}
#col1 {
width: 10em;
margin-right: -100%;
padding: 1em;
border: 1em solid red;
}
*:first-child/**/+html #col1 {
margin-left: 4.5em; /* #col1.paddingLeft + #col1.paddingRight + #col1.borderLeft + #col1.borderRight + #col2.желаемый_marginLeft */
}
#col2 {
width: 15em;
margin-right: -100%;
margin-left: 14.5em; /* #col1.paddingLeft + #col1.paddingRight + #col1.borderLeft + #col1.borderRight + #col2.желаемый_marginLeft + #col1.width */
padding: 1em;
border: 1em solid blue;
}
*:first-child/**/+html #col2 {
margin-left: 19em; /* #col2.marginLeft + #col1.marginLeft */
}
#footer {
clear: both;
}


Владимир, ваш способ я давно знаю и использовал его не раз. Но дело в том, что он не универсален. Я много раз сталкивался с тем, что при определенном дизайне он просто-напросто не работает. Поэтому я пришел к способу который описал в своей статье.
Если дизайн довольно простой, то да, ваш способ несомненно лучше.
И это вовсе не значит, что я не хочу учиться, как вы сказали выше
Все зависит от конкретного дизайна. Я сам предпочитаю, чтобы все было как можно проще
Признаю, я высказался слишком резко… Просто мне за тот день попалось слишком много супов, приготовленных на
divУ меня ни разу такого не получалось, всё время использую отрицательные границы. Вы меня заинтриговали! А можно, пожалуйста, какую-нибудь ссылочку на дизайн, где отрицательные границы не срабатывают?
Очень любопытно!
Я просто в силу природной лени пишу генератор многоколоночных макетов (составляю конкуренцию psd2html.com
), поэтому мне очень интересны примеры, в которых отрицательные границы разваливаются.
Пример показал бы с удовольствием, но, к сожалению, уже не помню, где был подобный трабл. Кстати, мои слова на счет того, что это работает не всегда, может подтвердить автор блога trifler.ru/blog/
P.S. В Opera 9.5 комментарии куда-то прячутся
Спасибо, буду искать концы
Да-да-да, на эту страничку я в тот злополучный день тоже нарвался
Вот и попался мне реальный глючный пример с использованием нижних отступов. Гляньте в Опере сюда - http://imhoblog.ru/2008/06/28/audit-imhoblogru-obzor-sobrannogo-nektara/
И это из-за вот такой штуки:
.sidebar {
…
padding: 5px 5px 32767px 5px;
margin-bottom: -32737px;
…
}
А когда я сдавал эту работу, данного глюка не было. Именно из-за таких казусов я и давно уже косо смотрю на данный способ.
overflow: hiddenконтейнеру в этом случае поможетВ том-то и дело, что overflow: hidden уже стоит, но не помогает и я не могу понять, почему он в данном случае не срабатывает. Поэтому здесь по любому придется отказыватья от этих отступов.
Дмитрий, я пользуюсь несколько иной техникой размещения колонок, но по-моему Вы потеряли
overflow: hiddenдля сайдбаров (.sidebar { overflow: hidden; }).Пробовал ставить и для .sidebar - не помогает. Видимо сайдбары нужно помещать в еще один див, которому ставить overflow: hidden.
Дмитрий, по-моему, Вы где-то ошиблись… Я сохранил страницу себе на диск, добавил
overflow: hidden.sidebarи всё отлично смотрится в Опере (по крайней мере, в 9.2x - 9.50 у меня нет).Тестовая страница: http://static2.sjinks.org.ua:8080/test/imhoblog/test.html
[...] переходим к трём колонкам: [...]
У меня как раз стоит Opera 9.5. И она, к сожалению, в данном случае overflow: hidden вообще не воспринимает, т.е. получается, что трабл только в Opera 9.5.
Дмитрий, тут такая проблема… Валидатор нашел 186 ошибок (!) и проблему с распознаванием UTF-8. Я бы всё же, наверное, попытался бы исправить ошибки, и только потом переходить к CSS. Валидатор жалуется на неправильно закрытые тэги.
Дмитрий, по ходу я прав - проблема в кривой разметке.
http://static2.sjinks.org.ua:8080/test/imhoblog/test.html
Я убрал этот блок (из Подписки), и всё стало красиво:
<center>
<br>
<p>
<!-- <a rel="nofollow" href="http://feeds.feedburner.com/imhoblog" rel="nofollow"><img src="http://imhoblog.ru/img/RSSicon32x32.png" height="32" width="32" style="border:0" alt="feedburner"/></a> -->
<a rel="nofollow" href="http://feeds.feedburner.com/imhoblog" rel="nofollow"><img src="http://imhoblog.ru/img/ratatfeed.gif" height="128" width="128" style="border:0" alt="Подпишись на RSS!" /></a>
<br>
<a rel="nofollow" href="http://feeds.feedburner.com/imhoblog" rel="nofollow"><img src="http://feeds.feedburner.com/~fc/imhoblog?bg=99CCFF&fg=444444&anim=0" height="26" width="88" style="border:0" alt="feedburner" /></a></p>
<br>
<a rel="nofollow" href='http://toodoo.ru/blog/19819/click' rel="nofollow">
<img src='http://c.toodoo.ru/blog/19819/images/88x15w.gif' border='0' alt='количество читателей онлайн и всего' /></a>
</a>
<br>
<!-- rss2email -->
<a "nofollow" href="http://www.rss2email.ru?rss=http://feeds.feedburner.com/imhoblog" title="Получать RSS-ленту на почту" rel="nofollow"><img src="http://www.rss2email.ru/counter/typeA/23728_3.gif" border="0"></a>
<!-- /rss2email -->
<br>
<a rel="nofollow" href="http://lenta.yandex.ru/settings.xml?name=feed&url=http://feeds.feedburner.com/imhoblog" rel="nofollow"><img src="http://lenta.yandex.ru/i/addfeed.gif" border="0" alt="Читать в Яндекс.Ленте" /></a>
<br>
<a rel="nofollow" href="http://fusion.google.com/add?source=atgs&feedurl=http%3A//feeds.feedburner.com/imhoblog" rel="nofollow"><img src="http://buttons.googlesyndication.com/fusion/add.gif" border="0" alt="Add to Google"></a>
<br><br>
<a href="http://imhoblog.ru/2008/05/09/chto-takoe-rss-chast-1-osnovy/" target="_blank" rel="nofollow">Что означает значок RSS?</a>
<br>
</center>
<noindex>
Для сравнения старая версия: http://static2.sjinks.org.ua:8080/test/imhoblog/test2.html
Мораль: ошибки в разметке надо исправлять
Ошибка с незакрытым тегом, слава Богу, не моя. Я подобных ошибок стараюсь не допускать.
Удивительные вещи - после исправления этого тега футер возвращается на место, но отступ все равно остается, теперь уже под футером. Методом исключений определил, что отступ появляется сразу же после выполнения скрипта todoo-виджета (блок “Наши ИМХО люди”). Вот это побороть я уже не в силах.
Это из-за того, что WordPress по умолчанию оформляет все виджеты как списки, а этот TooDoo лепит внутрь элемента
ulтаблицу. Фикс - править исходный код плагина или попытаться поиграть с параметрами виджета$beforeи$after(если они есть).