Современные и будущие возможности веб-стилизации, представленные на Google IO 2022, а также некоторые дополнительные возможности.
2022 год обещает стать одним из самых значимых годов для CSS, как с точки зрения новых функций, так и совместных выпусков функций браузеров. Совместная цель — реализовать 14 функций!
Обзор
Эта публикация представляет собой статью с доклада, прочитанного на конференции Google IO 2022. Она не претендует на роль подробного руководства по каждой функции, а скорее представляет собой введение и краткий обзор, призванный заинтересовать вас, предлагая широкий, а не глубокий обзор. Если вам интересно, ознакомьтесь с материалами в конце раздела, чтобы найти ссылки на дополнительную информацию.
Оглавление
Используйте список ниже, чтобы перейти к интересующим вас темам:
Совместимость с браузерами
Основная причина, по которой так много функций CSS планируется выпустить совместно, — это усилия Interop 2022. Прежде чем изучать усилия Interop, важно рассмотреть усилия Compat 2021 .
Compat 2021
Цели на 2021 год, определенные на основе отзывов разработчиков, полученных в ходе опросов, включали стабилизацию текущих функций, улучшение набора тестов и повышение проходных баллов браузеров по пяти функциям:
-
sticky
позиционирование - изменение размера
aspect-ratio
-
flex
макет -
grid
макета -
transform
позиционирования и анимации
Результаты тестов выросли по всем направлениям, что свидетельствует о повышенной стабильности и надёжности. Поздравляем команды!
Интероп 2022
В этом году разработчики браузеров собрались вместе, чтобы обсудить функции и приоритеты, над которыми они намерены работать, объединив усилия. Они планировали предоставить разработчикам следующие веб-функции:
-
@layer
- Цветовые пространства и функции
- Сдерживание
-
<dialog>
- Совместимость форм
- Прокрутка
- Подсетка
- Типографика
- Единицы измерения области просмотра
- Веб-совместимость
Это захватывающий и амбициозный список, и мне не терпится увидеть его воплощение в жизнь.
Свежее в 2022 году
Неудивительно, что состояние CSS 2022 существенно зависит от работы Interop 2022.
Каскадные слои
До появления @layer
порядок загрузки таблиц стилей был очень важен, поскольку стили, загруженные последними, могут перезаписывать ранее загруженные. Это привело к появлению тщательно управляемых таблиц стилей, где разработчикам приходилось сначала загружать менее важные стили, а затем более важные. Существуют целые методологии, помогающие разработчикам управлять этой важностью, например, ITCSS .
С помощью @layer
входной файл может заранее определить слои и их порядок. Затем, по мере загрузки или определения стилей, их можно размещать в слое, сохраняя приоритет переопределения стилей, но без тщательного управления загрузкой.
В видеоролике показано, как определенные каскадные слои позволяют более свободно и свободно создавать и загружать файлы, сохраняя при этом каскадность по мере необходимости.
Chrome DevTools полезен для визуализации того, какие стили взяты из тех или иных слоев:
Ресурсы
- Спецификация CSS Cascade 5
- Объяснение каскадных слоев
- Каскадные слои на MDN
- Уна Кравец : Каскадные слои
- Ахмад Шадид : Привет, каскадные слои CSS
Подсетка
До появления subgrid
сетка внутри другой сетки не могла выравниваться по своим родительским ячейкам или линиям сетки. Каждый макет сетки был уникальным. Многие дизайнеры размещают одну сетку поверх всего своего дизайна и постоянно выравнивают элементы внутри неё, что было невозможно сделать в CSS.
После subgrid
дочерний элемент сетки может принять столбцы или строки своих родителей как свои собственные и выровнять себя или своих дочерних элементов по ним!
В следующем примере элемент body создаёт классическую сетку из трёх столбцов: средний столбец называется main
, а левый и правый столбцы называют свои линии fullbleed
. Затем каждый элемент body, <nav>
и <main>
, заимствует именованные линии из body, устанавливая свойство grid-template-columns: subgrid
.
body {
display: grid;
grid-template-columns:
[fullbleed-start]
auto [main-start] min(90%, 60ch) [main-end] auto
[fullbleed-end]
;
}
body > * {
display: grid;
grid-template-columns: subgrid;
}
Наконец, дочерние элементы <nav>
или <main>
могут выравниваться или изменять свой размер, используя fullbleed
и main
столбцы и строки.
.main-content {
grid-column: main;
}
.fullbleed {
grid-column: fullbleed;
}
Devtools поможет вам увидеть линии и подсетки (пока только в Firefox). На следующем изображении родительская сетка и подсетки наложены друг на друга. Теперь всё выглядит так, как дизайнеры представляли себе макет.
На панели элементов devtools вы можете увидеть, какие элементы являются сетками и подсетками, что очень полезно для отладки или проверки макета.

