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

*:after{
	animation-direction: reverse;
	animation-iteration-count: infinite;
	-webkit-animation-timing-function: linear; /* Safari 4.0 - 8.0 */
  animation-timing-function: linear;
}
.secondsTen:after{
	content:'';
	animation-name: tenBased;
	animation-duration: 10s;
}

.secondsSix:after{
	content:'';
	animation-name: sixBased;
	animation-duration: 60s;
}

@keyframes tenBased {
	0% { content: '0';}
	10% { content: '1';}
	20% { content: '2';}
	30% { content: '3';}
	40% { content: '4';}
	50% { content: '5';}
	60% { content: '6';}
	70% { content: '7';}
	80% { content: '8';}
	90% { content: '9';}
	100% { content: '0';}
}

@keyframes sixBased {
  0% {content: '0';}
  16.66667% {content: '1';}
  33.33333% {content: '2';}
  50% {content: '3';}
  66.66667% {content: '4';}
  83.33333% {content: '5';}
  100% {content: '0';}
}
<span class='secondsSix'></span>
<span class='secondsTen'></span>

Как вы можете видеть, одна секунда уменьшается через 5 секунд. Но оно должно уменьшиться через 10 секунд до 5.

css
3
Ahmet Can Güven 24 Апр 2017 в 09:12

2 ответа

Лучший ответ

Объяснение наблюдаемого поведения

Анимация ключевого кадра выполняет переход между заданными состояниями. В вашем примере вы анимируете значение свойства content псевдоэлемента, которое полностью допустимо, но вы должны помнить, что между двумя ключевыми кадрами нет промежуточных шагов, которые можно визуализировать в этом случае.

Таким образом, на самом деле переход от 100% {content: '0';} к 83.33333% {content: '5';} завершится через 10 секунд (как и ожидалось), но в какой-то момент между значением свойства изменится. При установке animation-timing-function: linear; он находится точно между двумя ключевыми кадрами - в этом примере через 5 секунд это выглядит так, как будто начинается с задержкой.

*:after{
  animation-direction: reverse;
  animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear; /* Safari 4.0 - 8.0 */
  animation-timing-function: linear;
}

.secondsSix:after{
  content:'';
  animation-name: sixBased;
  animation-duration: 60s;
  position: absolute;
}

@keyframes sixBased {
  0% {content: '0'; left: 100%}
  16.66667% {content: '1';}
  33.33333% {content: '2';}
  50% {content: '3';}
  66.66667% {content: '4';}
  83.33333% {content: '5';}
  100% {content: '0'; left: 0%}
}

.timeline {
  border: solid grey;
  border-width: 1px 0;
  background: white;
  position: absolute;
  width: 100%;
  left: 0;
  top: 2em;
}

.timeline span {
  display: inline-block;
  float: left;
  margin-right: 8.33%;
  width: 0;
}
<div class='secondsSix'></div>
<div class='timeline'>
  <span>0</span><span>5</span><span>10</span><span>15</span><span>20</span><span>25</span>
  <span>30</span><span>35</span><span>40</span><span>45</span><span>50</span><span>55</span>
</div>

Я проанализировал поведение с помощью приведенного выше фрагмента и посмотрел, что произойдет, если я удалю отдельные ключевые кадры (по одному за раз, представленные пробелом в следующей таблице).

Content 0   5   4   3   2   1   0
Time    0   5   15  25  35  45  55
Time    0       10  25  35  45  55
Time    0   5       20  35  45  55
Time    0   5   15      30  45  55 // change from '4' to '2' at second 30
Time    0   5   15  25      40  55
Time    0   5   15  25  35      50

Как видите, содержимое всегда меняется точно между двумя заданными ключевыми кадрами. То же самое можно наблюдать в следующей демонстрации, где я изменил вашу анимацию tenBase:

*:after {
  animation-direction: reverse;
  animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear; /* Safari 4.0 - 8.0 */
  animation-timing-function: linear;
  animation-duration: 10s;
}

.secondsTen:after {
  content: '';
  animation-name: tenBased;
}

.secondsTenTwoSteps:after {
  content: '';
  animation-name: tenBasedTwoSteps;
}

@keyframes tenBased {
  0% { content: '0' }
  10% { content: '1'; }
  20% { content: '2'; }
  30% { content: '3'; }
  40% { content: '4'; }
  50% { content: '5'; }
  60% { content: '6'; }
  70% { content: '7'; }
  80% { content: '8'; }
  90% { content: '9'; }
  100% { content: '10' }
}

