November 12, 2019

Есть ли случайные числа в 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.