Мы публиковали статью «Что нужно знать о современном 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.

Прогрессивное улучшение

Да. Обычно такого рода анимация не является критически важной — скорее, приятным бонусом.

Полифилл

По сути, нет. Старые костыли включали, например, анимацию max-height до значения «с запасом» или использование JS, чтобы измерить реальный размер где-то «за кадром» и потом анимировать до этого числа. Оба варианта, мягко говоря, так себе.

❯ Поповеры и вызывающие элементы

Это два независимых и полезных инструмента, в первую очередь, связанных с 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.

Прогрессивное улучшение

Это зависит от того, для чего будет использоваться значение. В простых случаях это может выглядеть так: property: fallback; property: --function();

Полифилл

Не совсем. У Sass есть свои функции, но они основаны на другой спецификации и работают иначе.

Другие ресурсы

❯ if()

Что это такое?

CSS и так уже содержит элементы условной логики: селекторы применяют стили только к подходящим элементам, а медиа-запросы срабатывают, когда выполняются их условия.

Однако функция if() — это первый специальный логический инструмент, предназначенный именно для создания условных ветвлений в CSS.

Зачем это нужно?

Как и все функции, включая пользовательские @function, if() возвращает одно значение. Ее синтаксис помогает сделать код более читаемым и избежать дублирования выражений.

Поддержка

Браузеры

Только Chrome.

Прогрессивное улучшение

Это зависит от того, с каким свойством или значением используется if(). Если приемлемо запасное значение, такой подход можно применять: property: fallback; property: if( style(--x: true): value; else: fallback; );

Полифилл

Не совсем. В 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, что вполне допустимо.

Полифилл

Раньше, когда для этого использовался selectlist, полифилл был нужен. Но, по моему мнению, сейчас прогрессивное улучшение работает так хорошо, что он уже не требуется.

Пример использования

Сначала подключаем возможность, а затем развлекаемся по полной.

select,
::picker(select) {
  appearance: base-select;
}

❯ text-wrap

Что это такое?

Свойство text-wrap в CSS позволяет управлять переносом текста в браузере. Например, text-wrap: balance; пытается сделать так, чтобы строки текста были как можно более равными по длине.

Зачем это нужно?

Это свойство особенно удобно для элементов с крупным шрифтом, например, заголовков. Оно также помогает избегать «одиночных слов» в конце строки (orphans). Существует еще вариант text-wrap: pretty;, который предназначен для более длинного текста с небольшим шрифтом (улучшает читаемость). Проще говоря, это способ получить более эстетичную типографику без особых усилий.

Поддержка

Браузеры

balance поддерживается во всех браузерах, а pretty пока работает только в Chrome и Safari.

Прогрессивное улучшение

Обязательно. Насколько бы важной мы ни считали типографику, без этих улучшений текст все равно остается читаемым и доступным.

Полифилл

Для balance такая возможность есть.

Ресурсы

❯ linear()

Что это такое?

Здесь может возникнуть небольшая путаница: ключевое слово linear для transition-timing-function или animation-timing-function обычно означает «равномерное и скучное» движение (что иногда как раз требуется, например, при изменении прозрачности). Но функция linear() позволяет задавать определенную плавность анимации (easing), например, с эффектом «прыжка» или «отскока».

Зачем это нужно?

Даже такая сложная функция, как cubic-bezier(), позволяет создать лишь ограниченный эффект «отскока» в анимации. Функция linear() снимает эти ограничения: она может принимать неограниченное количество точек, открывая практически безграничные возможности для настройки плавности анимации.

Поддержка

Браузеры

Во всех браузерах.

Прогрессивное улучшение

Конечно. Можно использовать запасной вариант — именованное значение плавности анимации или cubic-bezier().

Полифилл

Насколько мне известно, нет. Но если очень важны сложные эффекты анимации, библиотеки на 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
  );
}

Ресурсы

❯ 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.

Прогрессивное улучшение

Не особо. Не стоит кардинально менять порядок элементов в макете, пока эта функция не получила стабильную поддержку во всех браузерах.

Полифилл

Нет, но если очень хочется, можно (надеюсь, разумно) обновлять атрибут элементов tabindex, чтобы задать логичный порядок фокусировки.

Пример использования

.grid {
  reading-flow: grid-rows;
}

Перестановка элементов в сетке — одна из самых распространенных задач, и логично, чтобы порядок навигации с помощью Tab соответствовал обновленным строкам после изменения порядка. Именно это делает приведенная выше строка кода. При этом значение нужно выбирать в соответствии с используемой раскладкой: например, для Flexbox стоит указать flex-flow. Полный список доступных значений см. на MDN.

Ресурсы

❯ Будущие возможности 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, на которые стоит обратить внимание


Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале

Комментарии (0)