Ars Longa, Vita Brevis

Кросс-браузерное решение для резинового макета с одинаковой высотой колонок и стопроцентной высотой

Недавно понадобилось сверстать резиновый трёхколоночный макет с высотой 100% и колонками одинаковой высоты. К моему удивлению, это оказалось не очень простым делом: вместо планируемого получаса это заняло намного больше времени.

Требования к макету:

  • кросс-браузерность (куда без неё);
  • минимальная высота: 100% (полное окно, независимо от высоты контента);
  • минимум кода;
  • все три колонки должны быть одинаковой высоты;
  • никакого JavaScript.

Минимум кода означает минимум разметки:

[-]
View Code HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Three Column Liquid Layout</title>
</head>
<body>
    <div id="header">Header</div>
    <div id="container">
        <div id="content" class="column">
            <p>Sed eleifend, sapien vel mollis euismod, sem velit semper ante...</p>
        </div>

        <div id="left" class="column">
            <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis sollicitudin dolor nec nunc iaculis tincidunt...</p>
        </div>

        <div id="right" class="column">
            <p>Phasellus sollicitudin. Fusce ut tellus. Vivamus dapibus. Cras eu elit. Vestibulum ante ipsum primis in faucibus orci luctus et...</p>
        </div>
    </div>
    <div id="footer">Footer</div>
</body>
</html>

So far so good, как любит говорить один мой коллега. Теперь переходим к разметке.

Начнём с общих определений:

[-]
View Code CSS
html {
    background: #800000;
}

html, body {
    margin: 0;
    padding: 0;
    border: 0;
}

body {
    font: 14px/120% Verdana, Tahoma, Arial, Helvetica, sans-serif;
    width: 90%;
    margin: 0 auto;
}

Теперь переходим к 100% высоте. Помним, что Konqueror/KHTML имеет свою точку зрения по поводу того, кто задаёт скроллинг; также не забываем про IE6, который не понимает min-height

[-]
View Code CSS
html {
    overflow: auto;
}

html:not(:nth-child(1)) {
    overflow: visible; /* KHTML сам нарисует скроллинг, не будем ему мешать */
}

html, body {
    margin: 0;
    padding: 0;
    border: 0;
    width: 100%;
    height: 100%;
}

#container {
    height: auto !important;
    height: 100%; /* для IE6 */
    min-height: 100%;
}

* html #container { overflow: visible; }

Для IE6 мы должны задать overflow: visible, в противном случае контент будет нещадно обрезаться.

Задаем заголовок и подвал:

[-]
View Code CSS
#header {
    height: 3em;
    background: red;
    color: #FFF;
    position: absolute;
    top: 0;
    width: 100%;
    z-index: 1000;
    left: 0;
}

.column {
    padding-top: 3em !important; /* компенсация высоты заголовка */
}

#footer {
    height: 3em;
    color: #FFF;
    background: green;
    position: relative;
    z-index: 1000;
    margin-top: -3em;
    width: 100%;
}

Заголовок позиционируем абсолютно, так как контейнер #container имеет как минимум стопроцентную высоту: задать высоту 100%-3em будет проблематично. Поэтому, считая, что высота заголовка нам известна (а так обычно всегда), мы просто помещаем заголовок "на территорию" контейнера, а высота заголовка будет компенсирована верхним отступом у колонок. Даже если нам придётся задать фоновый рисунок у #container, мы можем компенсировать высоту заголовка путём использования background-position.

Аналогично (только хуже :-) ) с футером: его нужно поднять вверх на всю его высоту (отсюда относительное позиционирование и z-index) — как и в случае с заголовком, для поддержания стопроцентной высоты необходимо, чтобы он располагался "на территории" контейнера.

Теперь переходим к трём колонкам:

[-]
View Code CSS
#container {
    padding-left: 220px;
    padding-right: 200px;
    overflow: hidden;
    float: left; /* IE 5.01 */
    float/**/: none;
    background: lime;
    position: relative;
}

#left, #right, #content {
    float: left;
    position: relative;
    padding-bottom: 1000em !important;
    margin-bottom: -997em !important; /* компенсация высоты футера */
}

#left {
    width: 220px;
    background: url(images/tile-2.jpg) repeat;
    margin-left: -100%;
    right: 220px;
}

* html #left { /* У IE6 всё не как у людей */
    left: 200px;
}

#right {
    width: 200px;
    background: url(images/tile-3.jpg) repeat;
    margin-right: -100%;
}

#content {
    width: 100%;
    background: url(images/tile-1.jpg) repeat;
}

Теперь идут хаки. По слухам, в IE/Mac вышеприведённая техника для создания колонок одинаковой высоты не работает. Вернее, он работает, но страницу разносит по высоте (добавляется невидимый padding). Мне-то всё равно, но так как исправить просто (в смысле, сделать колонки разной высоты), то почему бы и нет:

[-]
View Code CSS
#left, #right, #content {
    float: left;
    position: relative;
    padding-bottom: 3em; /* компенсация высоты футера */
}

/* Прячем от IE/Mac \*/
#left, #right, #content {
    padding-bottom: 1000em !important;
    margin-bottom: -997em !important;
}
/**/

Переходим к Опере. Старые версии (7.0-7.2) не обрезают колонки по высоте. На помощь приходит EasyClearing:

[-]
View Code CSS
#container:after {
    content: 'EasyClearing';
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
}

#container { display: inline-block; }
/*\*/
#container { display: block; }
/**/

Но, как это обычно бывает в жизни, исправил одну ошибку — вылезла другая: EasyClearing портит разметку в IE 5.01. По счастью, это легко лечится путём добавления float: left контейнеру #container:

[-]
View Code CSS
#container {
    float: left; /* IE 5.01 */
    float/**/: none;
}

Тем не менее, мы исправили не все глюки в Опере. Для Opera 8, у которой есть свои глюки в обработке overflow: hidden, нам придётся убрать margin-bottom/padding-bottom с самих колонок и применить их элементу внутри колонок. Либо так:

[-]
View Code CSS
@media all and (min-width: 0px) {
    #left, #right, #content {
        margin-bottom: 0 !important;
        padding-bottom: 3em !important; /* Компенсация высоты футера */
    }

    #left:before, #right:before, #content:before {
        content: 'EasyClearing';
        display: block;
        background: inherit;
        padding-top: 1000em !important;
        margin-bottom: -1000em !important;
        height: 0;
    }
}

Тестовая страница.

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

Комментарии к статье "Кросс-браузерный резиновый трёхколоночный макет в высоту окна" (10) »

  1. [June 30, 2008 00:12] Vladimir:

    Насколько всё проще, если высота во всё окно не требуется:

    [-]
    View Code CSS
    html, body {
        margin: 0;
        padding: 0;
        border: 0;
        width: 100%;
    }

    body {
        font: 14px/120% Verdana, Tahoma, Arial, Helvetica, sans-serif;
        position: relative;
        min-width: 640px;
        width: 90%;
        margin: 0 auto;
    }

    #header {
        height: 3em;
        background: red;
        color: #FFF;
        width: 100%;
    }

    #container {
        padding-left: 220px;
        padding-right: 200px;
        overflow: hidden;
        float: left; /* IE 5.01 */
        float/**/: none;
        height: auto !important;
        background: lime;
        position: relative;
    }

    #left, #right, #content {
        float: left;
        position: relative;
    }

    /*\*/
    #left, #right, #content {
        padding-bottom: 32767px !important;
        margin-bottom: -32767px !important;
    }
    /**/

    @media all and (min-width: 0px) {
        #left, #right, #content {
            margin-bottom: 0 !important;
            padding-bottom: 0 !important;
        }

        #left:before, #right:before, #content:before {
            content: 'EasyClearing';
            display: block;
            background: inherit;
            padding-top: 32767px !important;
            margin-bottom: -32767px !important;
            height: 0;
        }
    }

    #container:after {
        content: 'EasyClear';
        display: block;
        height: 0;
        clear: both;
        visibility: hidden;
    }

    #container { display: inline-block; }
    /*\*/
    #container { display: block; }
    /**/

    #left {
        width: 220px;
        background: cyan;
        margin-left: -100%;
        right: 220px;
    }

    * html #left {
        left: 200px;
    }

    #right {
        width: 200px;
        background: yellow;
        margin-right: -100%;
    }

    #content {
        width: 100%;
        background: #CCC;
    }

    #footer {
        height: 3em;
        color: #FFF;
        background: green;
        width: 100%;
    }
    #1
  2. [July 1, 2008 12:22] Иван:

    В IE 7 не заработало :( Футер вылазит на следующую страницу.

    А так, магия! Дэвид Блейн отдыхает

    #2
  3. [July 1, 2008 16:02] Vladimir:

    Иван, работает всё в IE7 :-) Скриншот приаттачен.
    Если высота контента больше высоты окна, то футер вылезет на следующую страницу, так и задумывалось.

    PS - Дэвид Блейн совсем не маг, то, что он вытворяет, может каждый… Непонятно, почему СМИ так это всё раздувают…

    IE7_3cols_h100.png

    #3
  4. [October 9, 2008 10:39] arnoldovich:

    Во-первых, спасибо за статью. Давно искал такую верстку. Сразу видно мастера.
    Во-вторых, вопрос.
    Можно ли усложнить задачу и вставить в этот дизайн горизонтальую навигационную панель, которая обычно визуально располагается под хедером? А в разметке желательно конечно, чтобы код был после контента.
    Например так:

    Header

    Sed eleifend, sapien vel mollis euismod, sem velit semper ante...

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis sollicitudin dolor nec nunc iaculis tincidunt...

    Phasellus sollicitudin. Fusce ut tellus. Vivamus dapibus. Cras eu elit. Vestibulum ante ipsum primis in faucibus orci luctus et...

    Item 1
    Item 2
    Item 3

    Footer

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

    #4
  5. [October 10, 2008 13:43] arnoldovich:

    В ИЕ 6.0.2 появляется горизонтальная полоса прокрутки.

    .jpg

    #5
  6. [October 16, 2008 10:40] Vladimir:

    Arnoldovich, я пока в отпуске и посмотреть смогу только где-то в начале ноября. Но я бы тоже решал задачу через абсолютное позиционирование. Единственное, что навигационную панель пришлось бы размещать после #container.

    #6
  7. [November 2, 2008 02:52] Chups:

    К сожалению, валидатор выдает ошибки…

    6: Unknown pseudo-element or pseudo-class :nth-child

    6: Unknown pseudo-element or pseudo-class :not

    67: Value Error : min-width Property min-width doesn’t exist in all but exists in all : 0

    98: #left Value Error : background Too many values or values are not recognized : cyan

    #7
  8. [November 10, 2008 13:35] Vladimir:

    Валидировать нужно с профилем CSS 3, не 2

    #8
  9. [November 10, 2008 19:44] olga:

    скажите, пожалуйста! Почему, если вставлять в левый блок ссылки так, чтоб при наведеннии на них они подчеркивались, этот левый блок уплывает вправо?

    #9
  10. [November 10, 2008 20:06] olga:

    имелось ввиду в ие6

    #10

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