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

И вот с этим вторым вариантом (который, кстати, мне нравится больше) я отметил одну проблему: его не получается сделать, если блок с основным содержимым идет в HTML раньше дополнительных.

А сегодня наткнулся на статью Меттью Левина на "A List Apart", где описывается, как это можно сделать. Читать ее надо обязательно, а я постараюсь кратко изложить принцип по-русски.

Принцип я покажу на двух колонках (на ALA рассматривают на трех).

<div id="container">
  <div id="main">...</div>
  <div id="sidebar">...</div>
</div>

Суть нужной резиновной раскладки в том, что одна из колонок должна иметь ширину "весь контейнер минус константа". Поскольку прямого способа это сделать в CSS нет, я предлагал оставить основную колонку в потоке с автоматической шириной и дать ей боковой фиксированный padding, который будет откладываться внтурь. Это и дает нужный эффект. Но как раз то, что блок остается в потоке, не дает поставить его в HTML первым перед боковушками, потому что тогда они будут начинаться ниже основной колонки (у меня в статье есть картинка).

#main {
  background:red;
  padding-left:200px;
}

#sidebar {
  background:blue;
  float:left;
  width:200px;
}

Левин делает по-другому.

Во-первых, основной блок таки float'ится, и ему ставится ширина 100%. А вот место под боковые колонки делается с помощью padding'ов в контейнере. Ширина содержимого контейнера при этом уменьшается, и именно в нее укладывается этот основной float.

Но боковые колонки все еще идут ниже основной, потому что та занимает 100% доступной ширины. Вот тут идет гениальная штука. Если боковушке дать отрицательный боковой margin равный или больше ее ширине, то она перестает занимать место по горизонтали вообще. И значит "умещается" сбоку основной колонки. И тем самым поднимается вверх.

#container {
  padding-left:200px;
}
#main {
  float:left; width:100%;
}
#sidebar {
  float:left; width:200px;
  margin-left:-200px;
}

Дальше осталось пододвинуть боковушку на свое место налево. Сейчас относительно своего начального положения (правый край) она сдвинута налево на 200 пикселов, и надо к ним добавить еще все ширину основной колонки — 100%. В CSS есть обходной способ, когда надо сложить несколько смещений в разных единицах: одно сделать через margin, а другое — через смещение при position:relative.

#sidebar {
  float:left; width:200px;
  margin-left:-200px;

  position:relative; left:-100%;
}

Вот теперь все практически на месте. Единственная проблема — баг в IE, который двигает колонку слишком далеко налево. Автор статьи это обходит неким шаманством, расставляя по-другому 200px и 100%, и применяя right вместе с left примерно так:

#sidebar {
  float:left; width:200px;
  margin-left:-100%;
  position:relative; right:200px;
}

* html #sidebar {
  left:0; /* тут ширина правой колонки, если есть */
}