Ресурсы
Контейнерные запросы
До появления @container
элементы веб-страницы могли изменяться только в зависимости от размера всей области просмотра. Это отлично подходит для макромакетов, но в микромакетах, где внешний контейнер не занимает всю область просмотра, подстройка макета невозможна.
После @container
элементы могут реагировать на размер или стиль родительского контейнера! Единственное ограничение — контейнеры должны декларировать себя как возможные цели запроса, что является небольшим требованием, но даёт существенные преимущества.
/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
}
Благодаря этим стилям столбцы «Пн», «Вт», «Ср», «Чт» и «Пт» в следующем видео могут запрашиваться элементами событий.
Вот CSS-код для запроса размера контейнера calendar-day
с последующей настройкой макета и размеров шрифта:
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
Вот еще один пример: один компонент книги адаптируется к свободному пространству в столбце, в который он перетаскивается:
Уна права, оценивая ситуацию с новым адаптивным дизайном . Использование @container
открывает множество интересных и значимых дизайнерских решений.
Ресурсы
- Спецификация контейнерных запросов
- Объяснение контейнерных запросов
- Запросы контейнеров на MDN
- Новый адаптивный дизайн на web.dev
- Демонстрация календаря от Уны
- Потрясающая коллекция контейнерных запросов
- Как мы создали Designcember на web.dev
- Ахмад Шадид : Приветствуем запросы CSS-контейнера
accent-color
До появления accent-color
, когда вам нужна была форма с цветами, соответствующими бренду, приходилось прибегать к сложным библиотекам или CSS-решениям, которыми со временем становилось сложно управлять. Хотя они предоставляли все возможности и, как мы надеемся, обеспечивали доступность, выбор между встроенными компонентами и собственными становился утомительным.
После accent-color
, одна строка CSS добавляет фирменный цвет встроенным компонентам. Помимо оттенка, браузер автоматически выбирает контрастные цвета для вспомогательных частей компонента и адаптируется к системным цветовым схемам (светлым или тёмным).
/* tint everything */
:root {
accent-color: hotpink;
}
/* tint one element */
progress {
accent-color: indigo;
}
Чтобы узнать больше об accent-color
, ознакомьтесь с моей публикацией на web.dev, где я рассматриваю множество дополнительных аспектов этого полезного свойства CSS.
Ресурсы
- спецификация акцентного цвета
- акцентный цвет на MDN
- акцентный цвет на web.dev
- Bramus : Тонирование элементов управления пользовательского интерфейса с помощью CSS-акцентного цвета
Уровень цвета 4 и 5
В течение последних десятилетий в интернете доминировало цветовое пространство sRGB, но в расширяющемся цифровом мире дисплеев высокой чёткости и мобильных устройств с предустановленными OLED- или QLED-экранами sRGB недостаточно. Более того, ожидается, что динамические страницы будут адаптироваться к предпочтениям пользователя, и управление цветом становится всё более важной задачей для дизайнеров, дизайн-систем и специалистов по сопровождению кода.
Но не в 2022 году — в CSS есть ряд новых цветовых функций и пространств: - Цвета, которые достигают цветовых возможностей HD-дисплеев. - Цветовые пространства, которые соответствуют цели, например, однородности восприятия. - Цветовые пространства для градиентов, которые радикально меняют результаты интерполяции. - Цветовые функции, помогающие смешивать и контрастировать, а также выбирать, в каком пространстве выполнять работу.
До появления всех этих цветовых функций дизайн-системам приходилось предварительно рассчитывать соответствующие контрастные цвета и обеспечивать соответствующие яркие палитры, в то время как препроцессоры или JavaScript выполняли тяжелую работу.
После всех этих цветовых функций браузер и CSS могут выполнить всю работу динамически и точно в срок. Вместо того, чтобы отправлять пользователям многокилобайтные CSS и JavaScript для включения цветовой темы и визуализации данных, CSS может взять на себя организацию и вычисления. CSS также лучше подготовлен к проверке поддержки перед использованием и корректной обработке резервных вариантов.
@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);
}
}
@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
}
}
hwb()
HWB означает оттенок, белизна и чернота. Это удобный для восприятия способ выражения цвета, поскольку это всего лишь оттенок и количество белого или чёрного для осветления или затемнения. Художники, смешивающие цвета с белым или чёрным, могут оценить это дополнение к цветовому синтаксису.
Использование этой функции цвета приводит к цветам из цветового пространства sRGB, аналогичного HSL и RGB. Что касается новшества 2022 года, это не добавляет новых цветов, но может облегчить некоторые задачи для любителей синтаксиса и ментальной модели.
Ресурсы
Цветовые пространства
Цвета представлены в цветовом пространстве. Каждое цветовое пространство предлагает различные функции и компромиссы для работы с цветом. Некоторые пространства могут объединять все яркие цвета вместе, другие могут сначала выстраивать их в порядке светлоты.
В CSS 2022 появится 10 новых цветовых пространств, каждое из которых обладает уникальными функциями, помогающими дизайнерам и разработчикам отображать, выбирать и смешивать цвета. Раньше единственным вариантом для работы с цветом было sRGB, но теперь CSS открывает новые возможности и предлагает новое цветовое пространство по умолчанию — LCH.
color-mix()
До появления color-mix()
разработчикам и дизайнерам требовались препроцессоры, такие как Sass, для смешивания цветов до того, как их увидит браузер. Большинство функций смешивания цветов также не позволяли указать цветовое пространство, в котором должно производиться смешивание, что иногда приводило к путанице.
После color-mix()
разработчики и дизайнеры могут смешивать цвета в браузере, наряду со всеми остальными стилями, без запуска процессов сборки и использования JavaScript. Кроме того, они могут указать, в каком цветовом пространстве выполнять смешивание, или использовать цветовое пространство смешивания по умолчанию LCH.
Часто в качестве основы используется фирменный цвет, на основе которого создаются варианты, например, более светлые или тёмные цвета для стилей наведения. Вот как это выглядит с помощью color-mix()
:
.color-mix-example {
--brand: #0af;
--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
}
и если вы хотите смешать эти цвета в другом цветовом пространстве, например srgb, измените его:
.color-mix-example {
--brand: #0af;
--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
}
Ниже представлена демонстрация тем с использованием color-mix()
. Попробуйте изменить цвет бренда и посмотрите, как изменится тема:
Наслаждайтесь смешиванием цветов в различных цветовых пространствах в своих таблицах стилей в 2022 году!
Ресурсы
- спецификация color-mix()
- color-mix() на MDN
- Демонстрация тем
- Еще одна демонстрация тем
- Фабио Джолито : создайте цветовую тему с помощью этих новых функций CSS
color-contrast()
До появления color-contrast()
авторам таблиц стилей требовалось заранее знать доступные цвета. Часто палитра отображала чёрный или белый текст на образце цвета, чтобы указать пользователю цветовой системы, какой цвет текста необходим для правильного контраста с этим образцом.

