CSS в 2023: что изменилось за последние несколько лет

Аватарка пользователя Елизавета Ржевская

Рассказали о нововведениях в CSS в 2023 году: какие оказали большое влияние на текущие методы работы с CSS, а какие не изменили ничего.

Lead Noveo Developer Екатерина старается всегда быть в курсе актуальных тенденций в мире HTML/CSS-разработки и щедро делится знаниями с коллегами. Предлагаем вашему вниманию ее перевод статьи о том, какие из новых функций CSS прижились в программировании эксперта, а какие для существуют пока скорее в теории. А что из этого списка используете вы?

О чем пойдет речь: CSS развивается быстрее, чем когда-либо. Новые функции, появившиеся в нашем распоряжении за несколько лет с момента появления Flexbox и Grid (и те, которых мы ждем в будущем), меняют и способы написания CSS. В этой статье Geoff Graham рассказывает, какие нововведения оказали самое большое влияние на его текущие методы работы с CSS, а какие не изменили ничего (по крайней мере, пока).

Есть ли в мире фронтенда что-нибудь, что развивается быстрее, чем CSS в наши дни? После долгого затишья, последовавшего за блокбастерами Flexbox и Grid, наблюдать за выпуском новых функций CSS за последние несколько лет было все равно что смотреть неистовый матч по регби по телевизору. Темп захватывающий, но в то же время не ошеломляющий.

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

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

Я ни в коем случае не хочу преуменьшать значимость достижений последних лет и сам в восторге от того, как развивается CSS. Многих из новых фич мы жаждали много-много лет. И, действительно, некоторые из них находят свое место в моем CSS. Повторюсь, изменения не радикальные, но достаточные, чтобы мне нравилось писать CSS сейчас больше, чем когда-либо.

Позвольте мне перечислить эти перемены.

Все больше и больше контейнерных запросов (Container Queries)

Скажу так: мне никогда не нравилось писать медиавыражения для адаптивных макетов. Контент по-разному реагирует на ширину области просмотра в зависимости от компонента, в котором размещен. А балансировка контента в одном компоненте всегда приводит к балансировке контента и в других компонентах, вызывая путаницу медиавыражений в, казалось бы, произвольных точках останова. Вложение медиавыражений в селектор с помощью Sass сделало это более приемлемым, но не настолько, чтобы мне действительно “нравилось” каждый раз переписывать и изменять существующие запросы, когда мне передают новый дизайн с изменениями в пользовательском интерфейсе.

Контейнерные запросы (Container Queries) – это именно то, что мне нужно. Теперь я могу ограничивать дочерние элементы контейнера и полагаться на его размер, чтобы определить, когда происходит сдвиг макета, не обращая внимания на другие окружающие компоненты.

Еще одна вещь, которая мне нравится в контейнерных запросах, – это их ‘CSS-подобие’. Определение контейнера непосредственно в селекторе соответствует естественному синтаксису свойств и значений и помогает мне избежать необходимости предварительно вычислять математические параметры для определения точек разрыва.
			.parent {
  container-type: inline-size;
}

@container (min-width: 600px) {
  .child {
    align-self: center;
  }
}
		

Я всё ещё использую медиавыражения для создания адаптивных макетов, но обычно оставляю их для ‘больших’ макетов, составленных из контейнеров. Точки разрыва более предсказуемы (и на самом деле можно более явно нацеливаться на конкретные устройства), когда нет необходимости учитывать, что происходит внутри каждого отдельного контейнера.

Подробнее о контейнейрных запросах:

  1. CSS Containment Module Level 3 (W3C)
  2. A Primer On CSS Container Queries”, Stephanie Eckles
  3. CSS Container Queries: Use-Cases And Migration Strategies”, Adrian Bece
  4. A Cornucopia of Container Queries”, Geoff Graham  

Группировка стилей в слоях

Мне нравится этот способ управления каскадом! Теперь, если у меня есть сброс стилей или какие-либо сторонние CSS из фреймворка или чего-либо еще, я могу упаковать их в слой каскада и переместить в конец файла, чтобы мои собственные стили оказались впереди и в центре внимания.

Пока я не использовал каскадные слои в продакшене, но почти всегда обращаюсь к ним при создании демонстраций в CodePen. Поддержка браузера есть, так что это не проблема. Скорее я всё ещё полагаюсь на Sass для определенных возможностей в проектах, и поддержка стилей в частичных файлах по-прежнему кажется мне удобной, по крайней мере, для такой работы.

