2. Свойство float на практике

На этой странице:

Сначала рассмотрим пример использования свойства float по прямому назначению — для создания блоков, которые другие элементы страницы обтекают слева или справа, а затем посмотрим, как можно использовать плавающие блоки для построения горизонтального меню и многоколонной вёрстки страниц.

Отметим, что свойство float не предназначено для вёрстки колонок, хотя используется для этой цели очень часто. Но что делать, если настоящие средства многоколонной вёрстки присутствуют только в стандарте CSS3 (серия свойств с префиксом column), который браузеры пока не поддерживают. Вот и приходится разработчикам придумывать техники, основываясь на подручном материале.

Вверх Плавающая врезка

Врезка в виде плавающего блока создаётся просто и естественно — именно для таких целей и было задумано свойство float.

Посмотреть страницу

Посмотреть CSS

Врезка размещается в блоке incut, который объявлен плавающим. Ширина врезки указана в em, но можно было задать значение в процентах (например, width:30%).

Фокус с display:inline для IE (ссылка) не потребовался, потому что внешний отступ справа у блока incut задан нулевым для выравнивания его справа по одной вертикали с остальным содержимым BODY.

Код HTML (с сокращениями):

<BODY>
  <H1>Роботландия</H1>
  <DIV id="incut">
    <H2>Роботландский конь</H2>
    ...
  </DIV>
  <P>
Курс с таким названием вошёл...
  <P>
  ...
  <DIV id="footer">...</DIV>
</BODY>
           

Код CSS (с сокращениями):

#incut
{
  float:right;
  width:15em;
  padding:10px;
  margin:0 0 10px 10px;
  border:1px solid #638F7B;
  background:#fff2a6;
  font-family:"Trebuchet MS",sans-serif;
}
           

Вверх Горизонтальное меню

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

Вот так это выглядит в окне браузера.

На горизонтальное меню совсем не похоже, но стоит взять в руки CSS…

Меню — это список. Поэтому логично записать его в виде UL:

<UL class="menu">
  <LI>Начало
  <LI>Продукты
  <LI>Университет
  <LI>Ссылки
  <LI>Автор
</UL>
          

Так это выглядит в FireFox и Opera.

Так — в IE.

Посмотреть

Благодаря float:left элементы LI стали плавающими и примкнули друг к другу по горизонтали.

Однако налицо две проблемы: появилась горизонтальная прокрутка, и фон, заданный для UL, не охватывает элементы LI в браузерах FireFox и Opera.

Сформулируем правила CSS, которые превращают вертикальный список в горизонтальный:

.menu
{
  width:100%;
  margin:0;
  padding:6px;
  list-style:none; /* Убираем маркеры */
  background:#ffcb2d;
}
.menu LI
{
  float:left;
  display:inline; /* Уловка для IE */
  margin-left:1em;
  font-family:Arial, sans-serif;
  font-size:70%;
}
          

С прокруткой всё понятно. Мы указали 100% для ширины блока UL. Но это ширина без отступов и границ. Значит, общая ширина UL получается равной 100% + 12 пикселов (6 пикселов, заданные в padding с обеих сторон). То есть ширина UL больше ширины BODY на 12 пикселов — вот и включается прокрутка.

Вывод: если для блока определена ширина в 100%, нельзя для него задавать горизонтальные отступы и границу.

В нашем случае надо положить padding:0 (в дополнение к margin:0).

Но почему фон, заданный для UL, не охватывает элементы LI в браузерах FireFox и Opera?

На самом деле, эти браузеры ведут себя согласно стандартам, а ошибается как раз IE!

Блок UL находится в потоке, а его потомки LI удалены из потока свойством float:left. Блок UL оказался пустым. Мы бы вообще его не увидели, если бы не padding:6px. Вот эти 12 пикселов (6 сверху плюс 6 снизу), окрашенные в цвет фона, мы и видим по вертикали (ссылка).

