Original article: Digging Into The Display Property: The Two Values Of Display

Мы много говорим о Flexbox и CSS Grid Layout, однако эти методы по существу являются значениями display, — "рабочей лошади", которая часто не получает особого внимания. Рейчел Эндрю (Rachel Andrew) раскрывает детали и ньюансы display в серии своих статей.
Flex или Grid макеты всегда начинаются с основы — объявления свойства display: flex или display: grid. Эти два метода являются значениями CSS свойства display. Мы не особо много говорим об этом свойстве, обычно концетрируясь на его значениях — flex или grid, однако, в свойстве display есть очень важные для понимания моменты, в том числе его правильное определение, которые гораздо упростят вашу жизнь при использовании CSS.
В этой статье, первой из серии статей на эту тему, я рассмотрю как задаются значения display в спецификации третьего уровня (Level 3 specification) по сравнению с тем, как мы определяли display в раниих версиях CSS. Несмотря на то что это может поначалу показаться необычным для тех, кто довольно давно работает с CSS, я считаю эти изменения действительно помогают понять, что именно происходит с элементом, когда мы меняем значение его свойства display.
Блоковые и строчные элементы
Самое первое правило, которому мы учим новичков в CSS, — это концепция блоковых и строчных элементов. Мы объясняем, что некоторые элементы на странице имеют display: block и поэтому имеют определенные функции: они растягиваются в строчном направлении и занимают все свободное пространство, они начинаются с новой строки, мы можем задавать для них ширину, высоту, внешние и внутренние отступы, и эти свойства зрительно отделят их от других элементов на странице.
Также мы знаем, что некоторые элементы имеют display: inline. Строчные элементы подобны словам в предложении: они не преносятся на новую строку, отедляют себя от других элементов одним пробелом, и, если добавить к ним отступы, они не оттолкнут от себя другие элементы, хотя отступы и будут визуально заметны.
Поведение блоковых и строчных элементов является фундаментальным понятием в CSS, а также гарантией того, что правильно размеченный HTML будет по умолчанию читаемым. Такую разметку страницы называют "Блоковый и строчный макет" или "Стандарный порядок", благодаря тому, что именно так элементы сами естественно располагаются на странице, если к ним больше не применяется никаких правил.
Внешние и внутренние значения свойства display
Мы разобрались в блочных и строковых элементах, но что произойдет если мы установим для элемента значение display: grid? Это что-то абсолютно другое? Если мы посмотрим на элемент, к которому мы применили display: grid, с точки зрения родительского элемента в макете, то он ведет себя как блоковый элемент: растягивается по ширине, занимает все место в строчном измерении и начнется с новой строки. Он будет вести себя точно также как блоковый эелемент по отношению к соседним элементам в макете. Но ведь мы не устанавливали значение display: block, не так ли? Или все же устанавливали?
Оказывается, что устанавливали. В Спецификации Level 3 of the Display значение display определяется как два ключевых слова. Эти ключевые слова задают внешнее значение display, которое будет строчным или блоковым и будет определять как элемент ведет себя по отношению к другим элементам в макете. А еще они определяют внутреннее значение элемента — как будут вести себя прямые потомки этого элемента.
Это значит, что когда вы говорите display: grid, то то, что вы говорите на самом деле, выглядит так: display: block grid. Вы запрашиваете контейнер grid блочного уровня — элемент, который будет иметь все атрибуты блочного элемента: высоту, ширину, внешний и внутренний отступы (margin and padding), и который будет растягиваться полностью заполняя контейнер. Однако потомкам этого контейнера было назначено внутреннее значение grid, поэтому они становятся грид элементами. Как эти грид элементы будут себя вести определяется в CSS Grid спецификации: свойство display предоставляет нам способ, при помощи которого мы можем объявить браузеру, что именно этот метод задания макета мы хотим использовать.
Такое понимание концепции свойства displayоказывается очень полезным. Оно напрямую объясняет что мы деалем с различными методами создания макета. Если бы мы задали display: inline flex, то что бы мы ожидали в итоге получить? Надеюсь, что это был бы контейнер, который ведет себя как строчный эелемент, потомки которого являются flex элементами.
Также есть еще несколько моментов, которые можно логично объяснить, если думать о свойстве display в новом контексте, и я разберу эти моменты в остальной части статьи.
Мы всегда возвращаемся к стандартному порядку элементов
Если думать о внешних и внутренних свойствах display, то, возможно, будет полезным посмотреть, что произойдет, если мы не будем пытаться изменить значения свойства display. Если вы напишете простой HTML код и посмотрите как он выглядит в браузере, то то, что вы увидете, будет блочно-строчным макетом страницы или нормальным порядком. Элементы на странице будут вести себя как блочные или строчные.
See the Pen Block and Inline Layout by rachelandrew (@rachelandrew)on CodePen.
See the Pen Block and Inline Layout by Rachel Andrew (@rachelandrew) on CodePen.
В примере ниже содержится часть кода, которую я переделала в media объект, задав диву свойство display: flex, таким образом два прямых потомка этого дива стали flex элементами и картинка располагается на одной линии с контентом. Если посмотреть на весь контент, то еще можно увидеть заголовок и параграф, которые отображаются в нормальном порядке. Прямые потомки объекта media превратились во flex элементы, потомки же этих элементов вернутся к нормальному порядку, только если мы снова не изменим значение свойства display на flex. Сам по себе контейнер flex является блоковым элементом; это подтверждает тот факт, что бордер растягивается до самого края родительского элемента.
See the Pen Block and Inline Layout with Flex Component by Rachel Andrew (@rachelandrew) on CodePen.
See the Pen Block and Inline Layout with Flex Component by Rachel Andrew (@rachelandrew) on CodePen.
Тот факт, что элементы на странице располагают сами себя в читаемом логическом порядке, а не сражаются друг с другом, стараясь где-то отхватить себе место, делает CSS намного проще. Также снижается верятность того, что у вас возникнут проблемы с доступностью, так как вы работаете с логической структурой документа, как и экранные считывающие устройства или пользователи, которые пользуются табами.
Разбираемся с flow-root и inline-block
Значение inline-block вероятно знакомо тем, кто уже работал с CSS. Это способ применить к срочному элементу свойства блочного. Например, inline-block элемент может иметь высоту и ширину. И в дополнение к этому такой элемент ведет себя так, что создает форматируемый блочный контент (Block Formatting Content (BFC))
BFC позволяет делать очень полезные вещи, например, он содержит floats. Более подробно прочитать про Block Formatting Contexts можно в моей статье “Understanding CSS Layout And The Block Formatting Context”. Тем не менее, как уже было сказано, устанавливая display: inline-block вы получаете строчный блок, который также создает BFC.
Если вы прочитаете вышеупомянутую статью, вы откроете для себя новое значение свойства display, которое также создает BFC — flow-root. Это значение создает BFC для блока, а не для строчного элемента.
- display: inline-block дает вам BFC для строчного элемента
- display: flow-root дает вам BFC для блочного элемента
Возможно к этому моменту вы уже немного запутались. Зачем нам нужны два абсолютно разных ключевых слова и что произойдет с нашим синтаксисом с двумя значениями для свойства display, о котором мы говорили выше? Ответ на эти вопросы подводит нас к следующему понятию о свойстве display, которое я хотела бы объяснить, а именно тот факт, что у CSS есть история касательно display, которую нам необходимо учитывать.
Устаревшие значения свойства display
Спецификация CSS2 описывает следующие значения свойства display:
- inline
- block
- inline-block
- list-item
- none
- table
- inline-table
Также были описаны различные внутренние свойства table, такие как table-cell, но которых мы не коснемся в этой статье.
Затем к этим свойствам были добавлены новые, чтобы поддержать flex и grid макеты:
- grid
- inline-grid
- flex
- inline-flex
Примечание: Спецификация также определяет ruby и inline-rubyдля поддержки Ruby Text. Подробнее об этом можно прочитать в Ruby specification.
Выше перечислены все единичные значения display, которые были определены до обновления спецификации. Очень важный момент, касающийся CSS, — мы не можем просто пойти обходными путями и просто так изменить всё, что было определено до. Мы не можем внезапно решить, что каждый должен использовать новый синтаксис с двумя значениями, ведь тогда каждый сайт, который был создан по старым правилам, сломается, если разработчик это не исправит.
Пока эта проблема существует, мы можем пользоваться этим списком ошибок в дизайне CSS, которые, если разобраться, не такие уж страшные ошибки, учитывая, что дизайн CSS разрабатывался без магического шара, который мог бы предсказать будущее. Тем не менее ситуация такова, что мы не можем просто так взять и сломать интренет, поэтому на данный момент браузеры поддерживают набор единичных значений для display, а в спецификации происходит смена на двухзначные значения.
Чтобы обойти это, нужно указать устаревшие и короткие значения для display, которые включают в себя все эти отдельные значения. Это значит, что сопоставление можно определить между одним значением и новым значением состоящим из двух ключевых слов. Это в итоге дает нам следующую таблицу значений:
Значение, состоящее из одного ключевого слова | Значение, состоящее из двух ключевых слов | Описание |
---|---|---|
block | block flow | Блочный контейнер со страндарным внутренним порядком |
flow-root | block flow-root |
Блочный контейнер, определяющий BFC |
inline | inline flow | Строчный контейнер со стандарным внутренним порядком |
inline-block | inline flow-root |
Строчный контейнер, определяющий BFC |
list-item | block flow list-item |
Блочный контейнер со страндарным внутренним порядком и дополнительным маркировочным контейнером |
flex | block flex | Блочный контейнер с внутренним flex макетом |
inline-flex | inline flex | Строчный контейнер с внутренним flex макетом |
grid | block grid | Блочный контейнер с внутренним grid макетом |
inline-grid | inline grid | Строчный контейнер с внутренним grid макетом |
table | block table | Блочный контейнер с внутренним табличным макетом |
inline-table | inline table | Строчный контейнер с внутренним табличным макетом |
Чтобы объяснить как это работает, давайте представим grid контейнер. В мире, в котором есть значения, состоящие из двух ключевых слов, мы могли бы созать grid контейнер блочного уровня задав:
.container {
display: block grid;
}
Однако устаревшее ключевое слово означает, что следующий код делает то же самое:
.container {
display: grid;
}
Если вместо этого мы хотим строчный грид контейнер, тогда мы бы написали:
.container {
display: inline grid;
}
И используя устаревшее значение:
.container {
display: inline-grid;
}
А теперь давайте вернемся к началу нашего разговора и еще раз взглянем на display: inline-block. Сверяясь с нашей таблицей, мы видим, что это задается как display: inline flow-root. Это совпадает с display: flow-root, который, если задавать словом с двумя значениями, выглядел бы как display: block flow-root. Это добавляет ясности тому как всё задается. Рефактор CSS, если можно так сказать.
Поддержка нового синтаксиса браузерами
К настоящему моменту браузеры не поддерживают новый синтаксис для свойства display. Баг в реализации для Firefox можно найти здесь. Реализация, когда она произойдет, будет однозначно включать в себя привязывание старых значений к новым с двумя ключевыми словами. Поэтому, скорее всего, пройдет некоторое время, прежде чем мы сможем использовать два ключевых слова в своем коде. Но всё же это не главная мысль в моей статье. Я хотела показать, что если смотреть на свойство display в новом свете, это поможет объяснить многие вещи, которые происходят в CSS.
Когда вы задаете контейнер в CSS, вы задаете как именно этот контейнер будет себя вести по отношению к другим объектам в вашем макете. А также вы определяете как будут себя вести потомки этого контейнера. И можно начать думать об этом задолого до того, как объявить эти значения в коде как два ключевых слова, не забывая как устаревшие значения соотносятся с этими ключевыми словами, и это поможет вам лучше понимать что произойдет, если вы измените значение свойства display.