Но в изолированной демонстрации, где все мои стили находятся в одном месте, как на CodePen, – да, все слои каскада, пожалуйста! На самом деле мне действительно нужен только один слой для базовых стилей, так как стили без слоев имеют более высокую специфичность, чем стили со слоями. Так мои специфичные для демонстрации стили остаются чистыми, не перегруженными и всё еще способными переопределять базовые стили вверху, что делает их гораздо более удобными для доступа.

			body {
  display: grid;
  gap: 3rem;
  place-items: center;
}

@layer base {
  body {
    font-size: 1.25rem;
    line-height: 1.35;
    padding: 3rem;
  }
}
		

Подробнее о каскадных слоях:

  1. A Complete Guide to CSS Cascade Layers”, Miriam Suzanne
  2. Getting Started With CSS Cascade Layers”, Stephanie Eckles
  3. CSS Cascading and Inheritance Level 5 (W3C) 
  4.  “Cascade Layers Are Coming To Your Browser”, Una Kravets  

:is() и :where()

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

Почему? Потому что в :is() специфичность определяется не основным селектором, а наиболее конкретным селектором в списке аргументов.

			/* Specificity: 0 1 1 */
:is(ol, .list, ul) li {}

/* Specificity: 0 0 2 */
ol li {}
		

Селектор .list дает первому набору правил более высокий балл специфичности, что означает, что он «превосходит» второй набор правил, даже если первый набор правил находится выше в каскаде.

С другой стороны, особенностью :where() является старый нулевой балл, поэтому он не добавляется к общему баллу любого селектора, на котором находится. На самом деле не имеет значения, что находится в его аргументе. По той же причине, по которой я использую :is() для увеличения специфичности, я использую :where() для ее уменьшения. Мне нравится, когда специфичность в целом низкая, потому что я все равно хочу, чтобы каскад работал с минимальным сопротивлением, и :where() позволяет добиться этого, особенно при определении глобальных стилей.

Прекрасным примером является обертывание :not() внутри :where(), чтобы :not() не повышал специфичность:

			/* Specificity: 0 0 0 */
:where(:not(.some-element)) {}
		
Взятые вместе, :is() и :where() не только помогают управлять специфичностью, но и уменьшают когнитивную нагрузку на ‘именование’ вещей.

Я из тех людей, которые до сих пор любят синтаксис BEM, но именование – как раз одна из самых сложных в нем вещей. Часто оказываюсь в ситуации, когда не хватает подходящих имен, чтобы описать функцию элемента и его отношение к окружающим элементам. Специфичные возможности :is() и :where() позволяют мне реже зависеть от замысловатых имен классов и больше использовать селекторы элементов вместо этого.

Подробнее о :is() И :where()

  1. CSS-Tricks Almanac: :is()”, Geoff Graham
  2. CSS-Tricks Almanac: :where()”, Chris Coyier
  3. Is “is” Useful?”, Chris Coyier
  4. Using The Specificity Of :where() As A CSS Reset”, Mojtaba Seyedi  

Новый синтаксис функции цвета

Обновленный синтаксис для цветовых функций, такой как rgb() и hsl() (а также развивающийся oklch() и oklab()), не является прямо таки уж сногсшибательным новшеством, но действительно упрощает определение значений цветов.

Во-первых, мне больше не приходится прибегать к rgba() или hsla(), когда мне нужно значение альфа-канала. Фактически я всегда использовал их, независимо от того, нужен ли мне альфа-канал, потому что не хотел тратить время на выбор версии.

			color: hsl(50deg, 100%, 50%);

/* Same */
color: hsla(50deg, 100%, 50% / 1)
		

Да, нужно дополнительно прописывать a, / и 1, зато не приходится думать о том, какую функцию использовать.

Но обновленный цветовой синтаксис похож на медоеда: ему все равно. Его не волнует лишняя буква a в имени функции. Его даже запятые не волнуют.

			color: hsl(50deg 100% 50% / .5);
		

Так что да, это определенно изменило мой способ написания цветов в CSS. А новые цветовые пространства oklch() и oklab(), которые теперь полностью поддерживаются браузерами, я жду с нетерпением!