Посмотреть страницу

Посмотреть CSS

Благодаря float:left, блок menu (это наш UL) стал охватывать своих плавающих потомков LI.

Отказ от горизонтальных отступов (padding:6px 0) убрал линейку прокрутки.

Добавим в правила для блока menu указание float:left и уберём внутренние горизонтальные отступы:

.menu
{
  float:left;
  width:100%;
  margin:0;
  padding:6px 0;
  list-style:none; /* Убираем маркеры */
  background:#ffcb2d;
}
          

Вверх Плавающие колонки фиксированной ширины

Рассмотрим типичный макет страницы с заголовочной частью, двумя колонками и подвалом:

HTML-код:

<BODY>
  <H1></H1> 
  <DIV id="content"></DIV> 
  <DIV id="sidebar"></DIV> 
  <DIV id="footer"></DIV> 
</BODY>
      

Зафиксируем для BODY такую ширину, чтобы страница отображалась без горизонтальной прокрутки в окнах шириной 800 пикселов.

Блоки H1 и footer оставим в потоке, а колонки (блоки content и sidebar) сделаем плавающими. Не забудем при этом для блока footer указать свойство clear:both, чтобы прекратить обтекание и обеспечить расположение подвала ниже обеих колонок.

Для content и sidebar не задаются внешние отступы и границы.

Общая ширина content: внутренний отступ (10) + ширина содержимого (480). Всего: 500.

Общая ширина sidebar: внутренний отступ (10) + ширина содержимого (220). Всего: 240.

Самое главное — аккуратно указать числовые значения ширины для всех блоков и не забыть про отличие коробочной модели IE (ссылка).

Определимся с общей шириной BODY: внешний отступ (10) + граница (1) + внутренний отступ (10) + ширина содержимого (740). Получается 762 пиксела без учёта внешних отступов и 782 с внешними отступами. Как правило, этого достаточно, чтобы не вызвать прокрутку в окне шириной 800 (остаток идёт на границы самого окна и линейку вертикальной прокрутки).

Проверка: 740 (ширина содержимого BODY) =  240 (общая ширина sidebar) +  500 (общая ширина content).

Теперь нетрудно написать стилевые определения:

HTML
{
  text-align:center; /* Центрирование BODY для IE5 */
  background:#F6F2E4; 
}

BODY
{
  /* Раскладка */
  margin:10px auto;  /* BODY по центру HTML */
  text-align: left;  /* Выравнивание текста слева */
  padding:10px;
  border:1px solid #638F7B;
  width:740px;  /* Для старых хороших браузеров */
  \width:762px; /* Обман для IE5 */
  w\idth:740px; /* Для новых хороших браузеров */  
  /* Шрифты    */
  font:small Georgia, serif;
  /* Цвета     */
  color:black;
  background:white; 
}

/* Заголовочная часть*/
H1
{
}

/* Общие свойства блока содержания и боковой панели */
#content, #sidebar 
{
  color:#2A3D34;
  padding:10px;
}

/* Содержание */
#content 
{ 
  float:left;
  background:#d4dff3;
  width:480px;  /* Для старых хороших браузеров */ 
  \width:500px; /* Обман для IE5 */
  w\idth:480px; /* Для новых хороших браузеров */ 
}

/* Боковая панель*/
#sidebar
{
  float:left;
  background:#fff2a6;
  width:220px;  /* Для старых хороших браузеров */ 
  \width:240px; /* Обман для IE5 */
  w\idth:220px; /* Для новых хороших браузеров */ 
}

/* Подвал */
#footer
{
  clear:both;
  padding:0 10px 10px 10px;
  white-space:nowrap;
}
      

Для блока sizebar задано float:left, но можно было бы задать и float:right — в данном случае нет никакой разницы.

Посмотреть

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

Колонки по определению должны иметь одинаковую высоту!

Проблема имеет решение под названием «ложные колонки» (ссылка).

