My old epileptic font remastered using CSS3 animations.
Had to use an obscene amount of styles. Unlike box-shadow
, text-shadow
doesn’t have spread
parameter, so I had to emulate the stroke using eight shadows. Moreover, you can’t just change the color of the shadows, so I also had to redefine all eight shadows in each keyframe.
On the bright side, latest Presto-based Opera and latest Firefox don’t require prefixes for animations, and IE10 had always worked without them, so I dropped every prefix but -webkit
.
To make characters wobble asynchronously I give ’em random classes. A total of eight classes (one per animation keyframe), each having animation-delay
equal to the length of the animation step, multiplied by the number of the class.
Animation smoothness is tweaked by the number of steps between animation keyframes. The more steps there are, the smoother the animation:
-webkit-animation-timing-function: steps(1);
animation-timing-function: steps(1);
For continuous animation replace steps()
with linear
(or just remove animation-timing-function
completely, as linear
is used by default).
"Wobbling" strength vary a bit between browsers. I used Chrome to tweak it, it seem to wobble a bit quieter in the others. After yet another update Chrome is wobbling just like the others. That’s great.
IE10 on winphone wins the “Tough guy” nomination among the mobile devices. Animates like a boss. Weak mobile webkits constantly loose desync and deliver pretty weak framerate overall. The weakest is Opera Classic on Android (as well as on the desktop, btw).
HTML:
<div class="pepyaka async">
<span class="pep1">Y</span><span class="pep6">a</span><span class="pep2">r</span><span class="pep0">r</span><span class="pep4">r</span><span class="pep7">!</span>
</div>
CSS:
.pepyaka {
font-family: 'Book Antiqua', 'Georgia', serif;
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
.pepyaka > * {
display: inline-block;
font-size: 3.5em;
letter-spacing: 0.2em;
-webkit-animation-duration: 0.4s;
animation-duration: 0.4s;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: steps(1);
animation-timing-function: steps(1);
-webkit-animation-name: pep;
animation-name: pep;
color: #1be5a0;
text-shadow: -0.05em 0 0 #000000,
-0.03em -0.03em 0 #000000,
0 -0.05em 0 #000000,
0.03em -0.03em 0 #000000,
0.05em 0 0 #000000,
0.03em 0.03em 0 #000000,
0 0.05em 0 #000000,
-0.03em 0.03em 0 #000000;
}
.pepyaka.smooth > * {
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
}
@-webkit-keyframes pep {
from {
color: #1be5a0;
text-shadow: -0.05em 0 0 #000000,
-0.03em -0.03em 0 #000000,
0 -0.05em 0 #000000,
0.03em -0.03em 0 #000000,
0.05em 0 0 #000000,
0.03em 0.03em 0 #000000,
0 0.05em 0 #000000,
-0.03em 0.03em 0 #000000;
-webkit-transform: translate(0.037em,-0.037em);
}
12.5% {
color: #b33aff;
text-shadow: -0.05em 0 0 #1be5a0,
-0.03em -0.03em 0 #1be5a0,
0 -0.05em 0 #1be5a0,
0.03em -0.03em 0 #1be5a0,
0.05em 0 0 #1be5a0,
0.03em 0.03em 0 #1be5a0,
0 0.05em 0 #1be5a0,
-0.03em 0.03em 0 #1be5a0;
-webkit-transform: translate(-0.05em,0.06em);
}
25% {
color: #fffe00;
text-shadow: -0.05em 0 0 #b33aff,
-0.03em -0.03em 0 #b33aff,
0 -0.05em 0 #b33aff,
0.03em -0.03em 0 #b33aff,
0.05em 0 0 #b33aff,
0.03em 0.03em 0 #b33aff,
0 0.05em 0 #b33aff,
-0.03em 0.03em 0 #b33aff;
-webkit-transform: translate(-0.037em,-0.075em);
}
37.5% {
color: #f12938;
text-shadow: -0.05em 0 0 #fffe00,
-0.03em -0.03em 0 #fffe00,
0 -0.05em 0 #fffe00,
0.03em -0.03em 0 #fffe00,
0.05em 0 0 #fffe00,
0.03em 0.03em 0 #fffe00,
0 0.05em 0 #fffe00,
-0.03em 0.03em 0 #fffe00;
-webkit-transform: translate(0.037em,-0.037em);
}
50% {
color: #62e51b;
text-shadow: -0.05em 0 0 #f12938,
-0.03em -0.03em 0 #f12938,
0 -0.05em 0 #f12938,
0.03em -0.03em 0 #f12938,
0.05em 0 0 #f12938,
0.03em 0.03em 0 #f12938,
0 0.05em 0 #f12938,
-0.03em 0.03em 0 #f12938;
-webkit-transform: translate(0,0);
}
62.5% {
color: #2751ef;
text-shadow: -0.05em 0 0 #62e51b,
-0.03em -0.03em 0 #62e51b,
0 -0.05em 0 #62e51b,
0.03em -0.03em 0 #62e51b,
0.05em 0 0 #62e51b,
0.03em 0.03em 0 #62e51b,
0 0.05em 0 #62e51b,
-0.03em 0.03em 0 #62e51b;
-webkit-transform: translate(-0.075em,-0.018em);
}
75% {
color: #ffc600;
text-shadow: -0.05em 0 0 #2751ef,
-0.03em -0.03em 0 #2751ef,
0 -0.05em 0 #2751ef,
0.03em -0.03em 0 #2751ef,
0.05em 0 0 #2751ef,
0.03em 0.03em 0 #2751ef,
0 0.05em 0 #2751ef,
-0.03em 0.03em 0 #2751ef;
-webkit-transform: translate(0.057em,-0.057em);
}
87.5% {
color: #000000;
text-shadow: -0.05em 0 0 #ffc600,
-0.03em -0.03em 0 #ffc600,
0 -0.05em 0 #ffc600,
0.03em -0.03em 0 #ffc600,
0.05em 0 0 #ffc600,
0.03em 0.03em 0 #ffc600,
0 0.05em 0 #ffc600,
-0.03em 0.03em 0 #ffc600;
-webkit-transform: translate(-0.060em,0.060em);
}
to {
color: #1be5a0;
text-shadow: -0.05em 0 0 #000000,
-0.03em -0.03em 0 #000000,
0 -0.05em 0 #000000,
0.03em -0.03em 0 #000000,
0.05em 0 0 #000000,
0.03em 0.03em 0 #000000,
0 0.05em 0 #000000,
-0.03em 0.03em 0 #000000;
-webkit-transform: translate(0.018em,-0.018em);
}
}
@keyframes pep {
from {
color: #1be5a0;
text-shadow: -0.05em 0 0 #000000,
-0.03em -0.03em 0 #000000,
0 -0.05em 0 #000000,
0.03em -0.03em 0 #000000,
0.05em 0 0 #000000,
0.03em 0.03em 0 #000000,
0 0.05em 0 #000000,
-0.03em 0.03em 0 #000000;
transform: translate(0.037em,-0.037em);
}
12.5% {
color: #b33aff;
text-shadow: -0.05em 0 0 #1be5a0,
-0.03em -0.03em 0 #1be5a0,
0 -0.05em 0 #1be5a0,
0.03em -0.03em 0 #1be5a0,
0.05em 0 0 #1be5a0,
0.03em 0.03em 0 #1be5a0,
0 0.05em 0 #1be5a0,
-0.03em 0.03em 0 #1be5a0;
transform: translate(-0.05em,0.06em);
}
25% {
color: #fffe00;
text-shadow: -0.05em 0 0 #b33aff,
-0.03em -0.03em 0 #b33aff,
0 -0.05em 0 #b33aff,
0.03em -0.03em 0 #b33aff,
0.05em 0 0 #b33aff,
0.03em 0.03em 0 #b33aff,
0 0.05em 0 #b33aff,
-0.03em 0.03em 0 #b33aff;
transform: translate(-0.037em,-0.075em);
}
37.5% {
color: #f12938;
text-shadow: -0.05em 0 0 #fffe00,
-0.03em -0.03em 0 #fffe00,
0 -0.05em 0 #fffe00,
0.03em -0.03em 0 #fffe00,
0.05em 0 0 #fffe00,
0.03em 0.03em 0 #fffe00,
0 0.05em 0 #fffe00,
-0.03em 0.03em 0 #fffe00;
transform: translate(0.037em,-0.037em);
}
50% {
color: #62e51b;
text-shadow: -0.05em 0 0 #f12938,
-0.03em -0.03em 0 #f12938,
0 -0.05em 0 #f12938,
0.03em -0.03em 0 #f12938,
0.05em 0 0 #f12938,
0.03em 0.03em 0 #f12938,
0 0.05em 0 #f12938,
-0.03em 0.03em 0 #f12938;
transform: translate(0,0);
}
62.5% {
color: #2751ef;
text-shadow: -0.05em 0 0 #62e51b,
-0.03em -0.03em 0 #62e51b,
0 -0.05em 0 #62e51b,
0.03em -0.03em 0 #62e51b,
0.05em 0 0 #62e51b,
0.03em 0.03em 0 #62e51b,
0 0.05em 0 #62e51b,
-0.03em 0.03em 0 #62e51b;
transform: translate(-0.075em,-0.018em);
}
75% {
color: #ffc600;
text-shadow: -0.05em 0 0 #2751ef,
-0.03em -0.03em 0 #2751ef,
0 -0.05em 0 #2751ef,
0.03em -0.03em 0 #2751ef,
0.05em 0 0 #2751ef,
0.03em 0.03em 0 #2751ef,
0 0.05em 0 #2751ef,
-0.03em 0.03em 0 #2751ef;
transform: translate(0.057em,-0.057em);
}
87.5% {
color: #000000;
text-shadow: -0.05em 0 0 #ffc600,
-0.03em -0.03em 0 #ffc600,
0 -0.05em 0 #ffc600,
0.03em -0.03em 0 #ffc600,
0.05em 0 0 #ffc600,
0.03em 0.03em 0 #ffc600,
0 0.05em 0 #ffc600,
-0.03em 0.03em 0 #ffc600;
transform: translate(-0.060em,0.060em);
}
to {
color: #1be5a0;
text-shadow: -0.05em 0 0 #000000,
-0.03em -0.03em 0 #000000,
0 -0.05em 0 #000000,
0.03em -0.03em 0 #000000,
0.05em 0 0 #000000,
0.03em 0.03em 0 #000000,
0 0.05em 0 #000000,
-0.03em 0.03em 0 #000000;
transform: translate(0.018em,-0.018em);
}
}
/*
Async wobbling styles
Defining different colors and shadows for each `pep` class isn't
necessary, but it gives colorful letters at the start, while waiting
for initial `animation-delay` to pass.
They can be omitted at the price of
same-colored letters at the start of the animation.
*/
.async .pep0 {
/* nothing here */
}
.async .pep1 {
-webkit-animation-delay: 0.05s;
animation-delay: 0.05s;
color: #b33aff;
text-shadow: -0.05em 0 0 #1be5a0,
-0.03em -0.03em 0 #1be5a0,
0 -0.05em 0 #1be5a0,
0.03em -0.03em 0 #1be5a0,
0.05em 0 0 #1be5a0,
0.03em 0.03em 0 #1be5a0,
0 0.05em 0 #1be5a0,
-0.03em 0.03em 0 #1be5a0;
}
.async .pep2 {
-webkit-animation-delay: 0.1s;
animation-delay: 0.1s;
color: #fffe00;
text-shadow: -0.05em 0 0 #b33aff,
-0.03em -0.03em 0 #b33aff,
0 -0.05em 0 #b33aff,
0.03em -0.03em 0 #b33aff,
0.05em 0 0 #b33aff,
0.03em 0.03em 0 #b33aff,
0 0.05em 0 #b33aff,
-0.03em 0.03em 0 #b33aff;
}
.async .pep3 {
-webkit-animation-delay: 0.15s;
animation-delay: 0.15s;
color: #f12938;
text-shadow: -0.05em 0 0 #fffe00,
-0.03em -0.03em 0 #fffe00,
0 -0.05em 0 #fffe00,
0.03em -0.03em 0 #fffe00,
0.05em 0 0 #fffe00,
0.03em 0.03em 0 #fffe00,
0 0.05em 0 #fffe00,
-0.03em 0.03em 0 #fffe00;
}
.async .pep4 {
-webkit-animation-delay: 0.2s;
animation-delay: 0.2s;
color: #62e51b;
text-shadow: -0.05em 0 0 #f12938,
-0.03em -0.03em 0 #f12938,
0 -0.05em 0 #f12938,
0.03em -0.03em 0 #f12938,
0.05em 0 0 #f12938,
0.03em 0.03em 0 #f12938,
0 0.05em 0 #f12938,
-0.03em 0.03em 0 #f12938;
}
.async .pep5 {
-webkit-animation-delay: 0.25s;
animation-delay: 0.25s;
color: #2751ef;
text-shadow: -0.05em 0 0 #62e51b,
-0.03em -0.03em 0 #62e51b,
0 -0.05em 0 #62e51b,
0.03em -0.03em 0 #62e51b,
0.05em 0 0 #62e51b,
0.03em 0.03em 0 #62e51b,
0 0.05em 0 #62e51b,
-0.03em 0.03em 0 #62e51b;
}
.async .pep6 {
-webkit-animation-delay: 0.3s;
animation-delay: 0.3s;
color: #ffc600;
text-shadow: -0.05em 0 0 #2751ef,
-0.03em -0.03em 0 #2751ef,
0 -0.05em 0 #2751ef,
0.03em -0.03em 0 #2751ef,
0.05em 0 0 #2751ef,
0.03em 0.03em 0 #2751ef,
0 0.05em 0 #2751ef,
-0.03em 0.03em 0 #2751ef;
}
.async .pep7 {
-webkit-animation-delay: 0.35s;
animation-delay: 0.35s;
color: #000000;
text-shadow: -0.05em 0 0 #ffc600,
-0.03em -0.03em 0 #ffc600,
0 -0.05em 0 #ffc600,
0.03em -0.03em 0 #ffc600,
0.05em 0 0 #ffc600,
0.03em 0.03em 0 #ffc600,
0 0.05em 0 #ffc600,
-0.03em 0.03em 0 #ffc600;
}