Веб-разработка
May 9

Блочная модель, поток и сетка на float — Тренажёр HTML Academy

В прошлых блоках мы научились работать с отдельными элементами сайта и знаем как детально их стилизовать. Теперь, наконец, переходим к формированию полной картины — построение так называемых «сеток», взаимное расположение крупных блоков сайта.

В этой части разберёмся как работают блоки и общий размер бокса, чем отличаются разные типы элементов. Разберёмся с потоком и как им управлять, как строить сетки на плавающих float элементах и как они ломают поток. А еще разберемся со строчно-блочными элементами!

Блочная модель документа

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

Все элементы вёрстки вписаны в прямоугольные области — их называют боксами. Боксов существует несколько типов, за тип бокса отвечает свойство display — мы уже встречались с ним несколько раз.

Однако, основных типов боксов два — блочный бокс display: block и строчный бокс display: inline, они ставятся по умолчанию большинству элементов.

Блочные боксы

Блочные боксы display: block; по умолчанию — это, например, заголовки <h1>, параграфы <p> и отдельно «просто блок» <div>, имеют ряд важных особенностей:

  1. Занимают всё доступное пространство по горизонтали;
  2. До и после бокса существует перенос строки;
  3. Можно задать ширину, высоту, внешние и внутренние отступы.

Таким образом, по умолчанию все блочные боксы занимают всю ширину родительского элемента или экрана и идут друг за другом, сверху вниз.

Блочным боксам можно явно задать размер с помощью свойств ширина width и высота height, например, в пикселях px, в процентах % или указать значение по умолчанию auto. Однако, важно заметить — перенос строки при этом никуда не денется, бокс будет один на строке.

Также блочному боксу можно задать внутренние padding и внешние margin отступы во все стороны и еще можно задать рамку border. Мы уже разбирали эти свойства, поэтому не будем повторно останавливаться.

Все эти свойства вместе с размером самого бокса формируют общий размер области занимаемый блочным боксом:

Значения всех "размерных" свойств складываются.

Это так называемая «Стандартная блочная модель», но есть несколько особенностей связанных с внешними отступами margin по вертикали, то есть с отступами сверху и снизу.

Первая особенность это «схлопывание» — вертикальный отступ margin между двумя боксами будет равен максимальному, а не их сумме:

Отступ не сумма отступа двух боксов 80px, а иаксимальный из двух 50px.

Вторая особенность это «выпадение» внешнего отступа margin дочернего элемента — всё по той же причине, выбирается максимальный внешний отступ, при этом контент родителя игнорируется:

Отступ сверху будет 50px от дочернего жлемента, а не 30px от родительского.

Чтобы избежать «выпадения» достаточно указать внутренний отступ padding родительскому элементу, тогда вступит в силу правило очерёдности стандартной блочной модели и внешний отступ margin дочернего элемента будет складываться с внутренним отступом padding родительского:

Отступы по горизонтали работает без схлопывания и выпадения.


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

По умолчанию значение width: auto; подстраивает ширину содержания в зависимости от отступов так, что бы общая ширина бокса, то есть сумма ширины и отступов, занимала 100% ширины родительского элемента.

Если же боксу указать width: 100%;, то мы по сути скажем «ширина содержания = ширине родителя» без учета отступов, из-за чего область занимаемая боксом выпадет из ширины родительского контейнера:

Разница между auto и 100%

Это важно учитывать, но к счастью, этим можно еще и управлять — с помощью свойства box-sizing. Имеет всего два значение — content-box по умолчанию, работает стандартная блочная модель и значение border-box, которое изменяет режим расчета ширины элемента, теперь в width учитывается и ширина содержания и отступы с рамкой.

Строчные и другие боксы

Строчные боксы display: inline; по умолчанию — это, например, ссылки <a>, различные выделения <em>,<strong> и так далее, и «просто строка» <span>. Строчные боксы ведут себя абсолютно по другому:

  1. Размер строчного бокса зависит от содержания, задать размеры width и height бокса через CSS по умолчанию нельзя;
  2. До и после бокса нет переноса строки — все строчные боксы идут друг за другом в строке, могут разрываться и переносится на новую строку;
  3. Можно задать только горизонтальные отступы margin и padding, на вертикальные реагируют, но не «отталкивают» соседние элементы;
  4. Реагируют на рамки border, но тоже не отталкивают элементы по вертикали, из-за чего рамки могут наложиться на контент соседних элементов.

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

