Главная / Блог / Имитация стрелочных часов с помощью новых тригонометрических функций CSS sin() и cos ()
Имитация стрелочных часов с помощью новых тригонометрических функций CSS sin() и cos ()
MasterNik / 15 марта 2023 г. / 1344 / Время чтения
Тригонометрические функции CSS есть в последних версиях Firefox и Safari. Наличие такого рода математической мощи в CSS открывает целую кучу возможностей. В этом материале мы применим пару новых функций: sin()и cos().
В конвейере есть и другие тригонометрические функции, tan() в том числе — так зачем фокусироваться только на sin()и cos()? Они идеально подходят для идеи, которая заключается в размещении текста вдоль края круга.
Вот что имеется в виду. Опять же, на данный момент это поддерживается только в Firefox и Safari:
Итак, это не совсем похоже на слова, образующие круглую форму, но мы размещаем текстовые символы вдоль круга, чтобы сформировать циферблат. Вот некоторая разметка, которую мы можем использовать для запуска:
Немного украсим там всё, но только для того, чтобы получить основную форму и цвет фона, которые помогут нам увидеть, что мы делаем. Обратите внимание, как мы сохраняем widthзначение в переменной CSS. Мы воспользуемся этим позже. Пока смотреть особо не на что:
Похоже на какой-то эксперимент в области современного искусства, верно? Давайте введем новую переменную, --_r, для хранения радиуса окружности, который равен половине ширины окружности. Таким образом, при изменении width (--_w) значение radius (--_r) также будет обновляться — благодаря другой математической функции CSS,calc():
.clock{--_w:300px;--_r:calc(var(--_w)/2);/* rest of styles */}
Теперь немного математики. Окружность равна 360 градусам. У нас на часах 12 меток, поэтому мы хотим размещать цифры через каждые 30 градусов (360 / 12). В math-land круг начинается с 3 часов, поэтому полдень на самом деле минус 90 градусов от этого, что составляет 270 градусов (360 - 90) .
Давайте добавим еще одну переменную, --_d, которую мы можем использовать для установки значения степени для каждого числа на циферблате. Мы собираемся увеличить значения на 30 градусов, чтобы завершить наш круг:
Хорошо, сейчас самое время запачкать руки функциями sin()иcos()! Что мы хотим сделать, так это использовать их для получения координат X и Y для каждого числа, чтобы мы могли правильно разместить их вокруг циферблата.
Формула для координаты X такова radius + (radius * cos(degree)). Давайте добавим это в нашу новую --_xпеременную:
--_x:calc(var(--_r)+(var(--_r)*cos(var(--_d))));
Формула для координаты Y такова radius + (radius * sin(degree)). У нас есть все, что нам нужно для вычисления этого:
--_y:calc(var(--_r)+(var(--_r)*sin(var(--_d))));
Для настройки чисел нам нужно выполнить несколько хозяйственных действий, поэтому давайте добавим к ним некоторый базовый стиль, чтобы убедиться, что они абсолютно расположены и размещены с нашими координатами:
Обратите --_szвнимание, что мы будем использовать для widthи heightчисел через мгновение. Давайте посмотрим, что у нас есть на данный момент.
Это определенно больше похоже на часы! Видите, как верхний левый угол каждого числа расположен в правильном месте по кругу? Нам нужно “уменьшить” радиус при вычислении позиций для каждого числа. Мы можем вычесть размер числа (--_sz) из размера окружности (--_w), прежде чем вычислять радиус:
--_r:calc((var(--_w)-var(--_sz))/2);
Намного лучше! Давайте изменим цвета, чтобы они выглядели более элегантно:
Мы могли бы остановиться прямо здесь! Мы достигли цели размещения текста по кругу, верно? Но что такое часы без стрелок, чтобы показывать часы, минуты и секунды?
Давайте используем для этого одну анимацию CSS. Сначала давайте добавим еще три элемента в нашу разметку,
<divclass="clock"><!-- after <time>-tags --><spanclass="arm seconds"></span><spanclass="arm minutes"></span><spanclass="arm hours"></span><spanclass="arm center"></span></div>
Затем некоторая общая разметка для всех трех плеч. Опять же, большая часть этого - просто убедиться, что рычаги абсолютно расположены и размещены соответствующим образом:
Мы будем использовать одну и ту же анимацию для всех трех рычагов:
@keyframes turn{to{transform:rotate(1turn);}}
Единственное различие заключается во времени, которое требуется отдельным стрелкам, чтобы совершить полный оборот. Для стрелки часов требуется 12 часов, чтобы сделать полный оборот. animation-durationСвойство принимает значения только в миллисекундах и секундах. Давайте придерживаться секунд, что составляет 43 200 секунд (60 seconds * 60 minutes * 12 hours).
animation: turn 43200s infinite;
Минутной стрелке требуется 1 час, чтобы совершить полный оборот. Но мы хотим, чтобы это была многоступенчатая анимация, чтобы движение между рычагами было ступенчатым, а не линейным. Нам понадобится 60 шагов, по одному на каждую минуту:
animation: turn 3600ssteps(60, end) infinite;
Секундная стрелкапочти такая же, как и минутная, но ее продолжительность составляет 60 секунд вместо 60 минут:
animation: turn 60ssteps(60, end) infinite;
Давайте обновим свойства, которые мы создали в общих стилях:
Что, если мы хотим начать с текущего времени? Нам нужно немного JavaScript:
const time =newDate();const hour =-3600*(time.getHours()%12);const mins =-60* time.getMinutes();
app.style.setProperty('--_dm',`${mins}s`);
app.style.setProperty('--_dh',`${(hour+mins)}s`);
Добавим id="app"к циферблату и установим для него два новых пользовательских свойства, которые устанавливают отрицательное animation-delayзначение. getHours()Метод объекта JavaScipt Dateиспользует 24-часовой формат, поэтому мы используем remainderоператор для преобразования его в 12-часовой формат.
В CSS нам animation-delayтакже нужно добавить:
.minutes{animation-delay:var(--_dm,0s);/* other styles */}.hours{animation-delay:var(--_dh,0s);/* other styles */}
Еще одна вещь. Используя CSS @supportsи свойства, которые мы уже создали, мы можем предоставить запасной вариант для браузеров, которые не поддерживают sin()и cos():
@supports not (left:calc(1px*cos(45deg))){time{left:50%!important;top:50%!important;transform:translate(-50%,-50%)rotate(var(--_d))translate(var(--_r))rotate(calc(-1*var(--_d)))}}
И вуаля! Наши часы готовы! Вот еще одна финальная демонстрация. Опять же, на данный момент это поддерживается только в Firefox и Safari.
Что еще мы можем сделать?
Здесь мы просто балуемся, но мы можем быстро превратить наши часы в круговую галерею изображений, заменив <time>теги на <img>затем обновив значения width (--_w) и radius (--_r):
Давайте попробуем еще один вариант. Мы можем создать вот такой шаблон, который называется “Луна” и состоит из множества точек, образующих круг.
На этот раз мы будем использовать неупорядоченный список, поскольку круги не следуют определенному порядку. Мы даже не собираемся помещать все элементы списка в разметку. Вместо этого давайте внедрим в них JavaScript и добавим несколько элементов управления, которые мы можем использовать для управления конечным результатом.
Элементы управления - это входные данные диапазона (<input type="range">)которые мы обернем в a <form>и прослушаем inputсобытие.
<formid="controls"><fieldset><label>Number of rings
<inputtype="range"min="2"max="12"value="10"id="rings"/></label><label>Dots per ring
<inputtype="range"min="5"max="12"value="7"id="dots"/></label><label>Spread
<inputtype="range"min="10"max="40"value="40"id="spread"/></label></fieldset></form>
Мы запустим этот метод для “ввода”, который создаст кучу <li>элементов с переменной degree (--_d), которую мы использовали ранее, примененной к каждому из них. Мы также можем перепрофилировать нашу переменную radius (--_r) .
Также сделаем так, чтобы точки были разных цветов. Итак, давайте рандомизируем (ну, не полностью рандомизируем) значение цвета HSL для каждого элемента списка и сохраним его как новую переменную CSS,--_bgc:
constupdate=()=>{let s ="";for(let i =1; i <= rings.valueAsNumber; i++){const r = spread.valueAsNumber * i;const theta =coords(dots.valueAsNumber * i);for(let j =0; j < theta.length; j++){
s +=`<li style="--_d:${theta[j]};--_r:${r}px;--_bgc:hsl(${random(50,25)},${random(90,50)}%,${random(90,60)}%)"></li>`;}}
app.innerHTML = s;}
random()Метод выбирает значение в пределах определенного диапазона чисел:
constrandom=(max, min =0, f =true)=> f ? Math.floor(Math.random()*(max - min)+ min): Math.random()* max;
И это все. Мы используем JavaScript для рендеринга разметки, но как только она визуализируется, она нам действительно не нужна. Функции sin()и cos()помогают нам расположить все точки в нужных местах.
Заключительные мысли
Размещение объектов по кругу - довольно простой пример для демонстрации возможностей тригонометрических функций, таких как sin()и cos(). Но это действительно здорово, что мы получаем современные функции CSS, которые предоставляют новые решения для старых обходных путей. Уверены, что мы увидим гораздо более интересные, сложные и креативные варианты использования, особенно с поддержкой браузеров в Chrome и Edge.
Если у вас есть вопросы по статье или нужна помощь в создании сайта, пишите нам в чат на сайте или Вконтакте. Не забудьте оставить свой e-mail и мы ответим в самое ближайшее время.
Понравилась статья?
Будем признательны, если поделитесь в соцсетях или мессенджерах, а также присоединитесь к нашей группе Вконтакте. Будет интересно!
Переходы между страницами выглядят очень, очень круто. Более того, они начинают появлятьсяповсюду. Уверены, что вы, как и мы, не раз встречали в сети такие переходы, от которых у вас возникаетвосхищениеи желание немедленно использовать их на своем сайте или в проекте.
HTML является одним из основополагающих строительных блоков Интернета. Но так же, как и методы веб-дизайна меняются со временем, также меняется и код, который мы используем. По мере развития HTML какая-то часть его старой разметки устарела, а какая-то была перепрофилирована...
Ползунки диапазона (<input type="range">) позволяют пользователям выбирать значение в пределах заданного диапазона, предоставляя альтернативные типы ввода, такие как <input type="number">.
В наше время без анимационных эффектов на сайте просто не обойтись. Это и слайдеры и скроллеры, различного рода реагирования элементов дизайна при наведении на них мышкой, это анимация при прокрутке страниц и различные выезжающие, выплывающие, выползающие и т.д. блоки контента. Дизайнеры используют свою фантазию на 100%, чтобы их дсайт выделился из общей массы и запомнился Пользователям...
Обычное поле Поиска по сайту можно оформить более оригинально, чем просто инпут с лупой. Например, благодаря анимационным эффектам на CSS3 поле для ввода поисковой фразы можно скрыть, чтобы освободить место для другого контента...