Есть ли случайные числа в CSS?
CSS позволяет создавать динамические макеты и интерфейсы в интернете, но как язык он статичен: как только значение установлено, оно не может быть изменено. Идея случайности не стоит на повестке дня. Генерация случайных чисел во время выполнения-это территория JavaScript, а не столько CSS. Или нет? Если мы учитываем небольшое взаимодействие с пользователем, мы действительно можем генерировать некоторую степень случайности в CSS. Давайте посмотрим!
Рандомизация с других языков
Есть способы получить некоторую "динамическую рандомизацию", используя переменные CSS, как объясняет Робин Рендл в статье о CSS-трюках . Но эти решения не являются 100% CSS, так как они требуют JavaScript для обновления переменной CSS с новым случайным значением.
Мы можем использовать препроцессоры, такие как Sass или меньше, чтобы генерировать случайные значения, но как только код CSS компилируется и экспортируется, значения фиксируются и случайность теряется.
Почему я забочусь о случайных значениях в CSS?
В прошлом я разрабатывал простые CSS - приложения, такие как игра в Пустяки , игра Simon и волшебный трюк . Но я хотел сделать что-то немного более сложное. Я оставлю дискуссию о правомерности, полезности или практичности создания этих фрагментов только для CSS на более позднее время.
Исходя из предпосылки, что некоторые настольные игры могут быть представлены в виде конечных автоматов ( FSM), они могут быть представлены с помощью HTML и CSS. Поэтому я начал разрабатывать игру змей и лестниц (ака парашюты и лестницы). Это простая игра. Цель состоит в том, чтобы продвинуть пешку от начала до конца доски, избегая змей и пытаясь подняться по лестницам.
Проект казался осуществимым, но было кое-что, чего мне не хватало: бросать кости !
Бросок кубиков (наряду с подбрасыванием монеты)являются универсально признанными для рандомизации. Вы бросаете кости или переворачиваете монету, и каждый раз вы получаете неизвестное значение.
Имитация случайного броска кубиков
Я собирался накладывать слои с метками и использовать CSS-анимации для "поворота" и обмена, какой слой был сверху. Что-то вроде этого:
Код для имитации этой рандомизации не является чрезмерно сложным и может быть достигнут с помощью анимации и различных задержек анимации:
/* The highest z-index is the numbers of sides in the dice */
@keyframes changeOrder {
from { z-index: 6; }
to { z-index: 1; }
}
/* All the labels overlap by using absolute positioning */
label {
animation: changeOrder 3s infinite linear;
background: #ddd;
cursor: pointer;
display: block;
left: 1rem;
padding: 1rem;
position: absolute;
top: 1rem;
user-select: none;
}
/* Negative delay so all parts of the animation are in motion */
label:nth-of-type(1) { animation-delay: -0.0s; }
label:nth-of-type(2) { animation-delay: -0.5s; }
label:nth-of-type(3) { animation-delay: -1.0s; }
label:nth-of-type(4) { animation-delay: -1.5s; }
label:nth-of-type(5) { animation-delay: -2.0s; }
label:nth-of-type(6) { animation-delay: -2.5s; }
Анимация была замедлена, чтобы облегчить взаимодействие (но все еще достаточно быстро, чтобы увидеть блокпост, описанный ниже). Псевдослучайность тоже более очевидна.
Но затем я столкнулся с препятствием: я получал случайные числа, но иногда, даже когда я нажимал на свои "кости", он не возвращал никакого значения.
Я попытался увеличить время в анимации, и это, казалось, немного помогло, но у меня все еще были некоторые неожиданные значения.
Именно тогда я сделал то, что делают большинство разработчиков, когда они находят препятствие, которое они не могут решить просто путем поиска в Интернете: я попросил других разработчиков о помощи в виде вопроса StackOverflow .
К счастью для меня, всегда находчивый Темани Афиф придумал объяснение и решение .
Чтобы немного упростить, проблема заключалась в том, что браузер только запускает событие click/press, когда элемент, который активен при наведении мыши вниз, является тем же элементом, который активен при наведении мыши вверх.
Из-за вращающейся анимации верхняя метка на mouse down не была верхней меткой на mouse up, если я не делал это быстро или достаточно медленно, чтобы анимация кружилась вокруг. Вот почему увеличение времени анимации скрывало эти проблемы.
Решение состояло в том, чтобы применить положение "статики", чтобы разорвать контекст укладки, и использовать псевдо-элемент, подобный ::before
или ::after
с более высокимz-index
, чтобы занять его место. Таким образом, активная метка всегда будет находиться сверху, когда мышь пошла вверх.
/* The active tag will be static and moved out of the window */
label:active {
margin-left: 200%;
position: static;
}
/* A pseudo-element of the label occupies all the space with a higher z-index */
label:active::before {
content: "";
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 10;
}
Вот код с решением с более быстрым временем анимации:
После внесения этого изменения осталось только создать небольшой интерфейс, чтобы нарисовать поддельные кости, чтобы щелкнуть, и CSS Snakes and Ladders был завершен.
Этот метод имеет некоторые очевидные неудобства
- Он требует ввода пользователем: метка должна быть нажата, чтобы вызвать " генерацию случайных чисел."
- Он не масштабируется хорошо: он отлично работает с небольшими наборами значений, но это боль для больших диапазонов.
- Это не совсем случайно, но псевдослучайно: компьютер может легко определить, какое значение будет генерироваться в каждый момент времени.
Но с другой стороны, это 100% CSS (нет необходимости в препроцессорах или других внешних помощниках), и для человека-пользователя он может выглядеть на 100% случайным.
И разговоры о руках... Этот метод может быть использован не только для случайных чисел, но и для случайных ничего. В этом случае мы использовали его, чтобы "случайно" выбрать компьютерный выбор в игре Rock-Paper-Scissors.