Мои любимые вопросы о CSS с ответами. Версия 2023 года
В 2020 году я поделился списком моих любимых вопросов о CSS, который стал довольно популярным, судя по просмотрам. Спустя 3 года CSS изменился, и я решил дополнить список, добавив вопросы про гриды, пользовательские свойства (CSS-переменные), новые селекторы и свойства.
Работая над вопросами, мне хотелось помочь вам в изучении новых возможностей CSS и тех моментов, которые многие разработчики упускают, судя по моей практике. Также вы можете использовать их, если проводите интервью. Я буду только рад этому. А теперь давайте начнём.
▍ Какая специфичность следующего правила?
:is(#container, .content, main) {
color: red;
}
Принцип работы псевдокласса :is()
заключается в том, что браузеры выбирают наиболее специфичный селектор из переданных. В нашем случае передан селектор #container
, у которого специфичность 0,1,0,0
. Она же будет использоваться для всего правила.
▍ Верно ли, что браузеры вычислят значение red
для свойства color
?
текст элемента
.label {
color: red;
}
:where(#label) {
color: blue;
}
Верно. Поскольку псевдокласс :where()
имеет специфичность 0
, то в нашем примере более специфичным будет правило с селектором .label
. Соответственно, браузеры возьмут значение для свойства color
из него.
▍ Перепишите следующий код так, чтобы свойства применялись при клике на кнопку, но не применялись, когда на неё сфокусировались при помощи клавиатуры.
.button {
outline: none;
color: red;
}
:focus-visible
, который срабатывает, когда пользователь сфокусировался на интерактивном элементе при помощи клавиатуры. В задаче требуется не применять свойства, поэтому нужно использовать инверсию, т. е псевдокласс :not()
, а также добавить псевдокласс :focus
, чтобы стили срабатывали после клика по кнопке.
.button:focus:not(:focus-visible) {
outline: none;
color: red;
}
▍ Какое вычисленное значение для свойства display
у псевдоэлементов ::before
и ::after
?
.parent {
display: inline-grid;
}
.parent::before {
content: "";
display: inline;
}
.parent::after {
content: "";
display: flex;
}
grid
или inline-grid
для элемента браузеры сделают проверку значения для свойства display
его дочерних элементов. Если у них будет значение inline
, inline-block
, inline-flex
, inline-grid
или inline-table
, то оно трансформируется в блочный аналог, а именно inline
, inline-block
в block
, inline-flex
в flex
, inline-grid
в grid
и inline-table
в table
.В нашем примере у псевдоэлемента ::before
установлено значение inline
, поэтому оно преобразуется в block
, а для псевдоэлемента ::after
значение flex
будет сохранено.
.parent {
display: inline-grid;
}
.parent::before {
content: "";
display: inline; /* здесь будет display: block */
}
.parent::after {
content: "";
display: flex; /* здесь будет display: flex */
}
▍ Как по умолчанию отображаются дочерние элементы внутри родительского с display: grid
или display: inline-grid
?
После объявления display: grid
или display: inline-grid
для родителя его дочерние элементы начинают отображаться в столбец.
▍ Чему равняется вычисленное значение для свойства width
и height
у элементов .child
?
элемент №1
элемент №2
.parent {
display: grid;
width: 1000px;
height: 400px;
}
display: grid
. В этом случае свойство width
будет эквивалентно свойству width
родительского элемента, т.е будет 1000px
. В свою очередь, вычисление свойства height
зависит от количества элементов. Если внутри грид-контейнера один элемент, то свойство height
будет таким же, как у родителя. Если несколько элементов, то свойство height
распределяется между элементами. В примере у всех дочерних элементов не объявлено свойство height
, поэтому у них одинаковая высота, следовательно, нужно разделить 400px
на 2, и мы получим 200px
.
▍ Верно ли, что внешние отступы у первого и последнего элемента p
выходят за границы родительского элемента?
body {
display: grid;
}
p {
margin-top: 1em;
margin-bottom: 1em;
}
После объявления display: grid
внешние отступы у первого и последнего элемента перестают выходить за пределы родительского элемента. Соответственно, правильный ответ — неверно.
▍ Если добавить display: grid
к элементу, будут ли схлопываться внешние отступы у его дочерних элементов?
Внутри грид-контейнера внешние отступы между элементами суммируются, а не схлопываются.
▍ Псевдоэлемент ::before
располагается по центру по горизонтали и по вертикали. Да или нет?
.box {
display: inline-grid;
width: 200px;
height: 200px;
}
.box::before {
content: "";
width: 15px;
height: 15px;
margin: auto;
}
Да, псевдоэлемент ::before
располагается по центру по горизонтали и по вертикали, потому что внутри грид-контейнера автоматические внешние отступы распределяются равномерно по обеим осям.
▍ В следующем примере для свойства padding
будет установлено значение 0
. Правда или ложь?
:root {
--padding-vertical-start: 30px;
--padding-horizontal-end: 40px;
--padding-vertical-end: 50px;
}
.box {
padding: var(--padding-vertical-start)
var(--padding-horizontal-end)
var(--padding-vertical-end)
var(--padding-horizontal-start);
}
В примере со свойством padding
из-за того, что не хватает одного значения, браузеры не знают, к какой стороне относят переданные значения 30px
, 40px
и 50px
, поэтому вычисленное значение для всех сторон будет 0
, соответственно, правильный ответ — правда.
▍ Какое вычисленное значение будет у свойства font-size
и background-color
у элемента p
?
body {
--font-size: purple;
--background-color: 20px;
font-size: 10px;
background-color: green;
}
p {
--font-size: inherit;
--background-color: inherit;
font-size: var(--font-size, 50px);
background-color: var(--background-color, red);
}
inherit
для пользовательских свойств нужно помнить, что они наследуют значение только между собой, и поэтому пользовательские свойства --font-size
и --background-color
унаследуют значения purple
и 20px
.body {
--font-size: purple;
--background-color: 20px;
font-size: 10px;
background-color: green;
}
p {
--font-size: inherit; /* здесь значение purple */
--background-color: inherit; /* здесь значение 20px */
font-size: var(--font-size, 50px);
background-color: var(--background-color, red);
}
Далее эти значения используются для свойств
font-size
и background-color
, поэтому значения по умолчанию 50px
и red
будут проигнорированы. После этого браузеры должны вместо функции var()
подставить значение пользовательского свойства. Перед тем как это сделать, они проверят, является ли значение корректным для свойства, для которого происходит замена. В нашем случае значения некорректны, потому что значение purple
должно быть подставлено для свойства font-size
, а значение 20px
для свойства background-color
. Но ошибки здесь не будет! В этом случае есть алгоритм, согласно которому браузеры подставят корректное значение.
Для этого они анализируют свойство, для значения которого происходит замена. Если оно наследуемое, то значение будет вычислено в результате наследования, если нет, то будет использоваться начальное значение (initial
).
В нашем примере свойство font-size
наследуемое, поэтому значение для элемента p
будет 10px
, которое наследуется от свойства font-size
элемента body
, а свойство background-color
ненаследуемое, поэтому будет использоваться начальное значение, а именно transparent
.
body {
--font-size: purple;
--background-color: 20px;
font-size: 10px;
background-color: green;
}
p {
--font-size: inherit;
--background-color: inherit;
font-size: var(--font-size, 50px); /* здесь получается font-size: 10px */
background-color: var(--background-color, red); /* здесь получается background-color: transparent */
}
▍ Почему для элемента p
браузеры вычислят значение green
для свойства background-color
?
body {
background-color: green;
}
p {
--background-color: inherit;
background-color: var(--background-color, inherit);
}
body
не определено пользовательское свойство --background-color
, то наследовать значение с помощью ключевого слова inherit
неоткуда. Так что значение для пользовательского свойства --background-color
будет не определено. Соответственно, браузеры подставят значение по умолчанию inherit
, а с помощью него передадут значение green
по алгоритму наследования.
▍ Каким свойством можно сократить количество определённых свойств для псевдоэлемента ::before
до трёх?
.parent {
position: relative;
}
.parent::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
position: absolute
, то можно альтернативно установить размеры с помощью свойств top
, right
, bottom
и left
..parent {
position: relative;
}
.parent::before {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Теперь сократим их в одно свойство
inset
..parent {
position: relative;
}
.parent::before {
content: "";
position: absolute;
inset: 0;
}
▍ Перепишите следующий код так, чтобы определение значений для свойств margin
и padding
было без использования 0
.box {
margin: 0 20px 0 40px;
padding: 30px 0 15px;
}
margin-block
, margin-inline
, padding-block
и padding-inline
. Важно помнить, что первым значением устанавливается значение сначала (сверху и слева), а вторым — значение с конца (снизу и справа)..box {
margin-inline: 40px 20px;
padding-block: 30px 15px;
}
▍ Как с помощью свойства gap
можно сократить следующий код до одного правила?
ul {
display: flex;
}
li:not(:last-child) {
margin-right: 15px;
}
display: flex
, кроме свойства margin
, мы можем использовать свойство gap
.ul {
display: flex;
gap: 15px;
}
▍ Как с помощью свойства isolation
расположить псевдоэлемент ::after
позади текста, чтобы он не перекрывался фоном элемента .parent
?
текст элемента
.parent {
background-color: purple;
}
.container {
position: relative;
}
.container::after {
content: "";
background-color: green;
position: absolute;
inset: 0;
z-index: -1;
}
z-index
, то мы должны помнить, относительно какого контекста наложения (stacking context
) будет расчёт положения. Поскольку в коде не создаётся новый контекст, то будет использоваться корневой, то есть элемент html
. Поэтому псевдоэлемент ::after
с отрицательным z-index
будет позади элемента .parent
.Чтобы отобразить его позади текста элемента .container
, нужно сделать этот элемент новым контекстом с помощью свойства isolation
, для которого задать значение isolate
.
.parent {
background-color: purple;
}
.container {
position: relative;
isolation: isolate;
}
.container::after {
content: "";
background-color: green;
position: absolute;
inset: 0;
z-index: -1;
}
▍ Вместо заключения
Мне интересно прочитать, какие темы о CSS, по вашему мнению, я упустил. Или, возможно, у вас есть свой список любимых вопросов. Так что, пожалуйста, делитесь. Я нацелен написать третью версию через 3 года! Ваша помощь будет очень кстати. Спасибо.
Выиграй телескоп и другие призы в космическом квизе от RUVDS. Поехали?