CSS всегда был детерминированным языком: при одинаковых входных данных вы получаете одинаковый результат. Каждый раз. Но это скоро изменится благодаря появлению двух новых функций для генерации случайных значений прямо в CSS.
В этой статье мы сразу перейдём к сути новой возможности. Если вам интересен более подробный разбор — включая историю появления случайности в CSS, принцип работы функции и её значение для самого языка — загляните в мою более большую статью, которая дополнит недавний доклад на конференции.
На момент написания статьи поддержка функции ещё не получила широкого распространения (только Safari поддерживает random() начиная с версии 26.2, и то частично). Ниже рассматривается спецификация и функции, которые ожидаются в будущем.
table.support {
margin-bottom: 2rem;
td {
color: green;
span { color: #c00; }
}
caption {
margin-bottom: 1rem;
}
th, td {
text-align: center;
}
}| Safari | Chrome | Firefox | |
|---|---|---|---|
random() | 26.2 | ❌ | ❌ |
random-item() | ❌ | ❌ | ❌ |
Давайте разберём новые функции.
random()
Функция random() возвращает случайное значение в указанном диапазоне. В простейшем варианте она принимает два параметра — минимальное и максимальное значение — и возвращает число внутри этого интервала.
Например:
div {
width: random(200px, 500px);
}
/*
Возможные результаты:
- width: 230px;
- width: 417px;
- width: 308.342px;
*/Обратите внимание, что результат не ограничивается только целыми числами. Любое значение внутри диапазона допустимо, включая дробные.
Incremental Random
Иногда дробные значения нам не нужны (мало кому нравится иметь дело с половинными пикселями в верстке). В этом случае функция принимает третий необязательный параметр — шаг или инкремент.
Чтобы задать шаг, нужно добавить третье значение:
div {
rotate: random(0deg, 180deg, 10deg);
}
/*
Возможные результаты:
- rotate: 120deg;
- rotate: 40deg;
- rotate: 180deg;
Невозможные:
- rotate: 5deg;
- rotate: 134deg;
- rotate: 89deg;
*/Шаг отсчитывается от минимального значения. Это означает, что иногда максимальное значение может оказаться недостижимым. Например, random(100, 200, 30) может вернуть 100, 130, 160 или 190 — но не 200 (шагом 30 от 100 его достичь нельзя) и не 210 (вне диапазона).
Sharing Options
Каждый вызов random() по умолчанию возвращает своё случайное значение. Но бывают ситуации, когда это нежелательно. Например, представим, что свойства aspect-ratio не существует, и мы хотим создать квадрат, задав случайную ширину и высоту.
div {
width: random(10em, 30em);
height: random(10em, 30em);
}
/*
Возможные результаты:
- width: 14em; height: 15em;
- width: 21em; height: 11em;
- width: 17em; height: 27em;
*/Существует способ делиться случайным значением внутри одного правила, элемента или даже глобально. Для этого добавляется дополнительный параметр в начале функции.
Он может принимать разные значения.
auto
Значение по умолчанию. Каждый вызов функции генерирует своё значение.
div {
width: random(auto, 100px, 200px);
height: random(auto, 100px, 200px);
}
/*
Использование auto эквивалентно обычному random()
Возможный результат:
- div.div1 → width: 125px; height: 198px;
- div.div2 → width: 142px; height: 101px;
*/Идентификатор с дефисом
Например --w. В этом случае значение будет общим для свойств внутри элемента, но не между разными элементами.
div {
width: random(--d, 100px, 200px);
height: random(--d, 100px, 200px);
}
/*
Использование идентификатора:
Каждый div будет квадратным,
потому что свойства используют одно и то же значение.
Возможный результат:
- div.div1 → width: 150px; height: 150px;
- div.div2 → width: 134px; height: 134px;
*/Это происходит потому, что
random()внутри генерирует базовое значение от 0 до 1, которое затем используется для вычисления результата. Если несколько вызовов используют один и тот же идентификатор, браузер переиспользует это базовое значение.
element-shared
Ключевое слово element-shared может использоваться отдельно или вместе с идентификатором.
div {
width: random(element-shared, 100px, 200px);
height: random(element-shared, 100px, 200px);
}
/*
Значение общее между элементами,
но не между свойствами.
Возможный результат:
- div.div1 → width: 150px; height: 134px;
- div.div2 → width: 150px; height: 134px;
*/div {
width: random(--v element-shared, 100px, 200px);
height: random(--v element-shared, 100px, 200px);
}
/*
Значение общее и между элементами,
и между свойствами.
Возможный результат:
- div.div1 → width: 128px; height: 128px;
- div.div2 → width: 128px; height: 128px;
*/fixed
Ключевое слово fixed с числовым идентификатором задаёт фиксированный глобальный случайный идентификатор.
div {
width: random(fixed 0.5, 100px, 200px);
height: random(fixed 0.5, 100px, 200px);
}
/*
Значение будет одинаковым
для всех элементов и свойств.
Возможный результат:
- div.div1 → width: 167px; height: 167px;
- div.div2 → width: 167px; height: 167px;
*/Это упрощённое объяснение работы механизма. Подробности можно посмотреть в спецификации.
Теперь, разобрав синтаксис и варианты использования random(), перейдём ко второй функции из черновика спецификации CSS Values and Units Module Level 5.
random-item()
В CSS есть свойства, принимающие дискретные значения, которые нельзя выразить диапазоном. В таких случаях random() не подходит. Нужна функция, которая принимает список значений и случайным образом выбирает одно из них. Эту задачу и решает random-item().
Функция принимает параметр для шаринга и список возможных значений:
div {
display: random-item(--d, block, flex, grid, table);
opacity: random-item(--o, 0.5, 0.6, 0.75, 0.9, 1);
background: random-item(--b, red, #00f, conic-gradient(#fff 0 0));
}
/*
Возможные результаты:
- display: block; opacity: 0.9; background: #00f;
- display: grid; opacity: 0.6; background: red;
- display: flex; opacity: 0.75; background: red;
*/Важно: в random-item() параметр шаринга обязателен.
Небольшая деталь, которую многие могли не заметить: CSS позволяет использовать фигурные скобки {} для группировки списка значений, если этот список передаётся как единый элемент внутри другого списка параметров.
Это полезно при вложенных списках:
div {
font-family: random({ Times, serif }, { Arial, sans-serif }, monospace);
}
/*
Возможные результаты:
- Times, serif
- Arial, sans-serif
- monospace
*/Если два вызова
random-item()используют один и тот же идентификатор и одинаковое количество элементов, их результаты будут коррелировать. Например:
random-item(--a, 1, 2, 3)иrandom-item(--a, red, green, blue)— если первый вернул2, второй вернётgreen.
Заключение
Надеюсь, статья помогла вам познакомиться с новыми функциями random() и random-item() в CSS (частично доступными уже сейчас в Safari).
При использовании этих функций в продакшене важно учитывать поддержку браузерами, кэширование, шаринг значений и влияние на производительность. Среди практических сценариев — случайные цвета, повороты элементов или интервалы между ними, что позволяет добавить вариативность интерфейсу без JavaScript.
Некоторые могут задаться вопросом, стоит ли вообще добавлять такие возможности на уровень CSS. С архитектурной точки зрения это логично: речь идёт о поведении интерфейса и раскладки, а значит, подобная логика должна находиться в слое стилей, а не в JavaScript.
…Но об этом подробнее будет рассказано в следующей большой статье.
Теги: css, html, webdev