@keyframes tenBasedTwoSteps {
  0% { content: '0' }
  100% { content: '10' }
}
<div class='secondsTen'></div>
<div class='secondsTenTwoSteps'></div>

Решение № 1

Первый способ решения проблемы прост, но не очень красив. Вам нужно изменить свойство в CSS-анимации внезапно без анимации и то, что ОП описывает как хакерский способ в связанном вопросе будет выглядеть так:

*:after{
  animation-direction: reverse;
  animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear; /* Safari 4.0 - 8.0 */
  animation-timing-function: linear;
}

.secondsSix:after{
  content:'';
  animation-name: sixBased;
  animation-duration: 60s;
  position: absolute;
}

@keyframes sixBased {
  0% {content: '0'; left: 100%}
  0.1% {content: '0';}
  16.66667% {content: '1';}
  16.7% {content: '1';}
  33.3% {content: '2';}
  33.33333% {content: '2';}
  33.4% {content: '3';}
  50% {content: '3';}
  50.1% {content: '4';}
  66.66667% {content: '4';}
  66.7% {content: '5';}
  83.33333% {content: '5';}
  83.4% {content: '0';}
  100% {content: '0'; left: 0%}
}

.timeline {
  border: solid grey;
  border-width: 1px 0;
  background: white;
  position: absolute;
  width: 100%;
  left: 0;
  top: 2em;
}

.timeline span {
  display: inline-block;
  float: left;
  margin-right: 8.33%;
  width: 0;
}
<div class='secondsSix'></div>
<div class='timeline'>
  <span>0</span><span>5</span><span>10</span><span>15</span><span>20</span><span>25</span>
  <span>30</span><span>35</span><span>40</span><span>45</span><span>50</span><span>55</span>
</div>

Решение № 2

Есть и другое решение. Вы увидите, что изменение animation-timing-function: linear; на что-то другое, например animation-timing-function: ease-out;, меняет момент времени, когда содержание резко меняется. Мы заметили, что контент меняется точно посередине при использовании функции линейного хронирования, поэтому я предполагаю, что он будет меняться на 50% прогресса между двумя ключевыми кадрами.

Как разрешено определять cubic-bezier мы можем сдвинуть этот момент времени, когда прогресс приближается к концу на 50%. Помните, что направление анимации меняется на противоположное, поэтому вам нужно отразить кривую (см. cubic-bezier.com/#0,1,0,1 ) .

*:after{
  animation-direction: reverse;
  animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear; /* Safari 4.0 - 8.0 */
}

.secondsSix:after{
  content:'';
  animation-name: sixBased;
  animation-duration: 60s;
  position: absolute;
}

@keyframes sixBased {
  0% {content: '0'; left: 100%}
  16.66667% {content: '1'; animation-timing-function: cubic-bezier(0,1,0,1);}
  33.33333% {content: '2'; animation-timing-function: cubic-bezier(0,1,0,1);}
  50% {content: '3'; animation-timing-function: cubic-bezier(0,1,0,1);}
  66.66667% {content: '4'; animation-timing-function: cubic-bezier(0,1,0,1);}
  83.33333% {content: '5'; animation-timing-function: cubic-bezier(0,1,0,1);}
  100% {content: '0'; left: 0%}
}

.timeline {
  border: solid grey;
  border-width: 1px 0;
  background: white;
  position: absolute;
  width: 100%;
  left: 0;
  top: 2em;
}

.timeline span {
  display: inline-block;
  float: left;
  margin-right: 8.33%;
  width: 0;
}
<div class='secondsSix'></div>
<div class='timeline'>
  <span>0</span><span>5</span><span>10</span><span>15</span><span>20</span><span>25</span>
  <span>30</span><span>35</span><span>40</span><span>45</span><span>50</span><span>55</span>
</div>
2
Community 23 Май 2017 в 11:46

Хотите попробовать это

.secondsTen:before {
    content: '9876543210';
    width:1ch;
    overflow:hidden;
    animation:tenBased 10s steps(10) infinite;
    float:left;
}
.secondsSix:before{
    content: '543210';
    width:1ch;
    overflow:hidden;
    float:left;
    animation:sixBased 60s steps(6) infinite;
}
@keyframes tenBased {
    0% {text-indent:0}
    100% {text-indent:-10ch;}
}
@keyframes sixBased {
    0% {text-indent:0}
    100% {text-indent:-6ch;}
}
<span class='secondsSix'></span>
<span class='secondsTen'></span>
0
Amal 24 Апр 2017 в 09:00