CSS Puns & CSS Jokes by Saijo George

Магия CSS. Глава 2. Раскладка

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

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

block—Моя ширина ограничена моим родителем. На меня влияют свойства width и height. Моя высота зависит от моего контента.

inline — Моя ширина и высота определяются моим контентом и значения свойств width и height не влияют на меня. Думайте обо мне как о слове в параграфе.

inline-block — Я такой же как block, но моя ширина зависит от моего контента.

Пример:

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

* {
background: #eee;
border: .125em solid;
margin-bottom: .5em;
padding: .5em
}
Все ширины блоков 100%
Все ширины блоков 20%

Пример призван проиллюстрировать разницу между блоками inline и inline-block. Блоки inline отображают padding, равный 0.5em и border размером 0.125em. Но только слева и справа (не сверху и снизу) это влияет на их расположение. В то же время inline-block располагается в макете с учетом всех отступов и границ. Так же себя ведут и элементы block.

Обратите внимание, что при установке значения 20% для свойства width у всех элементов, блочные элементы не становятся в один ряд. За исключением случаев с float, блочные элементы не допускают соседей в свой горизонтальный ряд.

Секции с горизонтальной прокруткой могут вызвать проблемы. К счастью, в этом нам может помочь inline-block.

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

body {    background: red /* I know it’s weird to make the whole page red, but sometimes it’s just what you have to do.... */}

Примечание переводчика: смотрите пример на странице оригинала. При прокрутке влево станет видно, что окрашивается фон не всей строки.

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

Добавив inline-block, который обернет все строки, мы получаем сколь угодно длинный скрол и строки (по прежнему display: block) будут чувствовать ширину именно оборачивающего элемента. А ширина элемента-оболочки в свою очередь занимает весь размер блока кода, включая область скролла, потому что ширина у inline-block зависит от контента — в нашем примере от самой длинной строки.

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

Таблицы совершенно сумасшедшие и в Главе 3 мы рассмотрим их более детально. Но из уважения к раскладке, думайте о таблицах как о inline-block элементах с одной только особенностью: дети table-cell (ячейки) могут выравнивать свой контент вертикально.

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

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

Нет ничего проще, чем вертикальное центрирование с использованием таблиц.

Но если вы используете таблицы только для этих целей (и вы не выводите данные при помощи tabular-data), вам следует использовать другой тип элементов (например div). И установите этому элементу свойство display по значением table, чтобы сымитировать поведение таблицы.

<style>
.vertical-outer {
display: table;
height: 10em
}

.vertical-inner {
display: table-cell;
vertical-align: middle
}
</style>

<div class="vertical-outer">
<div class="vertical-inner">
<p>I’m so centered it’s not even funny.</p>
</div>
</div>

Вот и все!

Честно сказать, отцентрировать что-то по вертикали, когда высота известна — тривиальная задача. Задайте position для элемента, установите одинаковые значения для top и bottom (0 (ноль) сгодится), задайте желаемую высоту и пропишите значение auto для margin-top и margin-bottom.

В основном text-align позволяет выровнять текст, дочерние inline и inline-block элементы по правому/левому краям, по центру или установить значение justify (вы понимаете о чем я, если когда-нибудь использовали WYSIWYG редактор).

Теперь немного магии.

С тех пор как поведение inline-block элементов стало более или менее похоже на поведение текста, мы получили возможность использовать text-align: justify для списка строчных блоков с целью создания сетки.

<style>
.grid {
border: .125rem solid;
text-align: justify;
font-size: 0;
padding: 4% 4% 0 4%
}

.box {
font-size: 1rem;
display: inline-block;
background: #eee;
border: .125em solid;
width: 30%;
padding: 2%
}

/* All but the last 3 boxes */
.box:nth-last-child(n+5) {
margin-bottom: 4%
}

.break {
display: inline-block;
width: 30%;
height: 0
}
</style>

<div class="grid">
<div class="box">Column</div>
<div class="box">Column</div>
<div class="box">Column</div>
<div class="box">Column</div>
<div class="box">Column</div>
<div class="box">Column</div>
<div class="break"></div>
</div>
Интерактивный пример по ссылке

text-align: justify позволяет сохранить сетку даже при условии изменения ширины блоков.

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

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

Правда на сегодняшний день, с тех пор как inline-block поддерживается повсеместно, нет особых причин для использования float. Мы оправдываем его только потому, что это “карта в рукаве”, но вам следует знать, как отменить его действие, перебить его. Но пока не переживайте особо по этому поводу.

Вы можете прочитать об отношениях между display, position и float в спецификации CSS3 от W3.

Хах, вот тут и начинается настоящее веселье.

