2

I would like to continuously flash between two different words using CSS. When the first one is visible, the second should not be and vice versa. They should not be visible at the same time (so no fade in/out).

I tried adapting the answers from here and here. But, this is not quite right, because the words are overlapping a lot of the time.

@keyframes blinker {
  50% {
    opacity: 0;
  }
}

.mask{
position:absolute;
-webkit-animation: blinker 140ms infinite;
}

.target{
position:absolute;
-webkit-animation: blinker 240ms infinite;
}
<p class="mask">MASK</p><p class="target">TARGET</p>

Using animation-delay does not work, because it applies the delay to the first presentation, not subsequent iterations. I read this page here but I'm finding it difficult to adapt to two words.

Also, I do not want there to be any delay for the first presentation. The first word has to be visible from the start.

Xinyi
  • 23
  • 4
  • I believe you may be looking for `animation-delay`. `240ms` on `.target` will only make the animation longer, causing it to overlap half of the time. – Mooshua Apr 22 '22 at 18:32
  • @Mooshua I had a look, but it only applies the delay to the first presentation, not subsequent iterations. https://css-tricks.com/css-keyframe-animation-delay-iterations/ – Xinyi Apr 22 '22 at 19:00

2 Answers2

3

Here is an idea using CSS grid and order animation. All you have to do is to adjust the percentage of the keyframes and the duration

.blinky {
  display: grid;
  grid-template-rows: 1fr 0; /* 2 rows with the second having 0 height  */
  overflow: hidden; /* hide the overflow of the second row*/
  font-size: 3rem;
}
/* apply the animation to only the last element */
.blinky > span:last-child {
  animation: blink 2s linear infinite;
}
@keyframes blink {
  0%,
  69%  {order:0}
  70%,
  100% {order:-1}
}
<div class="blinky">
  <span>MASK</span>
  <span>TARGET</span>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Interesting and clever approach. – F. Müller Apr 23 '22 at 08:32
  • Thank you, this looks exactly what I need. Could you speak a bit to how I would modify the percentages for different durations? e.g., if I wanted the first one to be presented for 24ms and the second for 14ms. – Xinyi Apr 23 '22 at 19:18
  • I changed the total animation duration from 2s to 38ms, and changed the percentages in the keyframes from 69% and 70% to 37% and 38%, is that correct? – Xinyi Apr 23 '22 at 19:27
  • 1
    @Xinyi yes, the duration will define the total of both state and the percentage will allow you to divide the time between both considering that 49%/50% will give equal time – Temani Afif Apr 23 '22 at 19:31
  • @TemaniAfif thanks. I am still a bit confused about the middle two percentages, 69 and 70. I think it means the first one is shown for 69% of the time, but what about the second one? say, if I changed 70 to be 90. – Xinyi Apr 23 '22 at 19:42
  • 1
    @Xinyi you will have a transition between 69% and 90% but order is not animatable so the change will happen somwhere between 69% and 90%. when using 69%/70% we control when the transition will happen, between 69% and 70% so we can say it's almost 70% – Temani Afif Apr 23 '22 at 19:52
  • @TemaniAfif ah, I understand now. – Xinyi Apr 23 '22 at 20:01
1

There's several other approaches to accomplish the goal. If you don't mind using pseudo elements then perhaps here's an option. I can add more later if you don't want pseudo elements.

.special-blinky {
  position: relative;
  font-size: 3rem;
  margin: 3rem;
}

.special-blinky:before {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  content: 'MASK';
  animation: blinky-special 1s linear infinite;
}


@keyframes blinky-special {
  50% { content: 'TARGET'}
}
<div class="special-blinky"></div>
Chris W.
  • 22,835
  • 3
  • 60
  • 94
  • this does not work because both words are being presented for 1s, I need them presented in different durations. – Xinyi Apr 22 '22 at 19:07
  • I do not think pseudo elements will work because I need it to work for many word pairs. – Xinyi Apr 22 '22 at 19:09
  • @Xinyi So you just want one word to say visible longer than the other? – Chris W. Apr 22 '22 at 19:09
  • @Xinyi If you don't mind using JS for this task ... there is https://greensock.com - relatively easy to use with a lot of docu. It's like flash but for JS. You can create your own pipelines, delays etc. – F. Müller Apr 22 '22 at 19:09
  • Nah greensock is probably overkill for such a little thing, if I understand the visual requirement then it's still not a big deal with pure css either. – Chris W. Apr 22 '22 at 19:10
  • @ChrisW. Well you've got a point there. But I'd like to know myself, how you would do that in css without running mad in the meantime. Feel free to surprise me :) – F. Müller Apr 22 '22 at 19:14
  • @F.Müller there's several ways, Temani just added one of which that's valid. I didn't apparently understand the end goal when originally answered lol. – Chris W. Apr 22 '22 at 20:13