Подробнее о возможностях CSS color 4:

  1. CSS Color Module Level 4 (W3C)
  2. A Guide To Modern CSS Colors With RGB, HSL, HWB, LAB And LCH”, Michelle Barker
  3. Using HSL Colors In CSS”, Ahmad Shadeed
  4. A Whistle-Stop Tour Of 4 New CSS Color Features”, Chris Coyier  

Выявление пользовательских предпочтений

Думаю, многие из нас обрадовались, получив медиавыражения, учитывающие предпочтения пользователя по отображению контента, ключевым из которых является предпочтительная цветовая схема для быстрого создания темных и светлых интерфейсов.

			:root {
  --bg-color: hsl(0deg 0% 100%);
  --text-color: hsl(0deg 0% 0%);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: hsl(0deg 0% 0%);
    --text-color: hsl(0deg 0% 100%);
  }
}

body {
  background: var(--bg-color);
  color: var(--text-color);
}
		

Однако самое сильное влияние на мой CSS оказал запрос prefers-reduced-motion. Это первое, о чем я думаю, когда проект включает анимации и переходы с использованием CSS. Мне нравится идея того, что уменьшение движения не означает полное отключение анимации, поэтому я часто использую prefers-reduced-motion, чтобы замедлить всё, когда это необходимо. Это означает, что у меня есть что-то подобное (обычно в слое каскада для базовых стилей):

			@layer base {
  :root {
    --anim-duration: 1s;
  }

  /* Reduced motion by default */
  body {
    animation-duration: --anim-duration;
    transition: --anim-duration;
  }

  /* Opt into increased motion */
  @media screen and (prefers-reduced-motion: no-preference) {
    body {
      --anim-duration: .25s;
    }
  }
}
		

Подробнее о запросах пользовательских предпочтений:

  1. Respecting Users’ Motion Preferences”, Michelle Barker
  2. Designing With Reduced Motion For Motion Sensitivities”, Val Head
  3. A DRY Approach To Color Themes In CSS”, Christopher Kirk-Nielsen
  4. A Complete Guide to Dark Mode on the Web”, Adhuham  

Определение цветовых палитр

Я использовал переменные для определения и назначения цветов с тех пор, как начал работать с Sass, и был в восторге, когда появились пользовательские свойства CSS. Я давал цветам в палитре общие имена, прежде чем передавать их переменным с более функциональными именами.

			/* Color Palette */
--red: #ff0000;
/* etc. */

/* Brand Colors */
--color-primary: var(--red);
/* etc. */
		

Я до сих пор так делаю, но теперь я абстрагирую вещи еще дальше, используя цветовые функции в проектах с большими палитрами:

			:root {
  /* Primary Color HSL */
  --h: 21deg;
  --s: 100%;
  --l: 50%;
  
  --color-primary: hsl(var(--h) var(--s) var(--l) / 1);
}

.bg-color {
  background: var(--color-primary);
}

.bg-color--secondary {
  --h: 56deg;
  background: hsl(var(--h) var(--s) var(--l) / 1);
}
		

Небольшой перебор с абстрагированием? Возможно. Но для проектов, в которых может быть десять разных оттенков красного, оранжевого, желтого и так далее, приятно иметь такой уровень тонкой настройки для манипуляций с ними. Возможно, больше контроля дает color-mix(), который я просто еще не исследовал.

Подробнее об определении цветовых палитр

  1. Simplify Your Color Palette With CSS Color-Mix()”, Daniel Yuschick
  2. How To Configure Application Color Schemes With CSS Custom Properties”, Artur Basak
  3. CSS Color Manipulation Functions, Please Save Us From The CSS Custom Property Gotcha”, Chris Coyier  

Что я не использую

Ого, кажется, я действительно пишу CSS немного по-другому, чем раньше! Сам я это слабо ощущаю, но, возможно, это связано с тем, что появилось и много новых функций, которые пока не использую. Количество нововведений, которые я использую, гораздо меньше тех, которые мне еще предстоит освоить, будь то из-за поддержки браузера или потому, что я просто еще до них не дошел.

CSS-Вложение

Я очень его жду, потому что это может стать переломным моментом, когда я полностью откажусь от Sass в пользу ванильного CSS. На момент написания этой статьи Firefox ожидает его поддержки, так что это может быть уже не за горами.

Стилевые запросы

