Наследование в CSS
Как и в случае с каскадом и специфичностью, разработчики почему-то относятся к наследованию с опаской. Но в этом нет необходимости, потому что наследование на самом деле довольно простое. Возможно, это также мой любимый аспект CSS. Сейчас объясню, почему.
Допустим, есть такой CSS:
body {
color: DarkSlateBlue;
}
Наряду с другими свойствами, color
наследуется, а это значит, что каждый фрагмент текста на странице — если не задан конкретный color
— станет DarkSlateBlue
.
Давайте рассмотрим это подробнее и добавим немного HTML.
<article>
<h1>I am a heading</h1>
<p>I am a paragraph.</p>
<h2>Subscribe</h2>
<form>
<label for="email">Email address</label>
<input type="email" id="email" placeholder="hello@test.com">
<button>Submit</button>
</form>
</article>
Если посмотреть демо, то заголовки, параграф и метка отображают текст цвета DarkSlateBlue
, но поле ввода (как placeholder
, так и value
) и кнопка по-прежнему используют цвет текста по умолчанию. Это происходит потому, что им назначены определённые цвета. Что можно увидеть в Инструментах разработчика:
button {
color: buttontext;
}
input {
color: fieldtext;
}
Это системные цвета, используемые в таблице стилей пользовательского агента (user agent) — стилях по умолчанию, применяемых браузером. Поскольку к этим элементам применяется значение color
, они не наследуют цвет от body
, как другие элементы на странице.
Ключевое слово inherit
Это ключевое слово удобно. Не все свойства CSS наследуются, хотя многие из них наследуются. Можно использовать ключевое слово inherit
, чтобы наследовать ненаследуемые свойства.
article {
display: flex;
}
h1 {
display: inherit;
}
В данном фрагменте <h1>
получит вычисленное значение display: flex
.
Вернёмся к нашему маленькому фрагменту HTML. Давайте сделаем так, чтобы элемент input
и button
наследовали цвет DarkSlateBlue
. Цвет является наследуемым, но можно использовать ключевое слово inherit
, чтобы заставить элемент наследовать эти свойства вместо стилей по умолчанию, назначенных таблицей стилей пользовательского агента.
input, button {
color: inherit;
}
Легко и просто, верно? Давайте продвинемся немного дальше и используем другое наследуемое свойство: font
. Сначала установим значение font
для body
:
body {
color: DarkSlateBlue;
font-family: Tahoma;
font-size: 2rem;
}
Магия наследования означает, что все текстовые элементы снова унаследовали font-family
, и весь текст стал больше.
Причина, по которой текстовые элементы, такие как заголовки, имеют больший размер, без дополнительного изменения размера, заключается в том, что стили пользовательского агента определяют их размер с помощью единиц em
, представляющих собой отношение вычисленного font-size
их родителя. Например, вот стиль размера шрифта h1
в стиле пользовательского агента в Chromium:
h1 {
font-size: 1.5em;
}
Поскольку мы установили font-size
для body
равным 2rem
, браузер рассчитал его как 24px
. font-size
для h1
равен 1,5em
, то есть 24 * 1,5
: 36px
.
Итак, вернёмся к небольшой демке. Проблема в том, что стиль placeholder
по-прежнему серый. Это связано с тем, что в таблице стилей пользовательского агента для placeholder
назначается определённый цвет, поэтому они больше не наследуют ни цвет body
, ни цвет input
.
Это правило placeholder в таблице стилей пользовательского агента Chromium.
::-webkit-input-placeholder {
-webkit-text-security: none;
color: darkGray;
pointer-events: none !important;
}
Значение color
установлено в darkGray
, поэтому даже если input
наследует цвет, это не повлияет на placeholder
, поскольку ему назначен более специфический стиль. Но ничего страшного, ведь всё, что нужно сделать, это использовать более кросс-браузерный селектор:
::placeholder {
color: inherit;
}
Управление наследованием
Конечно, я не устаю говорить о том, насколько мощным является наследование, но в реальном мире вы не будете создавать такие простые примеры, как приведённые выше. Будет много случаев, когда элемент унаследует нежелательные стили. Давайте рассмотрим некоторые варианты.
Пишите более специфичные стили
Это наиболее предпочтительный подход. Как уже говорилось в статье о каскаде и специфичности: стили пользовательского агента имеют низкий приоритет в каскаде, поэтому даже написание селекторов плоского типа, как в этом случае, сделает работу за вас:
a {
color: red; /* Очень легко переопределяет стиль пользовательского агента */
}
Именно так можно решить вышеописанные проблемы, и, вероятно, это путь наименьшего сопротивления при создании CSS.
Используйте ключевые слова
Давайте рассмотрим ключевые слова revert
, initial
и unset
.
Ключевое слово revert
.my-element {
color: revert;
}
Ключевое слово revert
установит свойство в значение таблицы стилей пользовательского агента — он же стиль браузера по умолчанию. Итак, если бы .my-element
был <button>
, цвет был бы установлен обратно в buttontext
, как говорилось ранее.
Ключевое слово unset
.my-element {
color: unset;
}
Ключевое слово unset
может запутать. Если свойство, которому присваивается unset
, является наследуемым, то фактически происходит следующее:
.my-element {
color: inherit;
}
Если это не наследуемое свойство, то значение свойства будет таким же, как и у следующего ключевого слова — initial
.
Ключевое слово initial
.my-element {
color: initial;
}
Это ядерный вариант, и его рекомендую избегать. Ключевое слово initial
вернёт значение к значению CSS-спецификации элемента, что в переводе на человеческий язык означает, что стиль будет полностью удалён.
Подведение итогов
Видите, наследование — это совсем не страшно, правда? Оно фантастически мощное, и если его принять, то можно писать меньше CSS. Кроме того, у вас будет более удобная кодовая база, а пользователи получат лучший опыт в целом. Магия.
Это сильно отличается от традиционной разработки программного обеспечения, где нужно очень точно стилизовать каждый элемент. Я понимаю, почему разработчики, пришедшие из этой среды, не любят CSS. Это изменение ментальной модели: отпустите потребность в абсолютном контроле, и всё станет проще. Это принцип создания веб-приложений в целом, улучшающий все ваши возможности. Поверьте мне.