После использования color-contrast()
авторы таблиц стилей могут полностью переложить эту задачу на браузер. Вы можете не только настроить браузер для автоматического выбора чёрного или белого цвета, но и предоставить ему список цветов, подходящих для системы дизайна, и выбрать первый из них, соответствующий желаемому коэффициенту контрастности.
Вот скриншот демонстрационной палитры цветов HWB, где цвета текста автоматически выбираются браузером на основе цвета образца:

Основы синтаксиса выглядят так: серый цвет передается в функцию, а браузер определяет, какой цвет (черный или белый) имеет наибольшую контрастность:
color: color-contrast(gray);
Функцию также можно настроить с помощью списка цветов, из которого она выберет наиболее контрастный цвет:
color: color-contrast(gray vs indigo, rebeccapurple, hotpink);
Наконец, если предпочтительнее не выбирать самый контрастный цвет из списка, можно указать целевой коэффициент контрастности и выбрать первый цвет, который ему соответствует:
color: color-contrast(
var(--bg-blue-1)
vs
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
);
Эту функцию можно использовать не только для цвета текста, хотя, по моим оценкам, это будет её основной областью применения. Представьте, насколько проще станет создавать доступные и читабельные интерфейсы, когда выбор подходящих контрастных цветов будет встроен в язык CSS.
Ресурсы
Относительный синтаксис цвета
До появления относительного цветового синтаксиса для вычисления цвета и внесения корректировок цветовые каналы требовалось индивидуально помещать в пользовательские свойства. Это ограничение также сделало HSL основной функцией управления цветом, поскольку оттенок, насыщенность и яркость можно было легко настроить с помощью calc()
.
После внедрения относительного цветового синтаксиса любой цвет в любом пространстве можно деконструировать, изменить и вернуть как цвет — всё это одной строкой CSS. Больше никаких ограничений HSL — манипуляции можно выполнять в любом цветовом пространстве, и для этого требуется гораздо меньше пользовательских свойств.
В следующем примере синтаксиса предоставляется базовый шестнадцатеричный код и относительно него создаются два новых цвета. Первый параметр --absolute-change
создаёт новый цвет в LCH на основе базового цвета, затем заменяет яркость базового цвета на 75%
, сохраняя насыщенность ( c
) и цветовой тон ( h
). Второй параметр --relative-change
создаёт новый цвет в LCH на основе базового цвета, но на этот раз уменьшает насыщенность ( c
) на 20%.
.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
}
Это похоже на смешивание цветов, но больше похоже на изменения, чем на смешивание. Вы можете получить цвет из другого цвета, получив доступ к трём значениям каналов, названным используемой цветовой функцией, и возможность настраивать эти каналы. В целом, это очень интересный и мощный синтаксис для работы с цветом.
В следующей демонстрации я использовал относительный цветовой синтаксис для создания более светлых и более темных вариантов базового цвета, а также использовал color-contrast()
чтобы гарантировать надлежащую контрастность меток:

Эту функцию также можно использовать для генерации цветовой палитры. Вот демо, где целые палитры генерируются на основе заданного базового цвета. Этот набор CSS-кода лежит в основе всех палитр, каждая из которых просто предоставляет свою базу. В качестве бонуса, поскольку я использовал LCH, обратите внимание на то, насколько равномерно распределены палитры — благодаря этому цветовому пространству не видно ни горячих, ни мёртвых зон.
:root {
--_color-base: #339af0;
--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
}

