Привет, Хабр. Я продолжаю рассказывать про неизвестные широкому кругу разработчиков CSS фишки. Я отбираю их так, чтобы они были полезны в разного рода проектах.
Неважно, верстаете ли вы сайт для малого бизнеса или создаёте супермодное React приложение. Они поддерживаются большинством браузеров. Отдельно отмечу, что я не считаю IE11 современным браузером. По этой причине я не учитывал его.
Сегодня мы рассмотрим:
- сброс стилей до значений, взятых из веб-стандартов;
- возврат значений свойств, установленных в браузере;
- что можно сделать с прыжками контента при открытии и закрытии модального окна;
- возможность отобразить текст «красиво» с помощью ключевого слова
system-ui
; - способ стилизации элементов на языке, отличающимся от основного.
Больше не буду затягивать. Давайте посмотрим, что я вам подготовил.
▍ Ключевое слово unset и revert
Периодически я копаюсь в CSS коде популярных библиотек. Так, однажды я наткнулся на версию CSS Reset от Элада Шехтер.
Сама библиотека довольно старая. Я сам первый раз познакомился с ней в году 2015. Элад обновил её. Его решение основано на использовании ключевых слов unset
и revert
. Например, так автор сбрасывает стили почти у всех элементов:
/*
Удаляет все "User-Agent-Stylesheet" стили, за исключением свойства display
*/
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
all: unset;
display: revert;
}
Что же делают ключевые слова? Разберём по порядку.
Для объяснения ключевого слова unset
вспомним, что в CSS есть два типа свойств, а именно: наследуемые и ненаследуемые. Разница между ними заключается в том, что первые могут получить значение в результате механизма наследования от родительского элемента, а вторые так не могут.
Если ключевое слово unset
используется для наследуемых свойств, то итоговое рассчитанное значение будет получено в результате механизма наследование. Например, в следующем примере значение у свойства color
у элемента <p>
будет получено из элемента <body>
.
body {
color: #222;
}
p {
color: unset; /* итоговое значение будет #222 */
}
А как будет работать ключевое слово для свойств, для которых механизм наследования не работает? Будет использоваться значение, определённое в веб-стандартах. Например, для свойства border-color
будет ключевое слово currentColor
.
body {
color: #222;
}
p {
color: unset; /* итоговое значение будет #222 */
border-width: 2px;
border-style: solid;
border-color: unset; /* итоговое значение будет #222, которое было получено с помощью currentColor */
}
Здесь стоит пояснить, почему в devTools мы увидим rgb(34, 34, 34)
(#222
в HEX формате). Ключевое слово currentColor
передаёт в свойство значение свойства color
. Поскольку для элемента <p>
установлено ключевое слово unset
, с помощью него браузеры установят значение #222
. Оно же будет использовано для свойства border-color
.
В итоге Элад в своём варианте CSS Reset строкой all: unset
сбрасывает все значения, чтобы они либо наследовали значение от родителя, либо использовали установленные стандартами значения.
Такой подход в целом работает, но не без исключений. Первое исключение — это свойство display
. После применения строки all: unset
у всех элементов будет установлено значение inline
, потому что оно установлено стандартами.
По этой причине Элад использует значение revert
для свойства display
.
/*
Удаляет все "User-Agent-Stylesheet" стили, за исключением свойства display
*/
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
all: unset;
display: revert;
}
Таким способом браузеры возьмут итоговое значение из «User-Agent-Stylesheet» стилей, установленных в них по умолчанию. Например, для элемента <p>
будет взято значение block
, а для элемента <span>
— inline
.
Для демонстрации принципа работы я добавлю код к элементам <p>
и <span>
.
p {
all: unset;
display: revert; /* здесь будет display: block */
}
span {
all: unset;
display: revert; /* здесь будет display: inline */
}
Мне лично не нравится подход «Сначала установим, а потом сбросим». По этой причине я не использую CSS Reset. Но сами значения unset
и revert
полезны.
Например, в компонентах, у которых меняется значение свойства display
. Или в качестве значений по умолчанию для переменных. Кстати, поделитесь, пожалуйста, в комментариях, как вы используете данные значения.
▍ Избавляемся от прыжков текста контента при открытии и закрытии модального окна
Модальные окна — один из наиболее ненавидимых мной элементов интерфейсов. Такое количество проблем и нюансов я нигде не видел. Одна из наиболее часто встречающихся — это смещение контента при открытии и закрытии окна. Вы можете посмотреть на неё с помощью демонстрации на сайте Дока.
Почему происходит смещение? Обратите внимание на полосу прокрутки браузера. Когда модальное окно закрыто — она есть, когда открыто — она убирается. Происходит это с помощью значение hidden
для свойства overflow
, добавленного к элементу <body>
. Убирая и добавляя полосу прокрутки, браузеры смещают контент на её ширину.
Существуют несколько техник, чтобы избежать смещения. Моя любимая основана на управлении пространством, выделяемым под полосу прокрутки. Отвечает за это поведение свойство scrollbar-gutter
.
В нашей задаче оно позволит навсегда зарезервировать место. Для этого нужно использовать значение stable
. Например, разработчики сайта Дока добавляют его к элементам <body>
и <html>
.
html,
body {
scrollbar-gutter: stable;
}
Теперь сдвигов контента при открытии и закрытии модального окна нет. Только есть момент, который я не понимаю. Зачем добавлять сразу к двум элементам? Если вы знаете, пожалуйста, напишите в комментариях. Спасибо.
▍ Воспользуемся для контента встроенным в платформу шрифтом
Стилизация текста является обычной рутиной фронтендера. Я не исключение. Для минимизации телодвижений, я написал базовый набор правил. Его использую по умолчанию во всех проектах.
В нём у меня есть возможность установить шрифт для текста. Для этого я создал переменную --ds-typography-main-font-family
и объявил её для элемента <body>
.
body {
font-family: var(--ds-typography-main-font-family, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Open Sans, Ubuntu, Fira Sans, Helvetica Neue, sans-serif);
}
Когда я реализовывал эту задачу, у меня был вопрос: «Какое значение по умолчанию установить?» Я погуглил и нашёл список шрифтов, которые рекомендуют для различных платформ. Его я стал использовать долгое время. А потом узнал про ключевое слово system-ui
.
В стандарте CSS Fonts Module Level 4 ему дано определение. Я понял его так, что ключевое system-ui
позволяет нам использовать для веб-контента шрифт, который встроен в операционную систему. Это помогает избежать отличий между текстом в интерфейсе ОС и текстом в веб-приложении.
«Блин, да это то, что нужно в моей задаче!» — подумал я. Так я добавил ключевое слово в свой сниппет.
body {
font-family: var(--ds-typography-main-font-family, system-ui);
}
Вместо длинной портянки получилось краткое ёмкое значение по умолчанию.
▍ Стилизация элементов и псевдокласс :lang()
В интерфейсах обычная практика использовать слова из другого языка. Часто они должны быть как-то иначе стилизированы. Для примера возьмём страницу Википедии о CSS. На ней есть фраза «Cascading Style Sheets».
<!DOCTYPE html>
<html lang="ru">
<head>
<!-- здесь элементы -->
</head>
<body>
<p>
CSS (англ. <span lang="en">Cascading Style Sheets</span> «каскадные таблицы стилей») — формальный язык декодирования и описания внешнего вида документа (веб-страницы), написанного с использованием языка разметки (чаще всего HTML или XHTML).
</p>
</body>
</html>
Как её сделать курсивом? Да, легко! Добавить класс к элементу, написать font-style: italic
и дело сделано. Конечно, это сработает. Но в CSS есть более элегантное решение, а именно псевдокласс :lang()
.
Он выбирает элементы, в зависимости от их языка. Есть несколько способов установить его. Самый популярный это — атрибут lang
. На примере стилизации фразы «Cascading Style Sheets» разберём, как применить псевдоэлемент.
Для элемента <span>
уже установлен атрибут lang
со значением en
. Осталось объявить псевдокласс :lang()
.
:lang(en) {
font-style: italic;
}
Можно пойти дальше. Определение стилей для каждого конкретного языка приведёт к раздуванию кода. Можно сделать проще. Написать стили для любого языка, кроме основного.
Напомню, что основной язык определяется при установке атрибута lang
для элемента html
. В моём примере используется lang="ru"
. Получается, наша задача заключается в том, чтобы выбрать все элементы, у которых значение атрибута lang
отличается от ru
.
Псевдокласс :not()
тут, как родной.
:not(:lang(ru)) {
font-style: italic;
}
▍ Заключение
Давайте подведём итог. В этой статье мы рассмотрели:
- как ключевое слово
unset
позволяет сбросить стили до значений веб-стандартов, а ключевое словоrevert
вернуть их обратно; - способ избегать прыжков контента при открытии и закрытии модального окна, основанном на свойстве
scrollbar-gutter
; - ключевое слово
system-ui
для использования шрифта платформы; - псевдокласс
:lang()
для стилизации элементов на языке, отличающегося от основного.
Оставляю ссылки на все выпуски:
Также, пожалуйста, напишите в комментариях, какие CSS фишки вы используете, о которых другие могут не знать. Буду ждать их. Спасибо за чтение!
P.S. Помогаю больше узнать про CSS в своём ТГ канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