Каскадные Таблицы Стилей / [Из песочницы] Секундомер на CSS3 без картинок, скриптов и SMS

в 7:13, , рубрики: css3, CSS3 animation, без SMS, красота, метки: , , ,

CSS3 timer
Привет, читатель!
Я даже не знаю что хуже, что код для этого секундомера занимает ~ 1100 строк, или то что он работает только в половине браузеров.
Но если же тебе интересно как это работает, прошу под кат.

Вступление

Во-первых о браузерах. Работает этот код, из нынешних: в FireFox, Safari и Chrome. На подходе такие гиганты браузеры как IE10 и супер секретная новая Opera.
Во-вторых, хочу сразу отметить, что я буду описывать именно процесс анимации, а не рисования на CSS3. На будущее план как раз наоборот сделать очень красивый рисунок, на CSS. O да, это стало не так нудно, после того как разработчики из сафари отказались от своего старого стандарта linear-gradient'a (прощай color-stop, from, to, 0 0) и Opera наконец-то стала поддерживать radial-gradient (последнее произошло относительно давно).

Сначала я подумал что сделаю всем привычный секундомер, со стрелочками и только, но это очень скучно.
Нет того драйва, и ощущения механизма, когда ты лицезришь две стрелочки, бегающие по монитору. С другой же стороны я сразу вспомнил, как когда-то делал что-то вроде одометра, для пройденного мышкой пути. И меня осенило.

Понеслась

Первым делом выстраиваем HTML (ниже приведен пример, только для «одометра»).

<div class="timer">     <div class="numb tenHour">     </div>     <div class="numb hour">     </div>     <div class="numb tenMin">     </div>     <div class="numb min">     </div>     <div class="numb tenSec">     </div>     <div class="numb sec">     </div>     <div>      :</div>     <div class="numb tenMilisec">     </div>     <div class="numb milisec">     </div> </div> 

План такой, в каждому диву numb мы присваиваем псевдоэлемент с записью «0 1 2 3 4 5 6 7 8 9 0».
Почему два нуля? Анимация проходит от одного края к другому, а потом без задержки времени переходит в изначальное положение. По сути мы видим два разных нуля, но на живом примере этого не заметно.
Почему именно псевдоэлемент? Почему не написать числа прямо в див? Тут есть два плюса, во первых мы не портим вид HTML, а во вторых мы пишем это только один раз.
Получаем какой никакой CSS