Надеюсь, теперь вы понимаете, как цветовые пространства и различные цветовые функции можно использовать для разных целей, учитывая их сильные и слабые стороны.
Ресурсы
- Спецификация синтаксиса относительного цвета
- Создание цветовых палитр с использованием относительного цветового синтаксиса
- Создание цветовых вариантов с использованием относительного цветового синтаксиса
Градиентные цветовые пространства
До появления градиентных цветовых пространств цветовое пространство sRGB использовалось по умолчанию. sRGB в целом надежен, но имеет некоторые недостатки, такие как серая мертвая зона .
После цветовых пространств градиента укажите браузеру, какое цветовое пространство использовать для интерполяции цвета. Это даёт разработчикам и дизайнерам возможность выбирать предпочитаемый ими градиент. Цветовое пространство по умолчанию также меняется с sRGB на LCH.
Добавление синтаксиса выполняется после направления градиента, использует новый in
и является необязательным:
background-image: linear-gradient(
to right in hsl,
black, white
);
background-image: linear-gradient(
to right in lch,
black, white
);
Вот базовый и важный градиент от чёрного к белому. Посмотрите на диапазон результатов в каждом цветовом пространстве. Некоторые достигают тёмно-чёрного раньше других, некоторые переходят в белый слишком поздно.
В следующем примере чёрный цвет переходит в синий, поскольку это известное проблемное пространство для градиентов. Большинство цветовых пространств постепенно переходят в фиолетовый во время интерполяции цветов, или, как мне нравится это называть, когда цвета перемещаются внутри своего цветового пространства из точки A в точку B. Поскольку градиент проходит по прямой линии от точки A до точки B, форма цветового пространства радикально меняет остановки, которые он проходит по пути.
Для более глубоких исследований, примеров и комментариев прочитайте эту ветку в Twitter .
Ресурсы
- Спецификация интерполяции градиента
- Демонстрация сравнения градиентов в пространствах
- Наблюдаемая тетрадь, сравнивающая градиенты
inert
До появления inert
считалось целесообразным направлять фокус пользователя на области страницы или приложения, требующие немедленного внимания. Эта стратегия направленного фокуса стала известна как «захват фокуса», поскольку разработчики помещали фокус в интерактивное пространство, отслеживали события изменения фокуса и, если фокус покидал интерактивное пространство, принудительно возвращали его обратно. Пользователи, использующие клавиатуру или программы чтения с экрана, возвращаются в интерактивное пространство, чтобы убедиться в завершении задачи перед переходом к следующей.
После inert
треппинг не требуется, поскольку можно заморозить или установить защиту целых разделов страницы или приложения. Щелчки и попытки изменения фокуса просто недоступны, пока эти части документа инертны. Можно также представить это как защиту, а не как ловушку, где inert
не заинтересован в том, чтобы вы оставались на одном месте, а делает другие места недоступными.
Хорошим примером этого является функция JavaScript alert()
:
Обратите внимание на то, что в предыдущем видео страница была доступна с помощью мыши и клавиатуры до вызова функции alert()
. После появления всплывающего диалогового окна оповещения остальная часть страницы застыла, или стала inert
. Фокус пользователя находился внутри диалогового окна оповещения, и ему некуда было двигаться дальше. После того, как пользователь взаимодействовал с элементом и выполнял запрос функции оповещения, страница снова стала интерактивной. inert
позволяет разработчикам легко реализовать тот же управляемый фокус.
Вот небольшой пример кода, демонстрирующий, как это работает:
<body>
<div class="modal">
<h2>Modal Title</h2>
<p>...<p>
<button>Save</button>
<button>Discard</button>
</div>
<main inert>
<!-- cannot be keyboard focused or clicked -->
</main>
</body>
Диалоговое окно — отличный пример, но inert
также полезна для таких вещей, как выдвижное боковое меню. Когда пользователь выдвигает боковое меню, недопустимо, чтобы мышь или клавиатура взаимодействовали со страницей за ним; это может быть довольно затруднительно для пользователей. Вместо этого, когда боковое меню отображается, сделайте страницу инертной, и тогда пользователям придётся закрывать его или перемещаться по нему, и они никогда не потеряются где-то ещё на странице с открытым меню.
Ресурсы
Шрифты COLRv1
До появления шрифтов COLRv1 в интернете существовали шрифты OT-SVG — также открытый формат для шрифтов с градиентами, встроенными цветами и эффектами. Однако они могли быть очень большими, и, хотя и позволяли редактировать текст, возможности для настройки были ограничены.
После появления шрифтов COLRv1 в Интернете появились шрифты меньшего размера, масштабируемые в векторном формате, перемещаемые, с функцией градиента и режимом смешивания, которые принимают параметры для настройки шрифта в соответствии с конкретным вариантом использования или для соответствия бренду.

Вот пример из блога разработчиков Chrome, посвящённый эмодзи. Возможно, вы заметили, что при увеличении размера шрифта эмодзи он теряет чёткость. Это изображение, а не векторная графика. Часто в приложениях, где используется эмодзи, его заменяют на более качественный объект. Благодаря шрифтам COLRv1 эмодзи получаются векторными и красивыми:
Шрифты-иконки могут творить чудеса с этим форматом, предлагая пользовательские двухцветные палитры и многое другое. Загрузка шрифта COLRv1 происходит так же, как и загрузка любого другого файла шрифта:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
Настройка шрифта COLRv1 осуществляется с помощью @font-palette-values
— специального CSS-правила для группировки и присвоения имени набору параметров настройки в пакет для последующего использования. Обратите внимание, что пользовательское имя указывается так же, как и пользовательское свойство, начиная с --
:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
При использовании --colorized
в качестве псевдонима для настроек последним шагом будет применение палитры к элементу, использующему семейство цветных шрифтов:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
.spicy {
font-family: "Bungee Spice";
font-palette: --colorized;
}

