1. Свойство float

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

Формальное описание свойства float выглядит очень просто: при значении left элемент-носитель свойства прижимается к границе слева, а остальные элементы обтекают его справа, при значении right — наоборот, “прилипание” справа, обтекание слева.

Однако, алгоритм работы свойства float содержит много тонкостей, поэтому стоит рассмотреть его в подробностях.

float
Значения: left | right | none | inherit
По умолчанию: none
Область применения: все элементы
Наследование: нет

align=left

align=right

CSS-cвойство float обобщает действие атрибутов align=left и align=right, которые работают только для картинок (и таблиц в некоторых браузерах), на все элементы HTML.

Картинка (элемент IMG) с атрибутом align=left прижимается к левому краю, а другие элементы обтекают её справа. Картинка с align=right, наоборот, прижимается справа, а обтекание происходит слева.

Рассмотрим в деталях поведение элемента с заданным для него свойством float, но прежде введём два определения.

Назовём контейнером первый предок элемента в иерархическом дереве элементов, который является блоком.

Строчный элемент STRONG является родителем элемента EM, но не является его контейнером. Первый блок-предок — P (дедушка), именно он и является контейнером для EM.

В качестве примера рассмотрим код:

<BODY>
  <DIV>
    <P>
В этом абзаце внутри 
<STRONG>сильного выделения 
находится обычное 
<EM>выделение</EM></STRONG>.
    </P>
  </DIV>
</BODY>
          

Контейнером элемента EM является блок P.

Будем называть элемент с заданным свойством float:left или float:right плавающим элементом (в ходу ещё один термин: перемещаемый элемент).

Вверх Правила перемещения

Плавающий элемент становится блоком

Плавающий элемент автоматически становится блоком, даже если он был строчным элементом.

Элемент EM превращается в блок и сдвигается к левой границе своего контейнера P. Остальная часть абзаца обтекает плавающий элемент справа.

Как вы помните (ссылка), внешние отступы строчных элементов работают только по горизонтали. Здесь свойство margin:10px действует со всех сторон, что типично для блока.

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

HTML-код:

<P>
В этом предложении внутри 
<STRONG>сильного выделения 
находится обычное 
<EM>выделение</EM></STRONG>. 
Это второе предложение, оно 
завершает абзац.
</P>
          

CSS-код:

EM
{
  float:left;
  background:#fff2a6;
  padding:10px;
  margin:10px;
  border: 1px solid black;
}
          

Практический вывод: если для строчных элементов (таких, как EM, STRONG, CITE, DFN, A, IMG, SPAN и других) задаётся свойство float:left или float:right, то для них автоматически устанавливается свойство display:block, и нет необходимости в явной установке этого свойства.

Более того, если мы даже укажем для плавающего элемента свойство display:inline, оно будет проигнорировано.

Позиция по горизонтали

Плавающий элемент со значением left прижимается к левому краю, а плавающий элемент со значением right — к правому краю своего контейнера.

Все элементы имеют внешние и внутренние отступы, а также границу. Возникает вопрос: какой именно частью плавающий элемент прижимается к своему контейнеру? И к какой именно части контейнера?

Действует правило:

Плавающий элемент примыкает к внутреннему краю своего контейнера своим внешним краем.

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

То есть внешний край внешнего отступа плавающего элемента соприкасается с внутренним краем внутреннего отступа контейнера.

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

Такое поведение означает, что плавающий элемент не может выйти за пределы области содержимого своего контейнера.

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

Позиция по вертикали

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

Элемент был блочным

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

HTML-код:

<BODY>
  <P>Первый абзац. Он расположен в коде до плавающего элемента.
  <P class=float>Второй абзац. Это плавающий элемент.
  <P>Третий абзац. Он расположен в коде после плавающего элемента.
  <P>Четвёртый абзац. Он расположен в коде последним.
</BODY>
      

CSS-код:

BODY { padding:0; margin:0;}
P /* Правила для всех абзацев */ 
{
  background:cyan;
  padding:10px;
  margin:10px;
  border: 1px solid black;
}
P.float /* Дополнения для абзаца float */
{
  float:left;
  width:160px;
  background:#fff2a6;
}
      

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

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

Видим на иллюстрации, что расстояние от границы плавающего блока до границы первого абзаца равно не 10 пикселов, а 20. Внешний отступ первого абзаца (10 пикселов) сложился с внешним отступом плавающего блока (10 пикселов).

В этом месте придётся остановиться, чтобы сделать замечание IE.

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

Так отображается, приведённый выше код, в самом популярном на сегодня браузере Интернета.

Видим, что внешний отступ слева удваивается (у плавающих элементов с float:right будет удваиваться внешний отступ справа).

