Say you want an element to be in one state for 9 seconds, and in another state for 1 second, on a loop.
No tweening between the state, just a straight swap.
I was wondering how to go about this other day, and Sarah Drasner showed me that you can use reallllllly short distances between keyframes to move from one state to another. Like 59.999% to 60%. No opportunity to tween there on a normal animation duration like 10 seconds.
See the Pen State Change with Quick Keyframe Change by Chris Coyier (@chriscoyier) on CodePen.
Perhaps a little bit cleaner, you don’t even have to get tricky with the .999 stuff if you use steps, like:
div {
...
animation: color 10s steps(10) infinite both;
}
Single keyframe / Single step changer
That led me to stumble into another super weird CSS thing. You’d think if you used steps(1)
that no change at all would occur, right? Since there is only one step? Not true, there is actually 2 steps when you use steps(1)
, for who-knows-what reasoning. We can use that.
Say we were going for the original premise of this article: one state for 9 seconds, and in another state for 1 second. Like this:
1-1-1-1-1-1-1-1-1-2
You could do:
div {
...
background: orangered;
animation: color 10s steps(1) infinite both;
}
@keyframes color {
90% {
background: teal;
}
}
That div will only be teal
for 1 second! Then switch back to orangered
. Change that keyframe to 70% and you’d get:
1-1-1-1-1-1-1-2-2-2
Change it to 10% and you’d get:
1-2-2-2-2-2-2-2-2-2
See the Pen 2efd2dc514da5485073acd6f4b9f3dab by Chris Coyier (@chriscoyier) on CodePen.
Change state and “stay there”
We have a pretty cool trick in hand now for changing state in a timed loop. If you didn’t want the looping part, you could have the animation run once and stay there like:
div {
...
background: orangered;
animation: color 10s steps(1) forwards;
}
@keyframes color {
90% {
background: teal;
}
}
All we’ve done here is removed the infinite
keyword which was making it repeat, and used forwards
meaning “when it gets to the end, keep the styles in that final state”. (The both
keyword will do that too.)
But how do you swap from one state to another from a user interaction? Even this is possible! Imagine an animation with a super long duration (like, days and days). You could tie a user interaction to jumping around positions (state) within that. Here’s a simple demo of that where the clicking of a link triggers a :target
state, which triggers an animation to jump to a position within keyframes that style that state:
See the Pen Keyframe State Changer by Chris Coyier (@chriscoyier) on CodePen.
Just at tricks, folks. We’ll be here all decade.
You guys are having too much fun! Brilliant!
Some additional things to mention:
step-start
andstep-end
timing functions are easier to deal with thansteps(1)
. By default,steps(1)
is equal tostep-end
, although you can also dosteps(1, start)
.If you have a single keyframe for the 50% value,
step-start
will jump to that value as soon as the animation starts, and then as soon as it passes the 50% animation time, it will jump to the next value (or, revert to the underlying values, if you don’t have a next keyframe). In contrast, withstep-end
orsteps(1)
, the animation will stay at the underlying value until you hit the 50% point, and will then jump to the value from the 50% keyframe and stay there until you hit the time point for the next keyframe (or reach 100% time).The position of
end
andstart
of each frame doesn’t change (relative to the overall timeline) if the animation is running in reverse or alternating directions. The entire animation runs backwards, with the same timing for each value.There’s an
animation-play-state
property, with valuesrunning
andpaused
if you want to start and stop an animation based on interaction.For just changing state once on interaction, however, might I suggest getting rid of the
@keyframes
altogether and just setting the new state in the:target{}
rule?Just a thought…
PS
Why do Markdown lists get turned into paragraphs with no spacing when you submit a comment? They work fine in the preview!
Testing an unordered list
List item 2
Testing an ordered list
List item 2
Testing an ordered list with paragraphs (blank lines between items)
List item 2
How it looked in preview:
PPS, The image embed also worked in preview. Here’s the link: https://s3-us-west-2.amazonaws.com/s.cdpn.io/91525/CSS-Tricks-Comment-Preview-Lies.png
Hi Amelia, I really like your thinking about ditching the
@keyframes
. Could you demo your solution in a pen? Thank you!Unless you meant something as simple as http://codepen.io/anon/pen/ENXOvw
That’s cool. This is very helpful in any way. But i’m thinking replacing my old way of building structure for my mobile toggle. I mean pure CSS it’s much lightweight instead of utilizing front end framework nav toggle javascript to implement. Thanks for this idea.
Great idea, might wanna try that. Thank you for sharing.
#WeMakeWebsite
Hi, great trick, always looking for hacks to avoid javascript. But one question, I can’t figure out how clicking on the X closes the nav layer. Can someone poke me into the right direction? Thanks.
Maybe you could provide some codepen so we could possibly help you.
Cheers
Hey there. =)
It’s fairly simple: When you click on the toggler with [href=”#menu”], the #menu gets his :target-state. When you click on the close button (which has [href=”#0″]), the :target-state changes from #menu to #0.
Thanks Azragh. Have a nice day