Честь ему и слава, что он до этого дохачил :-). Однако, это все равно работает, только если ширина контейнера занимает все окно. Если меньше, IE куда-то девает левую колонку, и у меня так и не вышло ее найти :-(.

Комментарии: 12

  1. .grin!

    containe{padding:0 0 0 200px;border-color:#000;}

    sidebar{float:left;width:200px;margin-right:-200px;position:relative;left:-200px;}

    main{float:right;width:100%;padding:0 0 0 200px;padd\ing:0;}

  2. .grin!

    аа, забыл бордеры убрать....

  3. Иван Сагалаев

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

  4. .grin!

    да, 3ю придётся выносить за контейнер =/

  5. Сергей

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

  6. Давид Мзареулян

    Внушаеть! Но при всём уважении к проделанной Меттью работе, ИМХО, это всё-таки тот случай когда проще плюнуть на принципы и переставить блоки в коде:)

  7. Анастасия

    Приведенный у вас код, тем не менее, не работает у меня в IE 6.0 :( как и код, приведенный в статье Меттью Левина, даже с "заплатками". А так уже хочется без проблем делать резиновую раскладку в 3 колонки :(

  8. Portnov

    А чем не нравится идея такая:

    left

    {
    position: absolute;
    left: 0;
    top: 0;
    width: 10em;
    }

    main

    {
    margin-left: 10em;
    margin-right: 11em;
    }

    right

    {
    position: absolute;
    right: 0;
    top: 0;
    width: 11em;
    }

    Какой html, думаю, понятно... Ну и добавляются правила нужные + хаки.

  9. Иван Сагалаев

    Абсолютно позиционированная колонка не сможет раздвигать вниз контейнер. И если она длиннее main'а, то будет напозать на футер или просто некраисво торчать снизу. Собственно, это основная проблема, из-за которой колонки делаются как правило float'ами: те можно оставить в потоке.

  10. Сергей Адаменко

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

    Решение с отступами в процентах привожу:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" “http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
      <title>title</title>
      <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
      <style><!--
        * {margin:0; padding:0;}
        html, body {margin:0; padding:0; border:none; height:100%;}
        #container {position: relative; width:100%; min-height:100%; height:auto; min-width:750px;}
        * html #container {height:100%; width:expression(document.documentElement.clientWidth < 751? "750px": "100%");}
        #top, #middle {position: relative; width:100%; margin:0; overflow:hidden;}
        #top_cont, #middle_cont, #footer_cont {position: relative; margin:0 2%;}
        #footer, #empty {height: 40px; width: 100%; padding-top:10px; margin: 20px 0 0 0;}
        #footer {position: absolute; bottom: 0; left: 0;}
        #empty {position: relative; clear: both;}
        #top_cont { height:70px;}
        #column-1, #column-2, #column-3 {float:left; position: relative;}
        #column-1-cont, #column-2-cont, #column-3-cont {padding:10px;}/* проще вложить еще по диву, чем в коде ниже заниматься математикой */
        #columns { position: relative; overflow:hidden; margin: 0; padding-left: 200px; padding-right: 200px; min-width: 200px;}
        #column-1 { width: 100%; background:#ffe; } /* центральную колонку пишем первой - она самая важная */
        #column-2 { width:200px; background:#efe; margin-left: -100%; right: 200px; //left: 200px; //margin-left: -96%;} /* здесь - левая колонка (Эхплорер, как обычно, без бубна не работает - ему скармливается левая позиция, равная ширине правой колонки и от левого марджина отнимается общий марджин middle_cont если есть) */
        #column-3 { width:200px; background:#eff; margin-right: -100%;} /* здесь - правая колонка */
    
        /* колонки можно менять местами */
      --></style>
    </head>
    <body>
      <div id="container">
        <div id="top">
          <div id="top_cont">top
          <!-- top_cont --></div>
        <!-- top--></div>
        <div id="middle">
          <div id="middle_cont">
            <div id="columns">
              <div id="column-1">
                <div id="column-1-cont">
                  column-1 column-1 column-1
                <!-- column-1-cont--></div>
              <!-- column-1--></div>
              <div id="column-2">
                <div id="column-2-cont">
                  column-2 column-2<br>
                  column-2 column-2 column-2 column-2 column-2 column-2 column-2<br>
                  column-2 column-2 column-2
                <!-- column-2-cont--></div>
              <!-- column-2--></div>
              <div id="column-3">
                <div id="column-3-cont">
                  column-3<br>
                  column-3 column-3 column-3 column-3 column-3
                <!-- column-3-cont--></div>
              <!-- column-3-->
            </div><!-- columns--></div>
          <!-- middle_cont--></div>
        <!-- middle--></div>
        <div id="empty"> <!-- empty--></div>
        <div id="footer">
          <div id="footer_cont">
            footer
          <!--footer_cont--></div>
        <!--footer--></div>
      <!-- container--></div>
    </body>
    </html>
    

    Возможно тут есть лишние контейнеры - просто у меня на все раскладки стандартный шаблон. К примеру, здесь футер клеится к нижнему краю окна, если содержимое меньше прокрутки, и к нижнему краю содержимого - если больше.

  11. Иван Сагалаев

    Возможно тут есть лишние контейнеры

    Да уж :-)

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

    CSS — не идеальный инструмент. Поэтому если его возможностей для целей дизайнера серьезно не хватает, мне кажется есть всего два выхода:

    • адаптировать желания дизайнера к несовершенству инструмента
    • взять другой инструмент

    Но пытаться пользоваться неподходящим инструментом просто незачем, мне кажется.

  12. Михаил

    к тому же последний вариант у меня ужасно глючит в ФайрФоксе и Опере ... лечно у меня на работе (не еще не работа, я туда устраиваюсь и должен тестовое задание ваполнить) требуют (даже настоятельно рекомендуют) что бы в большенстче браузеров работало хорошо! да что там начальство, я сам от себя этого требую ))) правда не получается пока, но рано или поздно думаю добью

Добавить комментарий