С появлением все большего количества вариативных и цветных шрифтов веб-типографика уверенно движется к богатой кастомизации и творческому самовыражению.
Ресурсы
- Спецификация Colrv1 на Github
- Разработчики Chrome: шрифты Colrv1
- Объясняющее видео для разработчиков BlinkOn
Единицы измерения области просмотра
До появления новых вариантов области просмотра веб предлагал физические единицы измерения для подгонки области просмотра. Существовали единые единицы для высоты, ширины, наименьшего размера (vmin) и наибольшей стороны (vmax). Они хорошо подходили для многих задач, но мобильные браузеры вносили некоторые сложности.
На мобильных устройствах при загрузке страницы отображается строка состояния с URL-адресом, которая занимает часть пространства области просмотра. Через несколько секунд после некоторого интерактивного взаимодействия строка состояния может съехать, чтобы предоставить пользователю больше места для просмотра. Но когда эта строка съезжает, высота области просмотра меняется, и все единицы измерения vh
смещаются и меняют размер в соответствии с изменением целевого размера. В последующие годы единица измерения vh
должна была специально выбирать, какой из двух размеров области просмотра она будет использовать, поскольку это вызывало резкие проблемы с визуальной компоновкой на мобильных устройствах. Было решено, что vh
всегда будет представлять самую большую область просмотра.
.original-viewport-units {
height: 100vh;
width: 100vw;
--size: 100vmin;
--size: 100vmax;
}
После появления новых вариантов области просмотра стали доступны малые, большие и динамические единицы измерения, а также логические эквиваленты физических. Идея заключается в том, чтобы дать разработчикам и дизайнерам возможность выбирать, какие единицы измерения они хотят использовать в конкретном сценарии. Возможно, небольшое резкое изменение макета при исчезновении строки состояния допустимо, поэтому можно без опасений использовать dvh
(динамическую высоту области просмотра).
Ниже приведен полный список всех новых вариантов единиц измерения области просмотра, которые стали доступны с новыми вариантами области просмотра:
.new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; }
.new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; }
.new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; }
.new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
Будем надеяться, что это предоставит разработчикам и дизайнерам гибкость, необходимую для создания адаптивных дизайнов с учетом области просмотра.
Ресурсы
- Спецификация относительных единиц области просмотра
- Bramus : Большие, Маленькие и Динамические Видовые Окна
:has()
До использования :has()
субъект селектора всегда находился в конце. Например, субъект этого селектора — элемент списка: ul > li
. Псевдоселекторы могут изменить селектор, но не субъект: ul > li:hover
или ul > li:not(.selected)
.
После :has()
субъект, находящийся выше в дереве элементов, может оставаться субъектом, обеспечивая при этом запрос о дочерних элементах: ul:has(> li)
. Легко понять, почему :has()
получил общее название «родительский селектор», поскольку субъект селектора в данном случае теперь является родителем.
Вот простой пример синтаксиса, где класс .parent
остается субъектом, но выбирается только в том случае, если дочерний элемент имеет класс .child
:
.parent:has(.child) {...}
Вот пример, где элемент <section>
является субъектом, но селектор срабатывает только в том случае, если один из дочерних элементов имеет :focus-visible
:
section:has(*:focus-visible) {...}
Селектор :has()
становится невероятно полезным, как только появляются новые практические примеры его использования. Например, в настоящее время невозможно выбирать теги <a>
, когда они оборачивают изображения, что затрудняет обучение тега-якоря изменению стилей в этом случае. Однако это возможно с помощью :has()
:
a:has(> img) {...}
Во всех этих примерах :has()
выглядит как родительский селектор. Рассмотрим пример использования изображений внутри элементов <figure>
и корректировки стилей изображений, если у рисунка есть <figcaption>
. В следующем примере выбираются рисунки с figcaptions, а затем изображения в этом контексте. :has()
используется и не меняет тему, поскольку мы ориентируемся на изображения, а не на рисунки:
figure:has(figcaption) img {...}
Комбинации, кажется, бесконечны. Сочетайте :has()
с количественными запросами и корректируйте макеты CSS-сеток в зависимости от количества дочерних элементов. Сочетайте :has()
с интерактивными состояниями псевдоклассов и создавайте приложения, которые реагируют на запросы новыми, креативными способами.
Проверка поддержки упрощается благодаря @supports
и его функции selector()
, которая проверяет, понимает ли браузер синтаксис перед его использованием:
@supports (selector(:has(works))) {
/* safe to use :has() */
}
Ресурсы
- :has() спецификация
- :has() на MDN
- Селектор CSS
:has()
— это нечто большее, чем просто «родительский селектор».
2022 и далее
После выхода всех этих замечательных функций в 2022 году всё ещё будет сложно реализовать ряд задач. В следующем разделе мы рассмотрим некоторые из оставшихся проблем и активно разрабатываемые решения для их решения. Эти решения являются экспериментальными, хотя они могут быть указаны или доступны с помощью флагов в браузерах.
Итогом следующих разделов должно стать осознание того, что перечисленные проблемы волнуют многих людей из многих компаний, а не то, что эти решения будут выпущены в 2023 году.
Свободно типизированные пользовательские свойства
Пользовательские свойства CSS — это нечто потрясающее. Они позволяют хранить в именованной переменной самые разные данные, которые затем можно расширять, вычислять, делиться ими и так далее. На самом деле, они настолько гибкие, что было бы неплохо иметь и менее гибкие.
Рассмотрим сценарий, в котором box-shadow
использует пользовательские свойства для своих значений:
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
Всё это работает хорошо, пока одно из свойств не будет изменено на значение, которое CSS не принимает, например, --x: red
. Вся тень разрушается, если какая-либо из вложенных переменных отсутствует или имеет недопустимый тип значения.
Вот тут-то и вступает в дело @property
: --x
может стать типизированным пользовательским свойством, которое больше не будет свободным и гибким, а станет безопасным с некоторыми определенными границами:
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
Теперь, когда box-shadow
пытается использовать var(--x)
и позже --x: red
, red
будет проигнорирован, так как это не <length>
. Это означает, что тень продолжает работать, даже если одному из её пользовательских свойств было присвоено недопустимое значение. Вместо того, чтобы завершиться ошибкой, она возвращается к своему initial-value
0px
.
Анимация
Помимо типобезопасности, это также открывает множество возможностей для анимации. Гибкость синтаксиса CSS делает анимацию некоторых элементов невозможной, например, градиентов. @property
здесь помогает, поскольку типизированное свойство CSS может информировать браузер о намерениях разработчика внутри чрезмерно сложной интерполяции. Это, по сути, ограничивает возможности браузера настолько, что он может анимировать аспекты стиля, которые раньше были недоступны.
Рассмотрим этот демонстрационный пример, где радиальный градиент используется для создания части наложения, создавая эффект фокуса прожектора. JavaScript устанавливает координаты мыши x и y при нажатии клавиш alt/opt, а затем изменяет фокусный размер на меньшее значение, например, 25%, создавая фокусный круг прожектора в позиции мыши:
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
}
Однако градиенты нельзя анимировать. Они слишком гибкие и сложные, чтобы браузер мог «просто вывести» желаемый способ анимации. Однако с помощью @property
можно типизировать и анимировать одно свойство изолированно, и браузер легко распознает его назначение.
Видеоигры, использующие этот эффект фокусировки, всегда анимируют круг, от большого до маленького. Вот как использовать @property
в нашей демонстрации, чтобы браузер анимировал градиентную маску:
@property --focal-size {
syntax: '<length-percentage>';
initial-value: 100%;
inherits: false;
}
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
transition: --focal-size .3s ease;
}
Теперь браузер может анимировать размер градиента, поскольку мы сократили область изменения до одного свойства и ввели значение, чтобы браузер мог разумно интерполировать длины.
@property
может сделать гораздо больше, но эти небольшие улучшения могут иметь большое значение.
Ресурсы
- @property спецификация
- @property на MDN
- @property на web.dev
- Демонстрация фокусировки с увеличением
- CSS-хитрости: изучение @property и его возможностей анимации
Был в min-width
или max-width
До того, как медиазапросы будут заданы, медиазапрос CSS использует min-width
и max-width
для обозначения условий «выше» и «ниже». Это может выглядеть примерно так:
@media (min-width: 320px) {
…
}
После диапазонов медиа-запросов тот же медиа-запрос может выглядеть так:
@media (width >= 320px) {
…
}
Медиа-запрос CSS, использующий как min-width
, так и max-width
может выглядеть следующим образом:
@media (min-width: 320px) and (max-width: 1280px) {
…
}
После диапазонов медиа-запросов тот же медиа-запрос может выглядеть так:
@media (320px <= width <= 1280px) {
…
}
В зависимости от вашего опыта программирования, один из них будет выглядеть гораздо более разборчиво, чем другой. Благодаря дополнениям к спецификации разработчики смогут выбирать предпочитаемый ими вариант или даже использовать их как взаимозаменяемые.
Ресурсы
- Спецификация синтаксиса диапазона медиа-запросов
- Синтаксис диапазона медиа-запросов на MDN
- Синтаксис диапазона медиа-запросов плагина PostCSS
Нет переменных медиа-запроса
До появления @custom-media
медиа-запросы приходилось повторять снова и снова или полагаться на препроцессоры для генерации правильного вывода на основе статических переменных во время сборки.
После @custom-media
CSS позволяет создавать псевдонимы медиа-запросов и ссылаться на них, как на пользовательские свойства.
Именование очень важно: оно позволяет согласовать назначение с синтаксисом, упрощая обмен информацией и использование её в командах. Вот несколько пользовательских медиазапросов, которые используются мной между проектами:
@custom-media --OSdark (prefers-color-scheme: dark);
@custom-media --OSlight (prefers-color-scheme: light);
@custom-media --pointer (hover) and (pointer: coarse);
@custom-media --mouse (hover) and (pointer: fine);
@custom-media --xxs-and-above (width >= 240px);
@custom-media --xxs-and-below (width <= 240px);
Теперь, когда они определены, я могу использовать один из них следующим образом:
@media (--OSdark) {
:root {
…
}
}
Полный список пользовательских медиа-запросов, которые я использую, можно найти в моей библиотеке пользовательских свойств CSS Open Props .
Ресурсы
Вложенные селекторы — это так здорово
До появления @nest
в таблицах стилей было много повторений. Это становилось особенно громоздко, когда селекторы были длинными и каждый из них учитывал небольшие различия. Удобство вложенности — одна из самых распространённых причин использования препроцессора.
После @nest
повторение исчезает. Практически все возможности вложенности с поддержкой препроцессора будут встроены в CSS.
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
Что для меня наиболее важно во вложении, помимо отсутствия повторения article
во вложенном селекторе, так это то, что контекст стиля остается в пределах одного блока стиля. Вместо перехода от одного селектора и его стилей к другому селектору со стилями (пример 1), читатель может оставаться в контексте статьи и видеть, что статья владеет ссылками внутри нее. Отношения и назначение стиля объединены вместе, поэтому создается впечатление, что article
имеет свои собственные стили.
Право собственности можно также рассматривать как централизацию. Вместо того, чтобы искать в таблице стилей соответствующие стили, их можно найти вложенными вместе в контекст. Это работает как с отношениями «родитель-потомок», так и с отношениями «потомок-родитель».
Рассмотрим дочерний компонент, который хочет настроить себя, находясь в другом родительском контексте, в отличие от родителя, владеющего стилем и изменяющего дочерний элемент:
/* parent owns this, adjusting children */
section:focus-within > article {
border: 1px solid hotpink;
}
/* with @nest becomes */
/* article owns this, adjusting itself when inside a section:focus-within */
article {
@nest section:focus-within > & {
border: 1px solid hotpink;
}
}
@nest
в целом помогает обеспечить более здоровую организацию, централизацию и владение. Компоненты могут группировать и владеть собственными стилями, вместо того, чтобы распределять их по другим блокам стилей. В этих примерах оно может показаться незначительным, но оно может иметь очень большое значение как для удобства, так и для удобочитаемости.
Ресурсы
Определить стили действительно сложно
До @scope
существовало множество стратегий, поскольку стили в CSS каскадируются, наследуются и по умолчанию имеют глобальную область действия. Эти функции CSS очень удобны для многих вещей, но для сложных сайтов и приложений, потенциально с множеством различных стилей компонентов, глобальное пространство и природа каскада могут создать ощущение утечки стилей.
После @scope
стили могут быть ограничены не только контекстом, например классом, но также могут указывать, где стили заканчиваются и не продолжают каскадироваться или наследовать.
В следующем примере область действия соглашения об именах BEM может быть изменена на фактическую цель. Селектор BEM пытается ограничить цвет элемента header
контейнером .card
с соглашениями об именах. Для этого необходимо, чтобы в заголовке было это имя класса, что соответствует цели. При использовании @scope
никаких соглашений об именах не требуется для достижения той же цели без разметки элемента заголовка:
.card__header {
color: var(--text);
}
/* with @scope becomes */
@scope (.card) {
header {
color: var(--text);
}
}
Вот еще один пример, менее специфичный для компонентов и больше посвященный глобальной природе CSS. Темные и светлые темы должны сосуществовать внутри таблицы стилей, где порядок имеет значение для определения выигрышного стиля. Обычно это означает, что стили темной темы идут после светлой темы; это устанавливает светлый стиль по умолчанию и темный как дополнительный стиль. Избегайте борьбы с порядком и областью действия с помощью @scope
:
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
Чтобы завершить эту историю, @scope
также позволяет установить, где заканчивается область действия стиля. Это невозможно сделать с помощью какого-либо соглашения об именах или препроцессора; это нечто особенное, и на него способен только CSS, встроенный в браузер. В следующем примере стили img
и .content
применяются исключительно тогда, когда дочерний элемент .media-block
является родственным или родительским .content
:
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
Ресурсы
Нет способа CSS для макета каменной кладки
До появления каменной кладки CSS с сеткой JavaScript был лучшим способом создания каменной кладки, поскольку любой из методов CSS со столбцами или флексбоксами неточно представлял порядок контента.
После кладки CSS с сеткой библиотеки JavaScript не потребуются, и порядок контента будет правильным.

