Посмотри на окружающий физический мир: в нем практически нет идеальных прямых линий и математически стерильных поверхностей. Листья на ветру колышутся с разной частотой, снимки Polaroid на рабочем столе ложатся под произвольными углами, а в классической типографской печати литеры букв всегда имеют микроскопический, едва уловимый наклон. Именно эти крошечные шероховатости делают аналоговый мир живым, теплым и осязаемым.
А теперь открой любой современный веб-интерфейс: пиксельная строгость, жесткие модульные сетки, одинаковые карточки и параллельные бегущие строки. Веб долгие годы страдал от математической стерильности. Когда же фронтенд-инженеры пытались добавить в верстку немного «живого несовершенства» (playful imperfection), им приходилось выбирать между двумя одинаково плохими компромиссами:
- Вызывать
Math.random()в JavaScript. Это приводило к дерганию интерфейса при гидратации, ухудшало метрику Cumulative Layout Shift (CLS) и нагружало процессор устройства. - Использовать препроцессоры вроде Sass, генерируя сотни строк громоздкого CSS с жестко прописанными псевдоклассами
:nth-child(n)для псевдослучайных поворотов.
В спецификации CSS Values and Units Module Level 5 рабочая группа W3C наконец-то предложила нативное браузерное решение: функцию random(). В большом исследовании на страницах Smashing Magazine бельгийский дизайнер и разработчик Брехт Де Рюйте подробно исследовал ее возможности на реальных примерах. Давай разберем, как устроена эта магия, почему случайность в CSS обязана быть детерминированной и как подготовить свои стили к новой эпохе.
Анатомия синтаксиса: границы, размерности и шаги сетки
Базовый синтаксис функции выглядит обманчиво просто:
random( <random-key>?, <min>, <max> [, by <step>]? )
Однако за этой лаконичностью скрываются строгие правила типизации движка рендеринга.
Первое фундаментальное требование спецификации: аргументы <min> и <max> обязаны иметь абсолютно одинаковую размерность единиц измерения.
Ты можешь передавать:
- Углы:
random(-4deg, 4deg)для легкого наклона элементов; - Временные интервалы:
random(0.2s, 1.5s)для рассинхронизации фаз анимации; - Линейные размеры:
random(100px, 300px)для вариации ширины колонок; - Безразмерные числа:
random(0.5, 1.0)для прозрачностиopacity.
Но ты не имеешь права напрямую смешивать разные единицы: выражение вида random(10px, 2rem) является синтаксической ошибкой и будет проигнорировано браузером. Если тебе действительно необходимо связать пиксели и относительные единицы, их придется предварительно приводить к единому знаменателю через calc().
Второе мощное свойство — параметр шага дискретизации (step). Без него функция генерирует непрерывную дробную величину. Но в реальных дизайн-системах отступы и размеры почти всегда кратны определенному модулю (например, 4 или 8 пикселей). Параметр шага позволяет удерживать случайность в строгих рамках:
.ticket-badge {
/* Случайный отступ строго с шагом по 4 пикселя: 8px, 12px, 16px... */
padding-inline: random(8px, 24px, 4px);
/* Случайная задержка анимации с шагом в 100 миллисекунд */
animation-delay: random(0s, 1s, 0.1s);
}
В нашем обзоре того, как устроены случайности в чистом CSS и что они изменят в верстке, мы подробно касались влияния шага на рендеринг. Это идеальный мостик между хаосом и порядком.
Проблема независимости: как ключи спасают квадраты
Что произойдет, если ты решишь сделать карточку случайного размера и напишешь:
.card {
width: random(100px, 200px);
height: random(100px, 200px);
}
По умолчанию каждый вызов функции random() вычисляется абсолютно независимо! Браузер сгенерирует для ширины, например, 184px, а для высоты — 112px. Твоя карточка превратится в случайный вытянутый прямоугольник. А если ты хотел сохранить идеальные пропорции квадрата 1:1?
Для решения этой задачи в спецификацию введен механизм именованных ключей (shared keys). Ключ работает как общий сид (seed): если двум разным CSS-свойствам передан одинаковый идентификатор ключа, они получат в точности одно и то же псевдослучайное значение:
.square-card {
/* Одинаковый ключ --box гарантирует, что ширина будет равна высоте */
inline-size: random(--box element-scoped, 100px, 200px);
block-size: random(--box element-scoped, 100px, 200px);
}
Обрати внимание на модификатор element-scoped. Без него глобальный ключ --box вычислил бы одно число для всей страницы целиком (все карточки на сайте стали бы одинаковыми). Модификатор element-scoped указывает движку: «изолируй генератор в пределах каждого конкретного DOM-элемента». Каждая карточка получит свой уникальный случайный размер, но останется безупречным квадратом!
Статус поддержки и безопасный прогрессивный фолбэк
На момент конца октября 2026 года функция random() находится на острие браузерной стандартизации:
- WebKit (Safari): экспериментальная реализация доступна в сборках Safari Technology Preview;
- Blink (Chrome / Chromium): функция внедрена в Chrome 156 Canary за флагом экспериментальных веб-платформенных функций;
- Gecko (Firefox): реализация тестируется в ветке Nightly за настройкой
layout.css.random-function.enabled.
Поскольку стабильные версии браузеров еще готовятся к повсеместному включению, использовать random() в продакшене необходимо по канонам прогрессивного улучшения (Progressive Enhancement).
Посмотрим на боевой пример оформления галереи фотокарточек со стилизацией под Polaroid:
/* Базовые стили для всех браузеров: аккуратное статическое отображение */
.polaroid-item {
rotate: 0deg;
transition: transform 0.3s ease;
}
/* Прогрессивное улучшение для современных браузеров с поддержкой random() */
@supports (rotate: random(0deg, 1deg)) {
.polaroid-item {
/* Легкий органический наклон каждой карточки от -3 до +3 градусов */
rotate: random(--photo-tilt element-scoped, -3deg, 3deg);
}
.polaroid-item:hover {
/* При наведении карточка встает строго ровно */
rotate: 0deg;
transform: scale(1.05);
}
}
В нашем исследовании о том, как 12 возможностей современного CSS вытесняют препроцессоры и JavaScript-хаки, мы отмечали: будущее веб-стилизации за переносом сложных динамических вычислений непосредственно в движок рендеринга.
Всегда оборачивайте правила с функцией random() в директиву @supports. Это гарантирует, что старые браузеры просто отобразят стандартный ровный макет без сбоев разбора CSS и без поломки соседних стилей.
Как только функция random() перейдет в разряд общедоступного Baseline, веб окончательно избавится от искусственной пластиковой стерильности, сделав интерфейсы по-настоящему живыми и органичными.