Суть метода в следующем: для контейнера колонок задаётся фоновая полоска, которая замащивает блок по вертикали, «продлевая» тем самым, высоту колонок до конца контейнера. Высоты колонок, конечно, остаются прежними, но визуально они уравниваются.

В нашем случае контейнером колонок является блок BODY, что неудовлетворительно. Ведь если замостить BODY ложными колонками, в них попадут блоки header и footer, что совершенно не нужно.

Придётся колонки обернуть во вспомогательный блок wrapper (он станет контейнером колонок) и именно для него указать нужную фоновую полоску.

Посмотреть страницу

Посмотреть CSS

Вероятно, вы догадались, зачем блок wrapper сделан плавающим!

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

Изменения в HTML:

<BODY>
  <H1></H1> 
  <DIV id="wrapper"> 
    <DIV id="content"></DIV> 
    <DIV id="sidebar"></DIV> 
  </DIV>  
  <DIV id="footer"></DIV> 
</BODY>
        

Изменения в CSS:

/* Обёртка блоков  sidebar и content */
#wrapper
{
  float:left;
  background:url(pic/bg.png) repeat-y;
}
        

Понятно, что показанная методика работает при любом числе колонок. Для всех плавающих блоков задаём float:left, и они будут прилипать друг к другу слева на одной горизонтали. Самое главное — аккуратно задать размеры всем блокам так, чтобы сумма равнялась ширине области содержимого BODY (значению его свойства width).

Вверх Плавающие пропорциональные колонки

Сделаем обе колонки «резиновыми». Пусть они заполняют ширину текущего окна в отношении 70%:30%.

HTML-код:

<BODY>
  <H1></H1> 
  <DIV id="wrapper"> 
    <DIV id="content">
      <DIV class="wrap"></DIV>
    </DIV> 
    <DIV id="sidebar">
      <DIV class="wrap"></DIV>
    </DIV> 
  </DIV>  
  <DIV id="footer"></DIV> 
</BODY>
      

Блоки content и sidebar, как и ранее, обёрнуты контейнером wrapper с той же целью: создать ложные колонки в виде фона блока wrapper.

Кроме того, содержимое блоков content и sidebar погружено в блоки <DIV class="wrap"></DIV>. Зачем?

Так сделано потому, что мы не можем в этом макете задавать отступы (и границу) для блоков content и sidebar, как это делали в макете с фиксированной шириной колонок.

Пусть для content и sidebar задан padding:10px. Тогда общая ширина этих блоков станет 100%+40px. Места для плавающего блока sidebar справа от content нет, и он свалится вниз:

В самом деле, мы должны указать:

#content 
{ 
  float: left;
  width: 70%;
}
#sidebar
{
  float: left;
  width: 30%;
}
      

Если задать ещё и отступы, то они добавятся к общей ширине блоков, и сумма превысит ширину контейнера.

Поэтому блокам sidebar и content отступы не приписываются, а будут заданы для специально введённых блоков wrap, которыми обёрнуто содержимое блоков sidebar и content.

С учётом сказанного, записываем стилевые определения для нашего «резинового» макета:

BODY
{
  /* Раскладка */
  margin: 10px; 
  padding: 0;
  /* Шрифты    */
  font: small Georgia, serif;
  /* Цвета     */
  color: black;
  background: white; 
}
/* Заголовочная часть*/
H1
{
}
/* Обёртка блоков content и sidebar*/
#wrapper
{
  float: left;
  width: 100%;
}
/* Общие свойства боковой панели и содержания */
#sidebar, #content
{
  color: #2A3D34;
}
/* Отступы для содержимого блоков sidebar и content */
.wrap
{
  padding:10px;
}
/* Содержание */
#content 
{ 
  float: left;
  width: 70%;
  background: #d4dff3;
}
/* Боковая панель*/
#sidebar
{
  float: left;
  width: 30%;
  background:#fff2a6;
}
/* Подвал */
#footer
{
  clear: both;
  padding: 0 10px 10px 10px;
}
      