Я не скрывал, что применение стилей к элементам на основе стилей других элементов меня действительно интересует. Это может представлять скорее академический интерес, поскольку конкретные варианты использования запросов стиля ускользают от меня. Возможно, ситуация изменится, когда они получат поддержку браузеров, и мы увидим гораздо больше сообщений в блогах, в которых умные люди экспериментируют с ними.

:has()

Я определенно буду использовать это, когда появится поддержка в Firefox. До тех пор я просто поигрался с этим сам и наслаждался тем, как экспериментируют другие. Без полной поддержки, однако, влияния на способ, которым я пишу CSS, это не оказало. Но ожидаю, что это произойдет, потому что возможность выбирать родительский элемент на основе содержащегося в нем дочернего элемента не может быть плохой идеей, правда?

Динамические единицы просмотра

Начиная с того момента, когда они получили широкую поддержку в конце 2022 года, я начал внедрять их в свои стили. Как и в случае с запросами стиля, вижу ограниченное применение — особенно при установке элементов на полную высоту на мобильном устройстве. Так что вместо того, чтобы использовать height: 100vh, я все чаще пишу height: 100dvh. Думаю, это повлияло на то, как я пишу CSS, пусть и незначительно.

Синтаксис диапазона медиавыражений

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

Цветовые пространства OKLCH и OKLAB

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

Единственная проблема, которую я вижу, касается того, что oklch() несовместим с другой интересной для меня функцией цветов, а именно…

color()

Она теперь имеет широкую поддержку, начиная с мая 2023 года! Это слишком ново, чтобы немедленно использовать его в моем повседневном CSS, но можно быть уверенным, что это произойдет. Возможность работать с любым цветовым пространством, будь то sRGB, Display P3 или Rec2020, намного удобнее, чем использовать конкретные функции цвета, по крайней мере для цветов в цветовых пространствах с каналами RGB (поэтому color() несовместима с oklch() и другими цветовыми пространствами, не являющимися RGB).

			--primary-color: color(display-p3 1 0.4 0);
		

Я не в восторге от значений RGB, потому что их трудно понять, в отличие, от HSL. Уверен, что в большинстве случаев всё равно буду использовать oklch() или hsl() именно по этой причине. Жаль, что мы не можем делать что-то подобное:

			/* ???? */
--primary-color: color(oklch 70% 0.222 41.29);
		

Вместо этого мы должны сделать так:

			/* ???? */
--primary-color: oklch(70% 0.222 41.29);
		

The confusing thing about that is it’s not like Display P3 has its own function like OKLCH:

			/* ???? */
--primary-color: display-p3(1 0.434 0.088);
		

Мы вынуждены использовать color() для подключения к Display P3. Это противоречит OKLCH/OKLAB, где мы вынуждены использовать эти конкретные функции.

Возможно, однажды у нас появится глобальная функция color(), которая будет поддерживать их все! А до тех пор мой CSS будет использовать как color(), так и специальные функции, такие как oklch(), и решать, какая из них лучше всего подходит для того, над чем я работаю.

Также добавлю в эту корзину функцию color-mix(), поскольку она получила полную поддержку одновременно с функцией color(). Я пока не использую ее регулярно, но обязательно поиграю с ней – вероятно, для создания цветовых палитр.

Почетные упоминания

Было бы настоящим подвигом прокомментировать каждую новую функцию CSS, появившуюся за последние пять лет или около того. Когда речь идет о функциях, которые я не использую в повседневной работе, лейтмотивом звучит, что они слишком новы или им не хватает поддержки браузера. Это не означает, что я не буду их использовать (вероятно, буду!), но пока что всего лишь наблюдаю за ними с интересом или просто весело провожу время, экспериментируя с ними.

Сюда включаются:

  • тригонометрические функции;
  • положение якоря; 
  • анимации, связанные с прокруткой;
  • initial-letter;
  • и ;
  • переходы между видами;
  • ограниченные стили.

А вы? Вы ведь, наверное, сейчас сами используете CSS не так, как пять лет назад, верно? Меняете ли вы свой подход к работе с каскадом? Пишете ли больше обычного CSS, без использования препроцессоров? А как насчет типографии, контроля за межстрочным интервалом и масштабом? Расскажите мне или, лучше, продемонстрируйте, как в настоящее время вы используете CSS.

Веб-разработка
CSS
Веб-дизайн
2595