Ars Longa, Vita Brevis

Кросс-браузерный семантически корректный резиновый макет с тремя колонками (сайдбары справа)

Очередной раз попав не туда, куда надо из Google, я натолкнулся на статью "Трехколоночный макет на CSS с одинаковой высотой колонок". Да, трехколоночные макеты (да еще и резиновые!) очень популярны, я смотрю :-) Но, несмотря на популярность таких макетов, многие верстальщики почему-то не хотят учиться и городят целый огород на div'ах.

В указанной статье приводится следующая разметка (я убрал пустые строки и изменил форматирование):

[-]
View Code HTML
<body>
    <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, но это моё сугубо личное мнение.

Попробуем переделать.
Начнём с разметки:

[-]
View Code HTML
<body>
    <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 нужно давать семантически значимые имена, но в качестве тестового примера пойдут и такие.

Простая разметка — простые стили:

[-]
View Code CSS
html, body {
    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.

Тестовая страница для экспериментов находится здесь.

[-]
View Code CSS
html, body {
    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;
}

Связанные записи

Комментарии к статье "Резиновый трехколоночный макет с правосторонними сайдбарами" (17) »

  1. [June 19, 2008 10:50] Dimox:

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

    Если дизайн довольно простой, то да, ваш способ несомненно лучше.

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

    #1
  2. [June 19, 2008 11:30] Vladimir:

    Признаю, я высказался слишком резко… Просто мне за тот день попалось слишком много супов, приготовленных на div

    Я много раз сталкивался с тем, что при определенном дизайне он просто-напросто не работает

    У меня ни разу такого не получалось, всё время использую отрицательные границы. Вы меня заинтриговали! А можно, пожалуйста, какую-нибудь ссылочку на дизайн, где отрицательные границы не срабатывают? :-) Очень любопытно!

    Я просто в силу природной лени пишу генератор многоколоночных макетов (составляю конкуренцию psd2html.com ;-) ), поэтому мне очень интересны примеры, в которых отрицательные границы разваливаются.

    #2
  3. [June 19, 2008 12:45] Dimox:

    Пример показал бы с удовольствием, но, к сожалению, уже не помню, где был подобный трабл. Кстати, мои слова на счет того, что это работает не всегда, может подтвердить автор блога trifler.ru/blog/

    P.S. В Opera 9.5 комментарии куда-то прячутся :)

    #3
  4. [June 19, 2008 12:52] Vladimir:

    В Opera 9.5 комментарии куда-то прячутся

    :-) Целый день экспериментами занимаюсь (и плюс поддержкой многоязыковости занимаюсь), так что какое-то время всё будет скакать.

    Пример показал бы с удовольствием, но, к сожалению, уже не помню, где был подобный трабл. Кстати, мои слова на счет того, что это работает не всегда, может подтвердить автор блога trifler.ru/blog/

    Спасибо, буду искать концы

    #4
  5. [June 20, 2008 16:26] Vladimir:

    Да-да-да, на эту страничку я в тот злополучный день тоже нарвался :-)

    #5
  6. [June 29, 2008 01:00] Dimox:

    Вот и попался мне реальный глючный пример с использованием нижних отступов. Гляньте в Опере сюда - http://imhoblog.ru/2008/06/28/audit-imhoblogru-obzor-sobrannogo-nektara/

    И это из-за вот такой штуки:

    .sidebar {

    padding: 5px 5px 32767px 5px;
    margin-bottom: -32737px;

    }

    А когда я сдавал эту работу, данного глюка не было. Именно из-за таких казусов я и давно уже косо смотрю на данный способ.

    #6
  7. [June 29, 2008 01:07] Vladimir:

    overflow: hidden контейнеру в этом случае поможет :-)

    #7
  8. [June 29, 2008 01:31] Dimox:

    В том-то и дело, что overflow: hidden уже стоит, но не помогает и я не могу понять, почему он в данном случае не срабатывает. Поэтому здесь по любому придется отказыватья от этих отступов.

    #8
  9. [June 29, 2008 01:47] Vladimir:

    Дмитрий, я пользуюсь несколько иной техникой размещения колонок, но по-моему Вы потеряли overflow: hidden для сайдбаров (.sidebar { overflow: hidden; }).

    #9
  10. [June 29, 2008 10:37] Dimox:

    Пробовал ставить и для .sidebar - не помогает. Видимо сайдбары нужно помещать в еще один див, которому ставить overflow: hidden.

    #10
  11. [June 29, 2008 15:51] Vladimir:

    Дмитрий, по-моему, Вы где-то ошиблись… Я сохранил страницу себе на диск, добавил overflow: hidden .sidebar и всё отлично смотрится в Опере (по крайней мере, в 9.2x - 9.50 у меня нет).

    Тестовая страница: http://static2.sjinks.org.ua:8080/test/imhoblog/test.html

    #11
  12. #12
  13. [June 30, 2008 16:51] Dimox:

    У меня как раз стоит Opera 9.5. И она, к сожалению, в данном случае overflow: hidden вообще не воспринимает, т.е. получается, что трабл только в Opera 9.5.

    #13
  14. [June 30, 2008 18:49] Vladimir:

    Дмитрий, тут такая проблема… Валидатор нашел 186 ошибок (!) и проблему с распознаванием UTF-8. Я бы всё же, наверное, попытался бы исправить ошибки, и только потом переходить к CSS. Валидатор жалуется на неправильно закрытые тэги.

    #14
  15. [June 30, 2008 19:04] Vladimir:

    Дмитрий, по ходу я прав - проблема в кривой разметке.

    http://static2.sjinks.org.ua:8080/test/imhoblog/test.html

    Я убрал этот блок (из Подписки), и всё стало красиво:

    [-]
    View Code HTML
    <noindex>  
    <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>&nbsp; -->
    <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&amp;fg=444444&amp;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

    Мораль: ошибки в разметке надо исправлять :-)

    #15
  16. [June 30, 2008 21:15] Dimox:

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

    Удивительные вещи - после исправления этого тега футер возвращается на место, но отступ все равно остается, теперь уже под футером. Методом исключений определил, что отступ появляется сразу же после выполнения скрипта todoo-виджета (блок “Наши ИМХО люди”). Вот это побороть я уже не в силах.

    #16
  17. [June 30, 2008 21:27] Vladimir:

    Это из-за того, что WordPress по умолчанию оформляет все виджеты как списки, а этот TooDoo лепит внутрь элемента ul таблицу. Фикс - править исходный код плагина или попытаться поиграть с параметрами виджета $before и $after (если они есть).

    #17

RSS feed for comments on this post. TrackBack URL

Оставить комментарий к записи "Резиновый трехколоночный макет с правосторонними сайдбарами"

Изображения должны быть включены!

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Subscribe without commenting