Посмотреть

Отметим две неприятности, связанные с браузером IE.

Первая связана с тем, что IE не умеет считать.

Предположим, ширина блока wrapper равна 1000 пикселам. В этом случае IE не подкачает, он определит 700 пикселов (70%) для блока content и 300 пикселов (30%) для блока sidebar. В сумме получится как раз 1000 пикселов, никаких проблем нет.

Пусть теперь ширина блока wrapper равна 999 пикселам. Получаем: 70% от 999 равно 699.3 и, соответственно, 30% от 999 равно 299.7. Нормальные браузеры получают 699 и 300 пикселов, IE всегда округляет в большую сторону. У него получается 700 и 300. Для блока sidebar места справа от content не хватает, и он сваливается вниз.

Неприятности можно избежать, если для второго блока задать ширину, равную не 30%, а только 29.9%.

Существуют и другие решения, одно из них описано в заметке Владимира Токмакова «Борьба с прыгающими блоками в IE» (ссылка). Это решение рекомендуется к использованию в практикуме 2 к этому разделу и проекте 4 темы 2. Оно также использовано в кодах примера 2.

Вторая неприятность связана с тем, что в узких окнах разметка рушится: блоки начинают наползать друг на друга, а в IE блок sidebar опять скачет вниз.

Для нормальных браузеров решение очень простое — нужно задать для BODY свойство min-width. Для IE приходится идти на хитрости при помощи функции expression, которую понимает только IE (IE7 уже научили понимать свойства min-width и max-width).

Таким образом, получаем следующие правки в стилевых определениях:

BODY
{
  /* Раскладка */
  margin: 10px; 
  padding: 0;
  min-width: 640px;
  width: expression(documentElement.clientWidth < 700 ? '700px' : 'auto'); 
  /* Шрифты    */
  font: small Georgia, serif;
  /* Цвета     */
  color: black;
  background: white; 
}
/* Содержание */
#content 
{ 
  float: left;
  width: 70%;
  background: #d4dff3;
}
/* Боковая панель*/
#sidebar
{
  float: left;
  width: 29.9%;
  background:#fff2a6;
}
      

Значения 700px для IE и 640px для других браузеров подобраны экспериментальным путём.

В IE был установлен самый крупный шрифт (в меню Вид/Размер шрифта), затем уменьшалась ширина окна, пока блок sidebar не стал сваливаться вниз.

Займёмся теперь фоновой полоской, создающей ложные колонки.

Суть метода в особенностях вывода фоновой картинки, положение которой задано в процентах (ссылка).

Общая длина фоновой полоски делается настолько большой, например, 3000 пикселов, чтобы она смогла покрыть ширину окна на огромном мониторе.

Полоска делится разными цветами в таком же процентном отношении, что и наши колонки (70%:30%). То есть для первого цвета в нашем случае отводится 900 пикселов, а для второго — 2100.

Для вывода полоски используется стилевое правило:

/* Обёртка блоков  sidebar и content */
#wrapper
{
  background:url(pic/bg.png) 70% top repeat-y;
}
          

Две вертикали, одна на элементе, другая на картинке, проведённые в 70% от левого края (соответственно, элемента и картинки), будут совпадать при любой ширине элемента wrapper.

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

Посмотреть страницу

Посмотреть CSS

Окончательный вариант макета показан на рисунке, но важно посмотреть, как страница ведёт себя при изменении ширины окна браузера.

Загрузите макет и проверьте его работу в окнах разной ширины.

Описанный метод легко обобщить на любое число колонок.

Например, для трёх колонок задаём два обёрточных блока и две фоновые картинки: первую для блока wrapper1, содержащего первую колонку и блок wrapper2, вторую — для блока wrapper2, содержащего вторую и третью колонки.