.timer div {     float: left;     width: 30px;     height: 30px;     position: relative; } .numb::before {     content:"0 1 2 3 4 5 6 7 8 9 0";     position: absolute;     width: 30px;             /* Так как мы поставили ширину у 30px, все числа будут с новой строчки, это нам и нужно. */     height: 360px;     color: #334;     text-align: center; } .timer div::after {     content: "";     height: 360px;     width: 1px;     left: 0;     background: #889; } .timer div:first-child::after {     display: none; } 

Ставим у родителя overflow: hidden и вуаля! Все, одометр готов.

Анимация

Приступим же к анимации, тут все просто:

.numb {    animation-delay: 0;   /* Обнеляем задержку анимации */    animation-iteration-count: infinite;  /* Количество повторений анимации - бесконечно */    animation-timing-function: linear;  /* отображение анимации относительно времени - плавно без рывков */ } .tenHour {animation-duration: 1000000s;}  /* по убывающей количество секунд на анимацию */  .hour { animation-duration: 100000s;}    .tenMin { animation-duration: 10000s;}  .min { animation-duration: 1000s;}  .tenSec { animation-duration: 100s;}  .sec { animation-duration: 10s;}  .tenMilisec { animation-duration: 1s;}  .milisec { animation-duration: .1s;}   /* вообще, разрешается использовать ms, но я решил использовать десятую чать секунды */ 

Теперь самое скучное, фреймы, точнее ключевые фреймы, они же «кадры».

@-keyframes timer {     0% {top:0}     100% {top:-300px;} } 

Такой код нас не устраивает, все передвигается плавно, но это некрасиво и неправильно, т.к. при паузе мы вполне себе можем попасть на непонятное значение. Пишем так:

@-keyframes timer {     0% {top:0}     9% {top:0}     10% {top:-30px}     19% {top:-30px}     20% {top:-60px}     29% {top:-60px}     30% {top:-90px}     39% {top:-90px}     40% {top:-120px}     49% {top:-120px}     50% {top:-150px}     59% {top:-150px}     60% {top:-180px}     69% {top:-180px}     70% {top:-210px}     79% {top:-210px}     80% {top:-240px}     89% {top:-240px}     90% {top:-270px}     99% {top:-270px}     100% {top:-300px;} } 

Все расписывать не буду, смысла в этом нет. Суть в том что мы берем 1% от 10-ти секунд, как время отведенное для перелистывания счетчика.
Поэтому для десятых — 0% 9.9% 10% 19.9% и так далее. Дальше больше, сотые — 0% 9.99%, тысячные — 0% 9.999%.

Заработало!

Теперь самое вкусное, как без JS заставить все это двигаться? Как нам имитировать onclick?
Есть несколько приемов, которые отвечают нашим требованиям.
Первый, самый старый и простой — псевдоклассы для ссылки
Я имею ввиду :active, :focus. Но это скучно, да и к тому же багнуто работает в Chrome (Что?! Может быть в IE?! Нет именно в Chrome)

Второй более веселый способ, использовать <input /> radio и checkbox.
И его псевдоелемент :cheked. Этот способ я вычеркнул, потому что нужен будет лишний элемент label для каждого <input />

Третий способ который пришел ко мне в голову, это та же ссылка, но с использованием :target.

Это не все способы которым можно прибегнуть, но когда я остановился на :target больше думать и не хотелось.

Итак код HTML:

            <a class="start" id="start" href="#start"></a>             <a class="pause" id="pause" href="#pause"></a>             <a class="stop" id="stop" href="#stop"></a> 

Тут даже обьяснять ничего не надо.
И теперь CSS:

.start:target ~ .timerInner .numb, .pause:target ~ .timerInner .numb {    animation-name: timer; } .start:target ~ .timerInner .numb.tenSec, .pause:target ~ .timerInner .numb.tenSec {    animation-name: timertenSec; } .pause:target ~ .timerInner .sec, .pause:target ~ .timerInner .tenMilisec {     animation-play-state: paused; } .stop:target ~ .timer .tenSec, .stop:target ~ .timer .sec, {    animation-name: reset; } 

Мы ставим в качестве имени анимации те имена кеифреймов, которые давали выше.
И все начинает работать. Для кнопки Пауза тоже ставим, это для того что бы анимация не обнулялась при нажатии на нее, но анимацию нужно остановить, для этого и предусмотрен animation-play-state

При нажатии на Стоп, по идее можно присвоить любое имя, главное чтобы оно не совпадало с именем наших анимаций, тогда произойдет обнуление. Я представил далеко не весь код анимации, дело в том что он однообразен, и присваивается каждому диву отдельно, кому интересно глянет код.

Ок, теперь сделаем часики. Именно стрелку, циферблат нам не интересен.
HTML

                    <div class="clock">                         <div class="line one"></div>                         <div class="line three"></div>                         <div class="line five"></div>                         <div class="arrow"></div>                     </div> 

Дивы line просто обозначают вертикаль по которой мы ставим деления на минуты.
Arrow и есть наша стрелка.

CSS

.arrow {    animation-delay: 0;   /* Задержка ноль */    animation-iteration-count: infinite;    /* бесконечно */    animation-timing-function: linear;    /* без рывков */    animation-duration: 600s;    /* 10м x 60с = 600с, время анимации */    background:#666; } 

Запускаем стрелку аналогично с одометром.
Приводить код думаю лишнее.

В общем, финальный результат, еще раз.
Спасибо за внимание, нового я по сути ничего не рассказал, лично я этой инфой владею уже давно.
Просто кому-нибудь это, возможно, будет полезно, или просто интересно.

Автор: leoni4

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js