За свою карьеру у меня было достаточно много собеседований. Конечно, одной из основных тем вопросов была вёрстка. Немного похвалюсь. Не было вопроса, на который я не ответил.
Недавно у меня появилось желание снова проверить себя и показать сообществу свои ответы на самые популярные вопросы по вёрстке. Может же быть так, что мои ответы были неполными или некорректными. Если это так, то я научусь новому. А если всё хорошо, то они помогут другим людям в подготовке к собеседованию. Кажется, это в любом случае будет полезно.
У меня получился достаточно большой список. Он составлен на основе моего опыта, опыта моих знакомых и публично доступных собеседований. Каждый вопрос будет отдельной статьёй.
Сегодня я дам ответ на следующий вопрос: «Зачем нужно использовать свойство display
?»
▍ Что скрыто за свойством
Согласно стандарту CSS Display Module Level 3 свойство display
определяет тип отображения элемента. Для большинства случаев значение состоит из двух ключевых слов. Стоп. Как двух? Мы же всю жизнь определяли одно!
Да, мы задаём значение из одного ключевого слова, а на деле оно неявно трансформируется в два. Первая часть отвечает за внешний тип отображения, а вторая за внутренний.
Мы задаём значение block
для элемента <div>
, а браузеры видят его как block flow
.
div {
display: block; /* здесь display: block flow */
}
Как так происходит? В стандарте есть таблица, в которой указаны все краткие версии и соответствующие полные. Браузеры используют её для работы. Например, значения block
и inline
для них выглядят следующим образом:
/*
block = block flow
inline = inline flow
*/
Здесь я хочу сделать паузу. Далее я буду подробнее рассматривать ключевые слова block
и inline
. Обратите внимание, что это не значения block
и inline
, которые мы указываем. Идём дальше.
Первая часть значения влияет на отображение элемента, к которому применено свойство. Таким образом определяется внешний тип отображения. В стандарте данный тип назвали <display-outside>
. Для него можно использовать ключевые слова: block
, inline
и run-in
.
block
Если к элементу будет применено ключевое слово block
, то он становится элементом block-level
.
inline
При использовании ключевого слова inline
создаётся inline-level
элемент. Правда есть исключение. Это значение inline
.
В этом случае создаётся элемент inline box
. Как описано в стандарте сказано это элемент inline-level
, у которого в качестве внутреннего типа отображения задано ключевое слово flow
. Зачем нужно было отделить этот тип? Не знаю. Оставим это на совести авторов.
run-in
Ключевое слово run-in
создаёт элемент run-in box
. По сути это тот же элемент inline box
, только с определёнными правилами.
Вторая часть значения определяет внутренний тип отображения, влияющий на отображение дочерних элементов. Оно называется <display-inside>
. Для него используются ключевые слова flow
, flow-root
, flex
, grid
, table
и ruby
.
flow
и flow-root
Создаётся контейнер и контекст, в котором могут существовать block-level
и inline-level
элементы. Его называют блочным. Разница между ними в том, что второе создаёт новый блочный контекст.
flex
Ключевое слово создаёт флекс-контейнер и контекст, в котором существуют флекс-элементы. Другими словами, это тот самый контейнер, в котором создаются две оси и другие свойства, используемые вами.
grid
При использовании гридов именно это ключевое слово создаёт грид-контейнер и контекст, в котором вы добавляете строки, столбцы, шаблоны сетки и всё остальное.
table
Специальная обёртка над блочным контейнером, создающая сетку для имитации таблицы.
ruby
Ключевое слово создаёт ruby-контейнер и контекст, внутри которого можно создать фрагмент текста, который будет аннотацией к другому фрагменту текста.
Каждый тип внешнего и внутреннего отображения влияет на отображение элементов по-своему. Это и начальное положение элементов, и установка размеров, и работа свойства margin
. Об этом мы поговорим в отдельной статье. А сейчас я покажу, как вы каждый день используете рассмотренные типы и не подозреваете об этом.
▍ Влияние внешнего и внутреннего типа отображения на практике
Своё объяснение я построю на примере разметки с двумя элементами <div>
и <span>
, вложенными в элемент <body>
.
<body>
<div>Первый элемент с display: block</div>
<div>Второй элемент с display: block</div>
<span>Первый элемент с display: inline</span>
<span>Второй элемент с display: inline</span>
</body>
В браузере элементы <div>
располагаются в столбец. Сначала идёт первый, а под ним находится второй. Элементы <span>
расположились в строке. Первый элемент отображён в начале строки, а второй следует за ним. Вроде всё очевидно и просто. В каждом обучающем видео и туториале рассказано о таком поведении. Что ещё добавить?
А мне есть что добавить. Как говорится в обучающих материалах, такое отображение элементов получилось, потому что они блочные и строчные. Но это не совсем так! Упускается важный нюанс. Привычное поведение возможно благодаря display: block
, установленному у родителя. А если быть суперточным, потому что используется ключевое слово flow
.
Опираясь на таблицу с полными значениями, браузеры понимают, что значение block
состоит из двух ключевых слов block flow
, а значение inline
— inline flow
.
body {
display: block; /* здесь display: block flow */
}
div {
display: block; /* здесь display: block flow */
}
span {
display: inline; /* здесь display: inline flow */
}
Ключевое слово block
мы опустим. Элемент <body>
является родителем для всех других, поэтому не так важно, какой внешний тип отображения у него. А на ключевом слове flow
мы остановимся.
В нашем примере оно делает элемент <body>
блочным контейнером. В него вложены элементы <div>
и <span>
, у которых используются ключевые слова block
и inline
. Поняв всю эту цепочку, браузеры с чистой совестью отображают элементы <div>
в столбец, а элементы <span>
в строку, потому что это естественное поведение block-level
и inline-level
(inline box
) элементов внутри блочного контейнера. Без ключевого слова flow
такое поведение не получилось бы.
Если вы мне не верите, давайте проведём эксперимент. Вместо ключевого слова flow
будем использовать flex
для элемента <body>
.
body {
display: flex; /* здесь display: block flex */
}
Поменяв значение block
на flex
, мы сказали браузерам заменить блочный контейнер на флекс-контейнер. По этой причине элементы <div>
и <span>
перестали быть block-level
и inline-level
(inline box
) элементами. Теперь они флекс-элементы (flex items
). По этой причине они абсолютно одинаково выстроились в строку.
Думаете, что-то изменится, если использовать display: inline-flex
? Попробуем.
body {
display: inline-flex; /* здесь display: inline flex */
}
Нет, элементы отображаются так же. Всё потому что мы не изменили второе ключевое слово. Оно осталось прежним — flex
. Единственные изменения случились с самим элементом <body>
, поскольку мы начали использовать ключевое слово inline
. Как я говорил выше, в текущем примере это не так важно.
▍ Ключевые слова contents
и none
Свойство display
может не только контролировать, как будет отображаться элемент. Оно дополнительно управляет тем, будет ли элемент отображён в принципе. В стандарте такое поведение называют <display-box>
. Есть следующие ключевые слова:
contents
Ключевое слово скрывает элемент для своего окружения, но дочерние элементы продолжают существовать в структуре страницы, становясь на его место. При этом сохраняется стилизация элементов.
none
При этом ключевом слове элемент и все его потомки перестают отображаться.
Ключевое значение none
не имеет смысла рассматривать на практике. Мы всё равно ничего не увидим, потому что всё будет скрыто. А на ключевом слове contents
остановлюсь.
<body>
<ul class="list">
<li class="list__group"><a href="#">Ссылка 1</a></li>
<li class="list__group"><a href="#">Ссылка 2</a></li>
<li class="list__group"><a href="#">Ссылка 3</a></li>
</ul>
</body>
.list {
display: grid;
gap: 1rem;
}
.list__group {
display: contents;
}
После того, как применится display: contents
, стили, указанные в элементе .list
, будут влиять на ссылки, а не на элементы <li>
. В этом заключается вся фишка ключевого слова.
▍ Значение list-item
Я рассмотрел ключевые слова, из которых строятся часто используемые значения. Осталось одно, о котором с большой вероятностью вы даже не слышали. Значение list-item
.
Оно состоит (внимание!) из трёх ключевых слов! Первым идёт ключевое слово для внешнего типа отображения, вторым — для внутреннего, а третьим — ключевое слово list-item
.
/*
list-type = block flow list-item
*/
Ключевое слово list-item
заставляет элемент генерировать псевдоэлемент ::marker
. Его содержимое указывается свойством list-style
.
С теорией мы закончили. Я хочу перейти к забавному моменту. Во многих справочниках есть значение list-type
. Но оно не единственное! Я случайно нашёл ещё inline list-type
.
<body>
<div class="list-item">элемент c list-item</div>
<div class="inline-list-item">элемент c inline list-item</div>
<div class="inline-list-item">элемент c inline list-item</div>
</body>
.list-item {
display: list-item;
}
.inline-list-item {
display: inline list-item;
}
В последнем абзаце раздела с описанием ключевого слова сказано, что если не указан внешний тип отображения, то присваивается ключевое слово block
. Я подумал, что будет, если написать ключевое слово inline
перед list-item
. И вот получилось значение inline list-item
. Воспринимайте это просто как забавный факт.
▍ Заключение
Отвечу кратко на вопрос «Зачем нужно использовать свойство display
?»
Свойство display
управляет отображением элемента и его потомков. Большинство значений состоит из двух ключевых слов. Первое контролирует внешний тип отображения, а второе — внутренние. Мы можем использовать ключевые слова block
, inline
и run-in
для установки внешнего типа. Ключевые слова flow
, flow-root
, flex
, grid
, table
и ruby
задают внутренний тип отображения. В целом отображение элемента зависит от комбинации внутреннего типа родительского элемента и внешнего типа самого элемента.
Также есть значения contents
и none
, управляющие как будет скрыт элемент. При первом скрывается только элемент, к которому применено display: contents
, а дочерние элементы «встают» на его место. При значении none
скрывается элемент и все его потомки.
Ещё я написал вторую часть. В ней рассказал про различия между значениями свойства display
.
На этом сегодня всё. Другие статьи из серии можно найти по тегу «sm909_css_interview».
Если вам было интересна статья и вы хотите, чтобы я продолжил эту серию, то напишите, пожалуйста, вопросы, которые сбивали вас с толку на собеседовании. Я попробую ответить на них в новой статье. Спасибо за чтение.
P.S. Помогаю больше узнать про CSS в своём ТГ канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