Например, рассмотрим гибридный тип бокса — его, наверное, можно назвать строчно-блочный тип display: inline-block;, он имеет свои интересные свойства:

  1. Ему можно задать размер через width и height, а также рамки border и отступы padding и margin, которые он корректно воспринимают по всем направлениям, как блочный бокс;
  2. По умолчанию ширина бокса зависит от содержания как у строчного бокса, а не растягивается на всю ширину контейнера;
  3. До и после такого бокса нет переноса строки, но в отличие от строчного бокса нет разрыва элемента при переносе на новую строку;
  4. Выравниваются вертикально как строчные боксы, выравниванием можно управлять с помощью свойства vertical-align.

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

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

Остальные свойства такие же — перенос строк до и после и можно применять размерные свойства и отступы с рамкой. Как можно заметить — этот тип бокса эквивалент тегу <table>.

Соответственно, существует тип бокса строка таблицы display: table-row;, который эквивалентен тегу <tr> и тип бокса ячейка таблицы display: table-cell;, который эквивалентен тегу <td>.

Свойства этих боксов аналогичны их оригинальным тегам и к ним применяются специфичные для таблиц свойства, например, border-collapse.


Особняком стоит тип display: none;, то есть "никакой" — полностью скрывает элемент, он не отображается и не занимает места. С его помощью делают разные всплывающие меню, подсказки, вкладки и дофига чего еще.

В тренажёре нас еще знакомят с похожим свойством visabiltiy: hidden;, которое тоже скрывает элемент визуально, но он занимает место. С его помощью семантически верно задаются заголовки всем секциям.

Ну и наконец звёзды современного веба — флексбокс disaplay: flex; и гриды display: grid;. Но про них мы поговорим отдельно и очень подробно.

Испытания

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

Первое испытание наглядно показывает как работает стандартная модель, отступы, рамки и размеры:

Второе испытание развивает тему и показывает работу box-sizing. Здесь, кстати, у меня случился BSoD — я сначала задал padding внешнему блоку с контуром.

Третье испытание — это полный фарш всех типов боксов. И строчно-блочный, и табличные и none.

Сетки на float и inline-block

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

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

Поток и float

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

Свойство float позволяет изъять указанный элемент из привычного потока и прижать к указанной в значении свойства стороне родительского элемента — left или right.

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

float: none; - значение по умолчанию для всех элементов

Изъятому или «плавающему» элементу можно задать размерные свойства width и height, отступы margin и padding и рамку border. В целом, такой элемент похож на строчно-блочный тип бокса, только для не «плавающих» блочных элементов он, как бы, не существует, но для текста и строчных элементов вполне ощутим. Благодаря этому необычному свойству можно добиться некоторых странных, но интересных эффектов:

Честно говоря, не знаю когда это может пригодиться.

Между собой плавающие элементы взаимодействуют практически также как строчно-блочные inline-block, находясь при этом в своем, отдельном потоке. Именно используя эту особенность можно создавать сетки сайта на float.

Для примера построим простейшую сетку из хедера и футера, занимающих всю ширину контейнера, и между ними — основное содержимое страницы разделённое на три колонки с помощью float.

Используем для этого схему выше, где мы уже задали первой колонке float: left;. Чтобы превратить боксы в колонки, зададим им float и размеры:

.column1 {
  float: left; /* прижат к левому краю родителя */
  width: 65px;
  min-height: 50px;
  margin-right: 9px; /* отступ справа */
}

.column2 {
  float: left; /* прижат к боксу column1 c отступом */
  width: 80px;
  min-height: 50px;
}

.column3 {
  float: right; /* прижат к правому краю */
  width: 65px;
  min-height: 50px;
}

Распорка и псевдораспорка

Сразу видно проблему — футер игнорирует наше построение и заполняет пространство «под» колонками, так как ему диктует его поток. На этот случай есть свойство clear которое запрещает обтекание элемента или, иными словами, учит блочные элементы «видеть» плавающие.

Свойство clear имеет четыре значения — none по умолчанию, left не обтекать слева, right не обтекать справа, both не обтекать с обеих сторон. Задав футеру свойство clear: both; мы «покажем» ему и те колонки, что прижаты влево и ту, что прижата вправо.

Уже вполне себе сетка