К счастью, этот баг излечивается очень просто — если для плавающего элемента записать display:inline, IE “исправится”.

Элемент был строчным

Рассмотрим поведение плавающего элемента, который был строчным.

Стандарт формулирует здесь два правила.

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

Второе правило. Плавающий элемент должен располагаться максимально высоко, не нарушая при этом первое правило.

Таким образом, если элемент находится в первой строке, то верх образованного из него плавающего элемента должен совпадать с верхом первой строки. Так и происходит на практике.

Рассмотрим теперь поведение элемента, расположенного не в первой строке.

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

Если строчный элемент стал плавающим, eго верх должен совпадать с верхом строки в которой он ранее находился.

На практике браузеры, либо всегда выводят плавающий элемент на строку ниже (IE, FireFox), либо и так, и так, в зависимости от того, есть ли в текущей строке место (Opera).

Путь страница задана следующим кодом.

HTML-код:

<BODY>
  <P>
В этом предложении внутри <STRONG>сильного выделения находится 
обычное <EM>выделение</EM></STRONG>. Это второе предложение, оно 
завершает абзац.
  </P>
</BODY>
      

CSS-код:

BODY { margin:0; padding:0; }
P { margin:0; padding:0; background:cyan; }
EM
{
  float:left;
  margin:0; padding:10px;
  width:100px;
  background:#fff2a6;
  border: 1px solid black;
}
      

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

Opera может вывести элемент и во вторую строку.

Всё выше сказанное относится к элементам с нулевыми и положительными внешними отступами. Отрицательные значения margin-top заставляют элемент подниматься выше обычного положения и даже перекрывать расположенные там элементы.

Поведение плавающего элемента

Изымается ли плавающий элемент из потока? Да, конечно.

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

Если элемент был строчным, он превращается в блок и покидает своё строчное место (удаляется из строки).

Плавающий элемент располагается над потоком, но не перекрывает содержимое (хотя перекрывает фон блоков в потоке).

Плавающий элемент поднимается над потоком. Он смещается по горизонтали к краю области содержимого своего контейнера. Блоки, следующие за ним, подтягиваются вверх и занимают освободившееся место в потоке.

Однако плавающий элемент не перекрывает содержимое других блоков. Содержимое начинает обтекать плавающий блок со свободной стороны.

Вверх Прекращение обтекания

Плавающий блок прижимается к границе контейнера, а элементы потока обтекают его. На практике часто бывает необходимо прекратить обтекание в каком-то месте потока, чтобы начать, например, новый раздел. Для прекращения обтекания используют свойство clear (аналог атрибута clear в теге BR).

clear
Значения: left | right | both | none | inherit
По умолчанию: none
Область применения: блочные элементы
Наследование: нет

Блок, в котором задано свойство clear опускается, пока не окажется ниже плавающего элемента.

Свойство clear позволяет прекратить обтекание:

  • clear:left — прекращает обтекание элементов float:left;
  • clear:right — прекращает обтекание элементов float:right;
  • clear:both — прекращает обтекание элементов float:left и float:right.

Свойство clear применимо только к блочным элементам (например, нельзя использовать <BR style="clear:left">, так как элемент BR — строчный).

Значение clear:none (оно работает по умолчанию) допускает обтекание с любой стороны. Это значение, как и float:none, существуют для того, чтобы иметь возможность обеспечить обычное поведение элемента (при помощи скрипта, например).

Вверх Когда плавающих элементов много

Плавающие блоки не перекрывают друг друга и не перекрывают содержимое потока (если только у них не заданы отрицательные внешние отступы).

Пусть плавающий блок 1 идёт в коде раньше плавающего блока 2. Блок 2 не может занимать на экране положение выше блока 1, но располагается максимально высоко.

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

Если места нет, плавающий блок, идущий в коде дальше, смещается ниже.

Следующие в коде друг за другом плавающие блоки разного типа (float:left и float:right) ведут себя аналогично: пытаются уместиться на одной горизонтали.

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

Вверх Плавающий внутри плавающего

Пусть в потоке один блок вложен в другой:

<DIV id="block1">
  <DIV id="block2">
    ...
  </DIV>
</DIV>
          

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

Сделаем вложенный блок плавающим:

#block2 {float:left}
          

Видим “странную” картину: блок-родитель “схлопнулся” по вертикали до размеров своих рамок и отступов.

Плавающий элемент не выходит за пределы своего плавающего родителя (если только не заданы отрицательные внешние отступы).

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

#block1 {float:left}
#block2 {float:left}
          

Рассмотрены самые важные правила поведения плавающих блоков, теперь можно перейти к практической части.