Мы публиковали статью «Что нужно знать о современном CSS» в прошлом году (2024), и какое-то время я сомневался, хватит ли материала, чтобы сделать новую версию. Но время идет — и CSS развивается вместе с ним. И знаете что? В этом году новинок даже больше, чем в прошлом. Этот (пусть и немного субъективный) список можно рассматривать как подборку «возможностей, которые, по мнению Криса, стоит знать — будь то совсем новые или те, что недавно получили хорошую поддержку в браузерах».
❯ Анимирование до auto
Что это такое?
Обычно мы не фиксируем высоту блоков с произвольным контентом, а даем им занять столько места, сколько требуется. Проблема в том, что раньше нельзя было анимировать переход от фиксированного значения (например, нуля) к «естественной» высоте элемента — и обратно. Иными словами, анимация до auto
(или других ключевых значений вроде min-content
) была невозможна.
Теперь же у нас появилась возможность включить поддержку анимации до таких ключевых слов, например:
html {
interpolate-size: allow-keywords;
/* Теперь, если задать переход
от "height: 0;" к "height: auto;"
где угодно, это сработает */
}
Если не хочется включать такую «опцию», можно пойти другим путем: использовать функцию calc-size()
. С ней переход будет работать без interpolate-size
.
.content {
height: 3lh;
overflow: hidden;
transition: height 0.2s;
&.expanded {
height: calc-size(auto, size);
}
}
Зачем это нужно?
В CSS впервые появилась возможность делать подобное. Такой кейс встречается довольно часто, и здорово, что теперь его можно реализовать нативно, без всяких костылей и проблем с поведением.
Причем, речь не только о height
(так можно анимировать любое свойство, принимающее размер), и не только об auto
(поддерживаются и другие ключевые слова для размеров).
Поддержка
Браузеры |
Пока только Chrome. |
Прогрессивное улучшение |
Да. Обычно такого рода анимация не является критически важной — скорее, приятным бонусом. |
Полифилл |
По сути, нет. Старые костыли включали, например, анимацию |
❯ Поповеры и вызывающие элементы
Это два независимых и полезных инструмента, в первую очередь, связанных с HTML, но их удобно показывать вместе, потому что они отлично дополняют друг друга.
Что это такое?
Поповер (popover) — это атрибут, который можно добавить к любому HTML-элементу, чтобы дать ему функциональность открытия/закрытия. После этого элемент получает JS API для управления состоянием. По сути, это напоминает модальные окна, но с некоторыми отличиями. Их, скорее, можно отнести к категории подсказок (tooltip), или к элементам, которые иногда хочется держать открытыми одновременно.
Вызывающие элементы (invokers) — это тоже HTML-атрибуты, которые позволяют работать с этими JS API через декларативную разметку.
Зачем это нужно?
Реализация функционала на уровне HTML — это удобно и эффективно. Такой подход работает даже без JS, остается доступным для всех пользователей и, как правило, сразу учитывает важные UX-аспекты, которые при самостоятельной реализации легко упустить.
Поддержка
Браузеры |
Поповеры уже повсюду, а вот вызывающие элементы на момент публикации поддерживаются только в Chrome. Есть и дополнительные возможности, например, popover="hint", которые пока поддерживается чуть хуже. |
Прогрессивное улучшение |
Не особо. Такие функции обычно должны _работать без сбоев_, поэтому проще и надежнее использовать полифилл, чем пытаться самому учитывать все возможные варианты поведения. |
Полифилл |
Да. Для обоих случаев: Popovers Polyfill Invokers Polyfill |
Пример использования
Важно помнить, что для поповеров существуют и JS API, например myPopover.showPopover()
или secondPopover.hidePopover()
. Но здесь речь идет именно о вызывающих HTML-элементах для управления ими.
Существуют и альтернативные «HTML-контроллы» (например, popovertarget="mypopover"
и popovertargetaction="show"
), их тоже можно использовать. Но мне больше нравится подход с универсальными вызывающими элементами.
К тому же стоит помнить, что поповеры особенно хорошо работают в связке с позиционированием через якорь (anchor) — еще одно современное чудо CSS.
@function
Что это такое?
В CSS уже есть множество функций — например, calc()
, attr()
, clamp()
и сотни других. Технически их называют CSS-функциями значений (value functions), потому что они всегда возвращают одно значение.
Магия @function
в том, что теперь можно создавать свои собственные функции:
@function --titleBuilder(--name) {
result: var(--name) " is cool.";
}
Зачем это нужно?
Вынос логики в функции — это принцип программирования, известный со времен первых компьютеров. Это не только «правильный» подход, но и способ писать CSS по принципу DRY (Don't Repeat Yourself): код и логика собираются в одном месте, вместо того, чтобы дублировать их или усложнять декларативные части CSS громоздкими выражениями.
Поддержка
Браузеры |
Только Chrome. |
Прогрессивное улучшение |
Это зависит от того, для чего будет использоваться значение. В простых случаях это может выглядеть так: |
Полифилл |
Не совсем. У Sass есть свои функции, но они основаны на другой спецификации и работают иначе. |
Другие ресурсы
Уна Кравец: 5 полезных CSS-функций с использованием нового правила @function
Брамус Ван Дамм: CSS
@function
+ CSSif()
= ?Хуан Диего Родригес: Функции в CSS?!
Черновик: CSS Functions and Mixins Module
❯ if()
Что это такое?
CSS и так уже содержит элементы условной логики: селекторы применяют стили только к подходящим элементам, а медиа-запросы срабатывают, когда выполняются их условия.
Однако функция if()
— это первый специальный логический инструмент, предназначенный именно для создания условных ветвлений в CSS.
Зачем это нужно?
Как и все функции, включая пользовательские @function
, if()
возвращает одно значение. Ее синтаксис помогает сделать код более читаемым и избежать дублирования выражений.
Поддержка
Браузеры |
Только Chrome. |
Прогрессивное улучшение |
Это зависит от того, с каким свойством или значением используется |
Полифилл |
Не совсем. В CSS уже есть похожие логические конструкции, но они не пересчитываются динамически в зависимости от значений или положения элементов в DOM. |
Пример использования
Встраивать логику в одно значение — довольно круто:
.grid {
display: grid;
grid-template-columns:
if(
media(max-width > 300px): repeat(2, 1fr);
media(max-width > 600px): repeat(3, 1fr);
media(max-width > 900px): repeat(auto-fit, minmax(250px, 1fr));
else: 1fr;
);
}
Синтаксис напоминает оператор switch
: можно задать любое количество условий, при этом выполняется первое совпадение:
if(
condition: value;
condition: value;
else: value;
)
Условия могут быть следующими:
media()
supports()
style()
❯ field-sizing
Что это такое?
Новое свойство field-sizing
в CSS позволяет создавать поля формы (или любые редактируемые элементы), которые автоматически подстраиваются под размер содержимого.
Зачем это нужно?
Эту задачу разработчики долгое время решали с помощью JS. Классический пример — <textarea>
: логично, чтобы его размер автоматически подстраивался под объем вводимой пользователем информации, без необходимости вручную менять высоту (что особенно неудобно на маленьких экранах мобильных устройств). Но автоматическое масштабирование любых редактируемых элементов — действительно полезная вещь.
Поддержка
Браузеры |
Поддерживается в Chrome и, похоже, скоро появится в Safari. |
Прогрессивное улучшение |
Да. Не критическая необходимость, а, скорее, приятный бонус для UX. |
Полифилл |
Есть довольно легкое решение на JS, которое можно использовать для имитации такого поведения. |
❯ Пользовательские селекты
Что это такое?
Внешний вид <select>
давно можно было стилизовать без особых трудностей. Но при открытии списка его содержимое отрисовывалось браузером в стандартном стиле операционной системы. Теперь же у нас появилась возможность включить полностью настраиваемые и стилизуемые выпадающие меню для <select>
.
Поддержка
Браузеры |
Только Chrome. |
Прогрессивное улучшение |
На 100%. В худшем случае, все просто откатится к нестилизованному |
Полифилл |
Раньше, когда для этого использовался |
Пример использования
Сначала подключаем возможность, а затем развлекаемся по полной.
select,
::picker(select) {
appearance: base-select;
}
❯ text-wrap
Что это такое?
Свойство text-wrap
в CSS позволяет управлять переносом текста в браузере. Например, text-wrap: balance;
пытается сделать так, чтобы строки текста были как можно более равными по длине.
Зачем это нужно?
Это свойство особенно удобно для элементов с крупным шрифтом, например, заголовков. Оно также помогает избегать «одиночных слов» в конце строки (orphans). Существует еще вариант text-wrap: pretty;
, который предназначен для более длинного текста с небольшим шрифтом (улучшает читаемость). Проще говоря, это способ получить более эстетичную типографику без особых усилий.
Поддержка
Браузеры |
|
Прогрессивное улучшение |
Обязательно. Насколько бы важной мы ни считали типографику, без этих улучшений текст все равно остается читаемым и доступным. |
Полифилл |
Для |
Ресурсы
Джен Симмонс: "Лучшая типографика с
text-wrap: pretty
"Стефани Стимак: "Когда использовать CSS
text-wrap: balance;
и когдаtext-wrap: pretty;
"
❯ linear()
Что это такое?
Здесь может возникнуть небольшая путаница: ключевое слово linear
для transition-timing-function
или animation-timing-function
обычно означает «равномерное и скучное» движение (что иногда как раз требуется, например, при изменении прозрачности). Но функция linear()
позволяет задавать определенную плавность анимации (easing), например, с эффектом «прыжка» или «отскока».
Зачем это нужно?
Даже такая сложная функция, как cubic-bezier()
, позволяет создать лишь ограниченный эффект «отскока» в анимации. Функция linear()
снимает эти ограничения: она может принимать неограниченное количество точек, открывая практически безграничные возможности для настройки плавности анимации.
Поддержка
Браузеры |
Во всех браузерах. |
Прогрессивное улучшение |
Конечно. Можно использовать запасной вариант — именованное значение плавности анимации или |
Полифилл |
Насколько мне известно, нет. Но если очень важны сложные эффекты анимации, библиотеки на JS, например, GSAP, решают эту задачу и работают во всех браузерах. |
Пример использования
.bounce {
animation-timing-function: linear(
0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141 13.6%, 0.25, 0.391, 0.563, 0.765,
1, 0.891 40.9%, 0.848, 0.813, 0.785, 0.766, 0.754, 0.75, 0.754, 0.766, 0.785,
0.813, 0.848, 0.891 68.2%, 1 72.7%, 0.973, 0.953, 0.941, 0.938, 0.941, 0.953,
0.973, 1, 0.988, 0.984, 0.988, 1
);
}
Ресурсы
Джейк Арчибалд: генератор плавности linear()
Маттиас Мартин: Easing Wizard
❯ shape()
Что это такое?
Ранее в CSS существовала функция path()
, которая просто копировала атрибут d
из SVG-элемента <path>
. Она работала только в пикселях и имела довольно запутанный синтаксис. Функция shape()
делает то же самое, но корректно адаптирована для CSS.
Зачем это нужно?
Функция shape()
позволяет создавать практически любые формы. Ее можно использовать в clip-path
, чтобы обрезать элементы по любой фигуре, причем, делать это адаптивно с поддержкой всех возможностей CSS: единиц измерения, кастомных свойств, медиа-запросов и т.д. Также ее можно применять в offset-path()
, чтобы задавать положение и анимацию элементов вдоль любой траектории. В будущем, вероятно, она будет поддерживаться и в shape-outside
.
Поддержка
Браузеры |
Поддерживается в Chrome и Safari, а в Firefox пока отмечена как экспериментальная функция. |
Прогрессивное улучшение |
Скорее всего. Обрезка элементов и движение по траекториям обычно нужны для эстетики и эффектов, поэтому возврат к менее эффектным вариантам вполне допустим. |
Полифилл |
По сути, нет. Лучше предусмотреть хороший запасной вариант. |
Пример использования
Практически любой path SVG можно преобразовать в shape()
:
.arrow {
clip-path: shape(
evenodd from 97.788201% 41.50201%,
line by -30.839077% -41.50201%,
curve by -10.419412% 0% with -2.841275% -3.823154% / -7.578137% -3.823154%,
smooth by 0% 14.020119% with -2.841275% 10.196965%,
line by 18.207445% 24.648236%, hline by -67.368705%,
curve by -7.368452% 9.914818% with -4.103596% 0% / -7.368452% 4.393114%,
smooth by 7.368452% 9.914818% with 3.264856% 9.914818%,
hline by 67.368705%, line by -18.211656% 24.50518%,
curve by 0% 14.020119% with -2.841275% 3.823154% / -2.841275% 10.196965%,
curve by 5.26318% 2.976712% with 1.472006% 1.980697% / 3.367593% 2.976712%,
smooth by 5.26318% -2.976712% with 3.791174% -0.990377%, line by 30.735919% -41.357537%,
curve by 2.21222% -7.082013% with 1.369269% -1.842456% / 2.21222% -4.393114%,
smooth by -2.21222% -7.082013% with -0.736024% -5.239556%,
close
);
}
Естественная адаптивность и более читаемый синтаксис — большое преимущество по сравнению с path()
:
❯ Более мощная функция attr()
Что это такое?
Функция attr()
в CSS позволяет получать строковое значение соответствующего HTML-элемента. Например, с <div data-name="Chris">
можно написать div::before { content: attr(data-name); }
и использовать «Chris» как строку. Но теперь можно задавать типы получаемых значений, что делает функцию гораздо более полезной.
Зачем это нужно?
Теперь из data-атрибутов HTML можно извлекать не только строки, но также числа и цвета:
attr(data-count type(<number>))
Поддержка
Браузеры |
Только Chrome. |
Прогрессивное улучшение |
Зависит от того, как используются значения. Если, например, мы передаем цвет для небольшого декоративного эффекта, это может считаться прогрессивным улучшением, с возможностью отката к запасному варианту или без него. Если же речь идет о критичной для макета информации, то такой подход вряд ли подойдет. |
Полифилл |
Насколько мне известно, нет. |
❯ Поток чтения
Что это такое?
Существуют разные способы изменить расположение элементов так, чтобы визуальный порядок отличался от порядка в исходном коде. Новое свойство reading-order
позволяет изменять порядок элементов, при этом сохраняя предсказуемую навигацию с помощью клавиши Tab
.
Зачем это нужно?
Долгое время все советовали: «Не меняйте порядок элементов в макете». Порядок элементов в исходном коде должен максимально совпадать с визуальным, чтобы фокус при навигации с помощью Tab
менялся логично. Если изменять только визуальный порядок, навигация с клавиатуры может стать хаотичной, вызывать неожиданную прокрутку и снижать доступность. С помощью reading-order
можно сообщить браузеру о внесенных изменениях и задать порядок фокусировки, соответствующий выбранному стилю макета.
Поддержка
Браузеры |
Только Chrome. |
Прогрессивное улучшение |
Не особо. Не стоит кардинально менять порядок элементов в макете, пока эта функция не получила стабильную поддержку во всех браузерах. |
Полифилл |
Нет, но если очень хочется, можно (надеюсь, разумно) обновлять атрибут элементов |
Пример использования
.grid {
reading-flow: grid-rows;
}
Перестановка элементов в сетке — одна из самых распространенных задач, и логично, чтобы порядок навигации с помощью Tab
соответствовал обновленным строкам после изменения порядка. Именно это делает приведенная выше строка кода. При этом значение нужно выбирать в соответствии с используемой раскладкой: например, для Flexbox
стоит указать flex-flow
. Полный список доступных значений см. на MDN.
Ресурсы
Рейчел Эндрю: Поток чтения в Chrome 137
Даниель Шварц: Что мы знаем (на данный момент) о свойстве CSS reading-order
Ди Чжан: Использование CSS-свойства
reading-flow
для логичного последовательного изменения фокуса
❯ Будущие возможности CSS
Макет «Masonry» пока не окончательно стандартизирован, хотя над ним ведется активная работа, и, похоже, результаты мы увидим уже в следующем году. Самое интересное сейчас — предложение
item-flow
, которое может помочь не только с Masonry, но и открыть новые возможности для других способов компоновки элементов за пределами сетки.Функция CSS
random()
уже поддерживается в Safari, и она впечатляет.Свойство CSS
margin-trim
очень удобно, и мы терпеливо ждем, когда его можно будет использовать не только в Safari.Функции
sibling-index()
иsibling-count()
есть в Chrome и, среди прочего, они отлично подходят для создания последовательных анимаций.Свойство
view-transition-name: match-element;
для View Transitions невероятно удобно, так как избавляет от необходимости создавать уникальные имена для каждого элемента. Кроме того, над поддержкой View Transitions работает Firefox.Скоро мы сможем использовать
calc()
для умножения и деления с единицами измерения (без требования, чтобы второй операнд был без единиц измерения), что позволит обойтись без различных обходных решений."CSS4" так и не появилось (Зоран объясняет это очень подробно), но, на мой взгляд, система именованного версионирования все же была бы полезна.
Если вам интересен более наглядный список «новинок CSS» за последние 5 лет, у Адама Аргайла есть отличная подборка.
❯ Возможности CSS, на которые стоит обратить внимание
Контейнерные запросы (и новые единицы) остаются относительно новыми и представляют собой настоящий прорыв после медиа-запросов в CSS.
Псевдокласс
:has()
невероятно полезен для выбора элементов, у которых есть потомки или которые находятся в конкретном состоянии.Суперсовременные возможности CSS, такие как View Transitions, Anchor Positioning и Scroll-Driven Animations, уже доступны в Safari.
Все новые полезные единицы области просмотра (например,
dvh
) теперь поддерживаются по умолчанию.
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