https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/
Предыдущая демонстрация достигается с помощью следующего CSS:
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
Приятно осознавать, что это рассматривается как недостающая стратегия макетирования, плюс вы можете попробовать ее сегодня в Firefox .
Ресурсы
- Спецификация раскладки кладки
- Раскладка кладки на MDN
- Smashing Magazine: собственный макет CSS Masonry с CSS Grid
CSS не может помочь пользователям уменьшить объём данных
До медиа-запроса prefers-reduced-data
JavaScript и сервер могли изменить свое поведение в зависимости от операционной системы пользователя или параметра «сохранения данных» браузера, но CSS не мог.
После медиа prefers-reduced-data
CSS может присоединиться к улучшению пользовательского опыта и сыграть свою роль в сохранении данных.
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
В этом компоненте прокрутки мультимедиа используется предыдущий CSS, и экономия может быть огромной. В зависимости от того, насколько велика область просмотра посещения, можно добиться большей экономии при загрузке страницы. Сохранение продолжается по мере того, как пользователи взаимодействуют со скроллерами мультимедиа. Все изображения имеют атрибут loading="lazy"
, и это в сочетании с CSS, полностью скрывающим элемент, означает, что сетевой запрос изображения никогда не выполняется.
Для моего тестирования на вьюпорте среднего размера изначально было загружено 40 запросов и 700 КБ ресурсов. Когда пользователь прокручивает выбор мультимедиа, загружается больше запросов и ресурсов. С помощью CSS и сокращенного запроса к носителю данных загружается 10 запросов и 172 КБ ресурсов. Это полмегабайта экономии, при этом пользователь даже не прокрутил ни одного медиафайла, и в этот момент никаких дополнительных запросов не делается.
У такого сокращения объема данных есть больше преимуществ, чем просто экономия данных. Можно увидеть больше заголовков, и нет отвлекающих изображений на обложках, которые отвлекали бы внимание. Многие пользователи просматривают страницы в режиме экономии трафика, поскольку платят за мегабайт данных — очень приятно видеть, что CSS может здесь помочь.
Ресурсы
- спецификация с предпочтительным сокращением данных
- предпочитает сокращенные данные на MDN
- предпочитает сокращенные данные в вызове GUI
- Smashing Magazine: Улучшение основных веб-показателей, практический пример Smashing Magazine
Функции прокрутки привязки слишком ограничены
До появления этих предложений по привязке к прокрутке написание собственного JavaScript для управления каруселью, слайдером или галереей могло быстро стать сложной задачей со всеми наблюдателями и управлением состоянием. Кроме того, если не соблюдать осторожность, естественная скорость прокрутки может быть нормализована сценарием, что сделает взаимодействие с пользователем немного неестественным и потенциально неуклюжим.
Новые API
snapChanging()
Это событие срабатывает, как только браузер освобождает дочерний элемент Snap. Это позволяет пользовательскому интерфейсу отразить отсутствие дочерней привязки и неопределенное состояние привязки скроллера, поскольку он сейчас используется и появится где-то в новом месте.
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
Как только браузер привязывается к новому дочернему элементу и скроллер останавливается, это событие срабатывает. Это позволяет любому пользовательскому интерфейсу, который зависит от привязанного дочернего элемента, обновляться и отражать соединение.
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => {
console.log('Snap changed', event.snappedTargetsList);
});
scroll-start
Прокрутка не всегда начинается с самого начала. Рассмотрим компоненты с возможностью перелистывания, где смахивание влево или вправо вызывает различные события, или панель поиска, которая при загрузке страницы изначально скрыта, пока вы не прокрутите страницу вверх. Это свойство CSS позволяет разработчикам указать, что скроллер должен начинаться в определенной точке.
:root { --nav-height: 100px }
.snap-scroll-y {
scroll-start-y: var(--nav-height);
}
:snap-target
Этот селектор CSS будет сопоставлять элементы в контейнере привязки прокрутки, которые в данный момент привязаны браузером.
.card {
--shadow-distance: 5px;
box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%);
transition: box-shadow 350ms ease;
}
.card:snapped {
--shadow-distance: 30px;
}
После этих предложений по привязке к прокрутке создавать слайдер, карусель или галерею стало намного проще, поскольку браузер теперь предлагает удобства для выполнения этой задачи, устраняя наблюдателей и код оркестровки прокрутки в пользу использования встроенных API.
Для этих функций CSS и JS все еще очень рано, но ищите полифилы, которые могут помочь в их внедрении и тестировании в ближайшее время.
Ресурсы
Перемещение между известными состояниями
До toggle()
для стилизации и взаимодействия можно было использовать только состояния, встроенные в браузер. Например, входной флажок имеет :checked
— внутреннее управляемое состояние браузера для входных данных, которое CSS может использовать для визуального изменения элемента.
После toggle()
для любого элемента можно создавать собственные состояния, которые CSS будет изменять и использовать для стилизации. Он позволяет осуществлять группы, циклическое переключение, направленное переключение и многое другое.
В следующем примере достигается тот же эффект зачеркивания элемента списка при завершении, но без каких-либо элементов флажка:
<ul class='ingredients'>
<li>1 banana
<li>1 cup blueberries
...
</ul>
И соответствующие стили CSS toggle()
:
li {
toggle-root: check self;
}
li:toggle(check) {
text-decoration: line-through;
}
Если вы знакомы с конечными автоматами, вы можете заметить, насколько много пересечений происходит с toggle()
. Эта функция позволит разработчикам встраивать больше своего состояния в CSS, что, как мы надеемся, приведет к более четким и семантическим способам организации взаимодействия и состояния.
Ресурсы
Настройка выбранных элементов
До <selectmenu>
CSS не имел возможности настраивать элементы <option>
с помощью расширенного HTML или сильно изменять отображение списка параметров. Это заставило разработчиков загружать внешние библиотеки, воссоздающие большую часть функциональности <select>
, что в конечном итоге потребовало большого труда.
После <selectmenu>
разработчики могут предоставлять богатый HTML для элементов параметров и стилизовать их так, как им нужно, при этом соблюдая требования доступности и предоставляя семантический HTML.
В следующем примере, взятом со страницы объяснения <selectmenu>
, создается новое меню выбора с некоторыми основными параметрами:
<selectmenu>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>
CSS может ориентироваться на части элемента и стилизовать их:
.my-select-menu::part(button) {
color: white;
background-color: red;
padding: 5px;
border-radius: 5px;
}
.my-select-menu::part(listbox) {
padding: 10px;
margin-top: 5px;
border: 1px solid red;
border-radius: 5px;
}
Вы можете попробовать элемент <selectmenu>
в Chromium в Canary с включенным флагом веб-экспериментов. В 2023 году и далее следите за появлением настраиваемых элементов меню.
Ресурсы
Привязка элемента к другому
До anchor()
абсолютная и относительная позиции были стратегиями положения, которые позволяли разработчикам перемещать дочерние элементы внутри родительского элемента.
После anchor()
разработчики могут размещать элементы относительно других элементов, независимо от того, являются ли они дочерними или нет. Это также позволяет разработчикам указывать, относительно какого края позиционировать, и другие тонкости для создания взаимосвязей между элементами.
В объяснителе есть несколько отличных примеров и образцов кода, если вы хотите узнать больше.