Понятно, что не всегда страница ограничивается только одной секцией с тремя колонками и все футером не исправишь. Для этого умные верстальщики решили использовать «распорки» — элемент созданный только для свойства clear: both; что бы разделять плавающие элементы на секции.

Распорку можно сделать в виде пустого <div> элемента внутри контейнера после плавающих элементов или поступить изящнее и задать контейнеру с колонками псевдоэлемент ::after с распоркой!

Логика переносов float

В тренажёре этому уделено пару уроков и сказано, что логика переноса бокса на новую строку не очень очевидна. Это и правда так, сначала можно сломать мозг, так как логика сильно отличается от обычного потока, но она есть.

Когда строители строят здание их точка отсчета это поверхность земли — они строят снизу вверх, этаж за этажом. Стандартный «поток» строительства.

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

Свойство float же, можно сказать, немного меняет направление «потока» для указанных элементов. И нет, не слева на право или наоборот, справа на лево — так может показаться из-за значений left и right.

Эти значения именно корректируют поток в свою сторону и таким образом стандартный поток «сверху вниз» меняется на:

  • «Из левого верхнего угла направо и вниз» для float: left; и
  • «Из правого верхнего угла налево и вниз» для float: right;.

Рассмотрим на примере одного из уроков и нарисуем поверх элементов направления потока. Возьмем три блочных элемента с float: left; и будем постепенно трансформировать их.

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

Теперь увеличим первый блок по высоте и внезапно произойдет нечто отличное от стандартного потока:

Последний блок переместился под второй из-за того, что первый его будто выдавил, хотя в стандартном потоке он бы так и остался снизу. Здесь вступает в силу изменённое направление потока! Мы прижали к левому краю не просто элемент, а поток для всех элементов со свойством float: left;.

Первый блок занял, как бы, диагональную строку, перпендикулярную направлению потока, который не «сверху вниз», а начинается именно из угла. Если по направлению потока есть свободное место для какого-то элемента, то они его заполнят. А если нет, например, если третий блок станет шире?

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

В этом случае сработает перенос, при этом последующие блоки не займут пустоту, так как поток направлен в том числе всё еще вниз и порядок блоков всё еще важен.

Все те же правила сработают и для float: right; только поменяется направление потока, а также не стоит забывать про блочную модель — при переносах учитывается общий размер бокса, включая отступы и рамку:

Эта часть из разряда «мне в бошку надуло», то есть это не часть тренажёра, там нет ничего про изменение потока.

Сетки на inline-block

Я уже пару раз выше писал, что плавающие элементы ведут себя очень похоже на строчно-блочные элементы. Но есть у них одна очень важная разница — собственно, стандартное направление потока.

Строчно-блочные элементы заполняют строку и при переносе остаются ниже предыдущих элементов независимо от их высоты или отступов. То есть ведут себя в этом плане как строчные.

Наглядно, разница между типами элементов:

Не ошибка, float именно left - блоки 7 и 8 расположены так, потому что 6й "умещается" на предыдущей строке

С одной стороны со строчно-блочными проще и это действительно так, если колонки одинаковой высоты. Но у строчно-блочных есть еще один очень неприятный нюанс.

Они воспринимают пробелы. Даже те, что есть в коде. Как мы знаем без тега <pre> все лишние пробелы сокращаются до одного, но даже этот один пробел между элементами строчно-блочные видят и воспринимают.

То есть даже если строчно-блочным задать нулевые отступы — между ними всё равно будет отступ в виде пробела, размер которого зависит от размера шрифта объявленного для этого блока.

Вариантов несколько:

  • Убрать все пробелы, но тогда вёрстка будет нечитабельна;
  • Задать нулевой размер шрифта контейнеру, а самим элементам переназначить на нормальный;
  • Задать элементам отрицательный отступ.

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

Испытания

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

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

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

Третье испытание самое легкое из этой части. Нужно стилизовать строчно-блочные элементы галереи. Испытание долгое, но простое.


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

Огромное спасибо за внимание! Хотелось бы мне ускорить написание, но пока не могу осилить быстрее одной статьи раз в 4-5 дней.

Ссылки на предыдущие статьи по HTML Academy:

Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float <- Вы здесь
Гибкие флексбоксы display: flex
Удобные сетки на гридах display: grid
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские
...

Остальные статьи можно посмотреть у меня на главной странице блога.

Также мои соц. сетки, которые я продолжаю вести:

Мой Twitter
Мой Telegram
Мой Паблик ВК

Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!