Функции CSS, за которые мы благодарны, и функции CSS, которые нам нужны

alexei10/10/2022 - 10:08
Функции CSS, за которые мы благодарны, и функции CSS, которые нам нужны

Когда Microsoft закрыла Internet Explorer в июне 2022 года, фронт-энд разработчики вздохнули с облегчением. Смерть IE означала, что теперь разработчики могут спокойно использовать множество интересных функций CSS, и они будут полностью поддерживаться во всех основных браузерах (Chrome, Firefox, Safari, Edge), и при этом не надо беспокоиться о совместимости с IE.

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

Функции CSS, за которые мы благодарны

Отдельные свойства трансформации

Большинство интерфейсных разработчиков знакомы с таким свойством, как transform. У него есть множество вариантов использования - от небольших украшательств (например, диагональной ленты с текстом) до таких вещей, как масштабирование изображения при наведении курсора мыши. Однако до недавнего времени использование этого свойства иногда становилось громоздким, потому что в одной строке приходилось определять несколько значений трансформации.


.optimus-prime {
  inline-size: 250px;
  padding: 2em;
  border-size: 3px;
  border-style: solid;
  background-color: orange;
  border-color: blue;
  transform: rotate(-5deg) translateX(10%) scale(1.2);
}

Если бы вы захотели изменить только одно значение трансформации (например, свойство rotate при состоянии :hover), то вам также пришлось бы определять все остальные свойства.


.optimus-prime:hover {
  transform: rotate(5deg) translateX(10%) scale(1.5);
}

Однако, начиная с Chrome 104 (выпущен в августе 2022 года), эти три свойства – translate, rotate, и scale, теперь могут использоваться как отдельные свойства, что означает меньше кода и проще жизнь.


.optimus-prime:hover {
  rotate: -5deg;
  translate: 10% 0;
  scale: 1.5;
}

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

Псевдоселекторы :is() и :where()

Вам когда-нибудь приходилось применять одни и те же стили к нескольким элементам HTML? Это делало ваш код длинным, запутанным и трудным для чтения? Что ж, теперь эта проблема решена, так как псевдоселекторы :is() и :where() поддерживаются во всех основных браузерах!

Допустим, вы хотите задать цвет всех заголовков внутри элемента <article>:


article h1,
article h2,
article h3 {
  color: rebeccapurple;
}

Благодаря :is() и :where() мы можем записать этот код так:


article :where(h1, h2, h3) {
  color: rebeccapurple;
}

В чем же разница между :is() и :where()? У :where() нет специфичности. У :is() будет такая же специфичность, что и у самого специфичного его аргумента. В следующем примере article h1 примет цвет #ccc:


article h1 {
  color: #ccc;
}

article :where(h1, h2, h3) {
  color: #000;
}

Однако в следующем примере article h1 примет цвет #000:


article h1 {
  color: #ccc;
}

article :is(h1, h2, h3) {
  color: #000;
}

Псевдоселектор :not()

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

Например, с помощью :not() можно добавить отступ внизу каждого элемента списка, кроме последнего элемента. В прошлом разработчик написал бы:


li {
  margin-bottom: 10px;
}

li:last-child {
  margin-bottom: 0;
}

Теперь же подобный блок можно записать следующим образом, сокращая тем самым объем написанного кода:


li:not(:last-child) {
  margin-bottom: 10px;
}

Псевдоселектор :not() стал долгожданным дополнением к инструментарию CSS.

Логические свойства CSS

Хотя логические свойства CSS не совсем "новые" (полностью поддерживаются с 2017 года), они начали становиться фактическим выбором для интерфейсных разработчиков, стремящихся сделать свой код гибким для всех языков и раскладок.

Логические свойства CSS - это модуль CSS, который может управлять раскладкой страницы с помощью логических, а не физических измерений и направлений. Это означает, например, что для определения начала отступа мы используем margin-inline-start, а не margin-left.

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

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


.content {
  margin-right: 20px;
  margin-bottom: 30px;
  padding: 15px 20px;
}

.sidebar {
  border-left: 1px solid #000;
  padding-left: 10px;
}

Но как быть с языками, которые читаются справа налево (RTL)? Вам придется продублировать свой код, изменив направление для полей и отступов и, возможно, добавив дополнительные классы или какие-либо другие контрольные элементы в таблице стилей:


.content-rtl {
  margin-left: 20px;
  margin-bottom: 30px;
  padding: 15px 20px;
}

