Какие современные возможности CSS стоит знать?
Вопрос
Какие современные возможности CSS появились в последние годы и решают задачи, для которых раньше требовался препроцессор или JS?
Короткий ответ
К ключевым современным возможностям относятся CSS custom properties (переменные), container queries (адаптация по размеру родителя, а не viewport), псевдокласс :has() (родительский/условный селектор) и функции clamp()/min()/max() для адаптивных вычислений без медиазапросов.
Подробный ответ
CSS custom properties (--var) — в отличие от переменных препроцессоров (Sass), это реальные значения в runtime: их можно менять через JS (element.style.setProperty), они наследуются по DOM-дереву как обычные CSS-свойства и могут быть переопределены на любом уровне каскада, включая медиазапросы и :root vs локальный скоуп. Читаются через var(--name, fallback).
Container queries (@container) — позволяют применять стили в зависимости от размера родительского контейнера, а не всего viewport, как это делает @media. Это критично для по-настоящему переиспользуемых компонентов: одна и та же карточка должна выглядеть по-разному в узком сайдбаре и в широкой основной колонке, независимо от ширины экрана. Требует объявить container-type: inline-size (или size) на родителе.
:has() — псевдокласс, позволяющий выбрать элемент на основе его потомков или соседей, то есть фактически родительский селектор, которого CSS не хватало десятилетиями. Пример: подсветить form, у которой есть невалидное поле, или стилизовать .card, содержащую изображение, иначе, чем без него.
clamp()/min()/max() — математические функции для адаптивных значений без медиазапросов:
clamp(min, preferred, max)— значение ограничено сверху и снизу, а между границами плавно масштабируется поpreferred(часто сvw).min()— выбирает наименьшее из значений, удобно для "не шире чем X, но не больше 100%".max()— выбирает наибольшее, удобно для нижней границы.
Пример
:root {
--gap: 16px;
--accent: #3b82f6;
}
.card {
padding: var(--gap);
border: 1px solid var(--accent);
}
/* container query: карточка адаптируется под ширину родителя, а не экрана */
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 120px 1fr;
}
}
/* :has() — форма с невалидным полем получает красную рамку */
form:has(input:invalid) {
border-color: crimson;
}
/* карточка без изображения получает другой паддинг */
.card:not(:has(img)) {
padding: 24px;
}
/* адаптивная типографика без медиазапросов */
.title {
font-size: clamp(1.25rem, 2vw + 1rem, 3rem);
width: min(90%, 640px);
}
Дополнительные вопросы
- Чем container queries принципиально отличаются от медиазапросов с точки зрения переиспользуемости компонентов?
- Как CSS custom properties взаимодействуют с наследованием и каскадом по сравнению с Sass-переменными?
- Какие ограничения производительности есть у
:has()при глубоко вложенных селекторах?