Недавно мы рассказывали про CSS-свойства, которые появились в 2023 году. Но нового так много, что мы сделали продолжение.
Пока эти свойства поддерживаются не всеми браузерами. Прежде чем использовать что-то в своём проекте, проверьте поддержку свойства на сайте Can I Use.
Динамические единицы измерения области просмотра
В CSS есть относительные единицы измерения, которые зависят от viewport — размера окна браузера, то есть видимой части документа:
vh
— viewport height, высота;vw
— viewport width, ширина;vmin
— размер в процентах от меньшей размерности;vmax
— размер в процентах от большей размерности.
Проблема с этими единицами в том, что они не всегда учитывают особенности мобильных устройств. Например, если смартфон не скрывает навигационные панели, а в макете задана высота 100vh
, то область просмотра оказывается меньше нужной и контент не вмещается:
Для решения этой проблемы были определены новые состояния: большой экран просмотра и малый экран просмотра — и введены новые единицы:
svh
иsvw
— наименьший активный размер области просмотра (small viewport height/width);lvh
иlvw
— наибольший активный размер области просмотра (large viewport height/width).
Единицу измерения svh
можно использовать для заполнения экрана, когда размер экрана на устройстве пользователя слишком большой, а контента мало. Это удобное свойство для адаптивного дизайна в мобильных браузерах с динамическими панелями инструментов.
Также есть новые динамические единицы dvh
и dvw
:
- Когда динамические панели инструментов развёрнуты, динамическая область просмотра равна размеру маленькой области просмотра.
- Когда динамические панели инструментов убраны, динамическое окно просмотра равно размеру большого окна просмотра.
Посмотреть, как работают динамические единицы в реальности, можно в этом видео:
⚠️ Динамические единицы нужно использовать с большой осторожностью: с ними размер контента может меняться, например, когда пользователь прокручивает страницу.
Тригонометрические функции
С помощью тригонометрических функций удобно управлять функциями трансформации, задавать параметры анимаций, рисовать фигуры, управлять компонентами и даже генерировать случайные значения.
Раньше это делали в препроцессорах, а теперь тригонометрические функции доступны прямо в CSS.
Что появилось:
cos()
возвращает косинус угла, значение которого находится в диапазоне от –1 до 1;sin()
возвращает синус угла, значение которого находится в диапазоне от –1 до 1;tan()
возвращает тангенс угла, значение которого находится в диапазоне от –∞ до ∞.
Также есть функции, которые выполняют вычисления в обратном порядке: asin()
, acos()
, atan()
и atan2()
.
Представим, что мы хотим нарисовать треугольник — в качестве элемента дизайна сайта или для иллюстрации статьи о треугольниках. Для этого нам нужно знать размер угла, длину гипотенузы, противолежащей и прилежащей сторон. Зададим угол 30° и гипотенузу (самую длинную сторону треугольника), равную 8rem
, то есть в 8 раз больше, чем шрифт корневого элемента. Дальше может быть немного сложно, поэтому следите за руками.
Прописываем HTML-структуру нашего элемента:
<figure>
<div class="triangle"></div>
<figcaption>
<span>Угол: 30 градусов</span> <span>Гипотенуза: 8rem</span>
</figcaption>
</figure>
Задаём стили для размера области рисунка в CSS-файле:
figure {
--size: 20rem;
width: var(--size);
height: var(--size);
}
Мы определили переменную --size
и через неё задали высоту и ширину рисунка.
Далее внутри элемента triangle
задаём переменные, с которыми будем работать, и стили:
.triangle {
--hypotenuse: 8rem;
--angle: 30deg;
--opposite: calc(sin(var(--angle)) * var(--hypotenuse));
--adjacent: calc(var(--hypotenuse) / 2);
Здесь мы описали основные элементы треугольника:
--hypotenuse
: установили длину гипотенузы треугольника.--angle
: задали угол между гипотенузой и одним из катетов треугольника.--opposite
: использовали математическую функцию calc(), которая умножает значение синуса угла, вычисленного с помощью функции sin(), на длину гипотенузы. Так мы получили длину противолежащей стороны треугольника.--adjacent
: вычислили длину прилежащей стороны треугольника.
Теперь нужно определить переменные для расчёта координат вершин треугольника. В этом же блоке кода прописываем следующие вычисления:
--startPosX: calc(var(--size) / 2 - var(--adjacent));
--startPosY: calc(var(--size) / 2 - var(--opposite) / 2);
--endPosX: calc(var(--size) / 2 + var(--adjacent));
--endPosY: calc(var(--size) / 2 + var(--opposite) / 2);
Здесь мы указали инструкции для вычисления начальных и конечных координат треугольника по оси X и Y.
Теперь осталось нарисовать треугольник. В том же элементе .triangle
прописываем:
--clip: polygon(
var(--startPosX) var(--endPosX),
50% var(--startPosY),
var(--endPosX) var(--endPosY)
);
clip-path: var(--clip);
height: inherit;
background: deeppink;
}
--clip
: задали переменную, которая используется для создания строки с координатами вершин треугольника для свойстваclip-path
. Так мы формируем треугольник с помощью координат вершин.clip-path
: установили обрезку элемента в форме треугольника с использованием значения переменной--clip
.height
: высота треугольника наследуется от родительского элемента, в данном случае отfigure
.background
: цвет фона.
Теперь в зависимости от требований можно менять угол и размер треугольника, а функции calc()
и sin()
всё посчитают за нас.
Есть интересный проект — анимированная лента Мёбиуса Аны Тюдор. В нём cos()
и sin()
используются для управления компонентами функции цвета hsl()
.
Можно посмотреть пошаговое создание такой анимации и сделать свою:
Индивидуальные свойства трансформации
Теперь трансформации (свойство transform
) можно разделять и применять по отдельности.
Представим, что мы хотим сместить треугольник из предыдущего примера и добавить дополнительное свойство при наведении курсора — изменение масштаба.
Тогда нужно было бы писать так:
.triangle {
transform: translateX(50%) rotate(30deg) scale(1.2);
}
.triangle:hover {
transform: translateX(50%) rotate(30deg) scale(2);
}
При ховере изменяется только масштаб, но мы должны повторить для него все свойства transform
. Код дублируется.
Теперь же можно написать более компактный код:
.triangle {
translate: 50% 0;
rotate: 30deg;
scale: 1.2;
}
.triangle:hover {
scale: 2;
}
При ховере перезаписалось только свойство scale
, а остальные свойства трансформации так и остались применёнными к элементу.
Отдельные свойства трансформации удобны, когда есть большая анимация в CSS. В этом случае можно настроить преобразование на каждом шаге анимации.
Продвинутый синтаксис nth-child
Псевдоклассы группы child
позволяют выбирать дочерние элементы не по классу или тегу, а по порядковому номеру. Например, такой синтаксис :nth-child(2)
— обращается ко второму дочернему элементу в родительском контейнере.
Новый продвинутый синтаксис nth-child
позволяет добавлять ещё и класс элемента. Для этого используется ключевое слово of
в скобках.
Представим, что у нас есть секция с фигурами:
<section class="main">
<div class="circle"></div>
<div class="circle"></div>
<div class="square"></div>
<div class="square"></div>
<div class="circle"></div>
<div class="square"></div>
<div class="circle"></div>
</section>
Внутри секции мы хотим обратиться ко второму элементу square
.
Тогда мы пишем так:
section :nth-child(2 of .square) {
background: rgb(0, 207, 83);
}
Мы сказали браузеру зайти в контейнер section
, выбрать там все элементы .square
и поменять цвет фона у второго элемента.
Это даёт ещё большую гибкость при стилизации и избавляет от необходимости писать дополнительные стили, чтобы обращаться к каким-либо элементам.
Стили с ограниченной областью видимости
Ключевое слово @scope
позволяет создавать пространства имён и задавать стили с ограниченной областью видимости, например, чтобы они применялись в определённой части страницы, ограниченные выбранными элементами. Так можно явно задавать границы стиля и не множить в проекте селекторы с высокой специфичностью, которые потом будет сложно переопределить, если макет изменится.
Область действия задается двумя параметрами: корнем области и пределом области. Корень области действия (<scope-start>
) определяет узел документа, где начинают применяться стили. Ограничение области (<scope-end>
) определяет узлы, на которые не влияет область действия. Этот параметр необязателен.
Представим, что у нас есть страница со статьёй с двумя подразделами, в каждом из которых есть ссылка:
<div class="article-section">
<p>Основная часть: <a target="_blank" href="#">читать</a></p>
<div class="quote-section">
<p>Дополнительная информация: <a target="_blank" href="#">перейти</a></p>
</div>
<div class="news-section">
<p>Комментарии: <a target="_blank" href="#">оставить</a></p>
</div>
</div>
Для всех ссылок внутри раздела .article-section
мы задаём стиль через ключевое слово @scope
:
@scope (.article-section) {
a {
color: blue;
}
}
Теперь нам нужно поменять цвет ссылки в разделе .quote-section
. Чтобы не писать селектор .quote-section a
с высокой специфичностью, можно задать ограничение области видимости для селектора а
, чтобы стили применялись только в определённом блоке:
@scope (.quote-section) to (.news-section .quote) {
a {
color: red;
}
}
Это удобно, когда есть много однотипных блоков и нужно применять уникальные стили к отдельным элементам этих блоков, например для обеспечения доступности или определённой цветовой схемы. Но пока что поддержка @scope
браузерами ограничена.