.sidebar-rtl {
  border-right: 1px solid #000;
  padding-right: 10px;
}

Однако, если вы будите использовать логические свойства CSS, вы сможете ограничить свой код всего двумя селекторами и при этом определить сразу обе раскладки:


.content {
  margin-inline-end: 20px;
  margin-block-end: 30px;
  padding-block: 15px;
  padding-inline: 20px;
}

.sidebar {
  border-inline-start: 1px solid #000;
  padding-inline-start: 10px;
}

Предпочитаемый пользователем язык настроен в браузере, поэтому еще до того, как ваш CSS будет сгенерирован, браузер уже знает, в каком направлении пользователь предпочитает читать текст. Например, используя border-inline-start, браузер помещает рамку в начало горизонтальной области контента, независимо от направления, так что для посетителей, предпочитающих LTR текст, она будет находиться в левой части боковой панели, но для RTL посетителей она будет справа, потому что именно там у них появляется боковая панель.

CSS ограничение строки

Свойство -webkit-line-clamp это маленький хитрый трюк, который делает отображение текста тизера гораздо более управляемой задачей.

Включенный в браузеры Chrome еще в 2011 году, этот "один маленький трюк, который авторы плагинов jQuery терпеть не могут" позволяет создать абзац из четырех строк, заканчивающийся многоточием. И он работает во всех современных браузерах:


.my-text-block {
  display: -webkit-box;
  text-overflow: ellipsis;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

Да, вы прочитали правильно. Даже Firefox примет и отобразит префиксы -webkit для всех этих свойств. Хотя официально эта функция не входила в спецификацию CSS, она поддерживалась настолько широко, что к 2019 году она работала везде (кроме IE, конечно). Ведется работа по добавлению свойства ограничения строки в CSS, но если это произойдет, все равно обратная поддержка для -webkit-line-clamp останется.

CSS функции, которые нам все еще нужны

Подсетка

Сетки CSS являются частью инструментария веб-разработчиков с 2017 года. Но что сделало бы сетки еще более мощными? Возможность выравнивать элементы внутри сетки по самой сетке. В настоящее время это невозможно. Сейчас, без подобной подсетки, разработчики для выравнивания элементов внутри сетки прибегают к добавлению полей, отступов и т.п. методы.

Подсетка облегчила бы жизнь многих веб-разработчиков, которым приходится создавать сетку внутри сетки. Со значением grid-template-rows: subgrid все внутри сетки идеально выравнивается, если для любого элемента сетки вы хотите использовать ту же сетку, что и для его родительского элемента. (Это тоже работает и для grid-template-columns.)

Вы можете увидеть подсетку в действии, если просмотрите следующий код Codepen в Safari 16 или Firefox. Содержимое карточки 2 длиннее, чем на карточках 1 и 3, и в идеале мы хотели бы, чтобы ссылка внизу была выровнена по одной и той же линии сетки во всех трех карточках. В браузере, поддерживающем подсетку, вы увидите, что включение подсетки позволяет выровнять содержимое внутри карточки по той же сетке, что и сами карточки:

По состоянию на сентябрь 2022 года подсетка поддерживается только в Firefox и в новейшей версии Safari.

Контейнерные запросы

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

Чтобы использовать контейнерные запросы, сначала определяем свой контейнер:


.my-fantastic-container {
  container-type: inline-size;
  container-name: main-container;
}

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


@container main-container (min-width: 768px) {
  .card {
    width: 50%;
  }
}

Теперь, когда размер контейнера .my-fantastic-container будет 768px или больше, ширина карточки будет 50%.

Поддержку контейнерных запросов планируется добавить в Safari 16 и Chrome 106, которые должны выйти ближе к концу 2022 года.

Улучшенный псевдоселектор :has()

По состоянию на середину 2022 года, благодаря поддержке Safari и Chrome (с расширенными настройками), в развитии :has() был достигнут значительный прогресс. Но Firefox, Edge и Chrome (с обычными настройками) не поддерживают этот псевдоселектор.

Если вы не знаете, что делает :has(), то если коротко, то данный псевдоселектор позволяет вам настроить условие для чего-то, что содержит определенный другой элемент.

Например, вы можете настроить определенный стиль для всех элементов <p>, внутри которых есть элемент img.

Это невероятно полезно! Однако в настоящее время у параметров :has() отсутствует возможность применения их специфики.

Допустим, у вас есть неупорядоченный список, содержащий не менее десяти элементов, который нужно вывести в 2 столбца. Следующий код отлично подошел бы, если бы он работал:


ul:has(li:nth-child(10)) {
  column-count: 2;
}

Данная раскладка с :has() должна бы работать, но ограничения в браузерах препятствуют этому. Вот пример CodePen, который продемонстрирует, что на данный момент это будет работать только в Safari и Chrome:

В Safari и Chrome вы увидите три аккуратных столбца со штатами США, но в остальных браузерах это будет просто длинный список. И все потому, что специфика nth-child игнорируется в :has(). Это может быть крайним случаем, но без этого вы не сможете использовать :has() в полную силу. Мы надеемся, что как только этот псевдоселектор получит повсеместную поддержку, он продолжит развиваться и когда-нибудь станет более полезным.

Реальное свойство CSS для программ чтения с экрана

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

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


.hidden-text-block {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  clip-path: inset(50%);
  border: 0;
}

Должен быть лучший способ сделать это. Почему бы не использовать идею с классом .visually-hidden и не превратить его в отдельное свойство?


.hidden-text-block {
  visually-hidden: true;
}

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

Свойство color-contrast()

Продолжая тему доступности, стоит упомянуть свойство color-contrast, которое принимает заданное цветовое значение, а затем сравнивает его с двумя наборами цветов, выбирая цвет с наибольшим контрастом.

Например, в следующем примере сравниваются цвета #404040 и #5a5a5a с цветом #111, а затем выбирается более контрастный:


.header-color {
  color-contrast: (#404040 vs #5a5a5a, #111);
}

Можно увидеть, как это может действительно хорошо работать с набором цветовых переменных :root по сравнению с различными фоновыми цветами, предоставляя возможность сохранять цвета доступными без каких-либо переписанных стилей или других плагинов JS.


--primary-color: blue;
--secondary-color: green;
--main-bg: #4a4a4a;
--sidebar-bg: #32a3fa;

.text-color {
  color-contrast: (--main-bg vs --sidebar-bg, --primary-color);
}

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

Изменение неанимируемых свойств в начале/конце анимации

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

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

Проблема в том, что обычные свойства CSS показывающие/скрывающие элемент, такие как display: none или visibility: hidden, не учитываются в начале/конце анимации.


.ghost-kitty {
  inline-size: 2rem;
  block-size: 4rem;
  background: url("../images/ghost_cat.jpg") no-repeat center;
  animation: ghost-kitty 5s infinite;
}

@keyframe ghost-kitty {
  0% {
    opacity: 100%;
  }
  25% {
    opacity: 75%;
  }

  50% {
    opacity: 50%;
  }

  75% {
    opacity: 25%;
  }

  100% {
    opacity: 0%;
    display: none;
  }
}

В приведенном выше примере, элемент .ghost-kitty исчезнет (навсегда), как только будет выполнено свойство display: none в последнем ключевом кадре анимации, тем не менее этот элемент все равно будет виден для программ чтения с экрана, потому что он был сгенерирован при формировании документа, что противоречит целям анимации. И поскольку свойство opacity, которое обычно используется в анимации, не работает с программами чтения с экрана, мы попадаем в тупик, выход из которого при помощи CSS найти не получится, и мы не можем действительно что-то скрыть/показать для всей аудитории.

Возможно, что как и в случае с :has(), :is() и :where() по мере роста использования появится какой-нибудь странный хак, чтобы заставить все это работать (например, line-clamp), но было бы неплохо иметь полезный способ по-настоящему контролировать неанимируемые свойства в анимации!

text-wrap: balance

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

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

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

Пока text-wrap: balance это только запрошенная спецификация, но давайте скрестим пальцы, чтобы она все же появилась как можно раньше!

Разбейте box-shadow, чтобы можно было задавать его стили раздельно

Это скорее пожелание, чем необходимость, но было бы неплохо определять каждое значение box-shadow независимо друг от друга. Как это делается с рамками, когда вы можете определить рамку либо при помощи краткого свойства (например, border: 1px solid rebeccapurple), либо задать каждое значение индивидуально:


border-width: 1px;
border-style: solid;
border-color: rebeccapurple

Возможность декларировать box-shadow, например, таким образом была бы весьма полезной:


box-shadow-color: rebeccapurple;
box-shadow-offset-x: 2px;

// Такие комментарии

Серьезно, почему у нас есть только /* */ такие комментарии?

Заключение

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