Элемент считается “спозиционированным”, если значение свойства position отличается от static.

Когда элемент позиционируется, его положение начинает зависеть от значений свойств top, bottom, left и right, написанных среди его правил.

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

Значения у свойства position могут быть следующими:

static — Значение по умолчанию. Свойства позиционирования top, bottom, right и left игнорируются.

absolute — Элемент будет сдвинут со своей естественной позиции в раскладке и спозиционирован относительно своего ближайшего спозиционированного родителя при помощи свойств позиционирования.

fixed — Элемент будет сдвинут со своей естественной позиции в раскладке и его позиция будет высчитываться от края окна. На мобильных устройствах с зумом поведение может быть непредсказуемым.

relative — В отличие от absolute или fixed, элемент остается на своем естественном месте в раскладке и свойства top, right, bottom и left только выталкивают его с его естественной позиции.

Эти описания могут сбивать с толку, так что мы остановимся на некоторых важных моментах:

  • absolute и fixed элементы не являются частью нормальной раскладки документа. Изменение их размеров влияет только на их дочерние элементы. Существует тонкое исключение из этого правила: абсолютно спозиционированные элементы могут создать полосу прокрутки (по направлению расположения контента; по умолчанию вправо или вниз) и уже это может повлиять на расположение других элементов на странице.
  • static и relative элементы являются частью раскладки. Изменение их размеров влияет и на их соседей.
  • Если подтолкнуть элемент со значением relative при помощи top, right, bottom или left, это не повлияет на соседние элементы. Соседи ведут себя так, как если бы этот элемент никогда не сдвигался со своего первоначального положения. Исключение с прокруткой действует и здесь.
  • Так называемый относительный (relative)элемент не должен сбивать с толку, потому что дочерние элементы позиционируются «относительно» него. Скорее такое название описывает, что вы можете сдвинуть элемент «относительно» его исходного положения.

А теперь еще немного магии.

Позиционирование дочерних элементов относительно внешней стороны устроено немного сложнее.

Наивным подходом является задание отрицательных значений для свойств позиционирования.

Например:

.parent {
position: relative;
text-align: center;
padding: 1.25em;
background: #eee
}

.child {
position: absolute;
height: 2.5em;
top: -2.5em;
right: 0;
line-height: 2.5em;
background: #444;
color: #fff;
padding: 0 .625em
}

Обратите внимание на следующие две строки CSS:

height: 2.5em;
top: -2.5em;

Эта часть не идеальна, поскольку нарушает принцип DRY (“Не повторяйся”) и потому что мы должны указать жесткую высоту. Когда это возможно, лучше избегать указания значения высоты в CSS. Чем больше элементов будут иметь возможность подстраивать свою высоту под количество контента, тем лучше. Это делает вашу верстку более гибкой, она предусматривает больше сценариев использования и снижается вероятность возникновения ошибок в будущем.

Что же нам следует сделать в нашем случае? Использовать значение 100%.

Вместо того чтобы двигать ребенка при помощи отрицательного значения свойства top, сдвиньте его на 100% от нижней границы (bottom). Теперь наш пример можно переписать следующим образом:

.parent {
position: relative;
text-align: center;
padding: 1.25em;
background: #eee
}

.child {
position: absolute;
bottom: 100%;
right: 0;
background: #444;
color: #fff;
padding: .625em
}

Обратите внимание на то, как в этом варианте мы смогли опустить свойства line-height и padding, поскольку размеры дочернего элемента теперь зависят от его контента, а не наоборот.

Эта тема, безусловно, достойна отдельной главы. Трансформации находятся в той области, где реально много магии. Но прямо сейчас обратите внимание на факт, что, к сожалению, трансформированные элементы ведут себя как позиционированные, даже если их позиция по факту является статической (static). Зафиксируйте это в памяти иначе в какой-то момент это выжжет вам мозг.

  1. Relationships between display, position, and float
  2. Un-fixing Fixed Elements with CSS Transforms

Нашли ошибку? Воспользуйтесь функцией Private notes: выделяете текст с ошибкой, нажимаете на символ замка в появившемся дудле и оставляете свой комментарий. Спасибо!

Перевод главы из сборника The magic of CSS by Adam Schwartz
Настоятельно советую обратится к первоисточнику. Он прекрасен!

Frontend-дева. Верстаю, пишу и перевожу статьи, менторю, выступаю. Поддержать переводы: https://www.tinkoff.ru/sl/2QSPTULCQcC

Frontend-дева. Верстаю, пишу и перевожу статьи, менторю, выступаю. Поддержать переводы: https://www.tinkoff.ru/sl/2QSPTULCQcC