Maintaining CSS Style States using “Infinite” Transition Delays

March 19th, 2012 :: Web Development

Earlier today I discovered an interesting way to keep (store) a CSS style on an element using CSS transitions. This is probably best explained with an example, so here goes:

an hourglass

This text will only have the color while the button is pressed down.

This text will keep the given color even after the button is released.

As far as CSS only solutions go, there are two other tricks that can be used to achieve this similar behavior: using either the :checked or the :target pseudo selectors. In this post, I’ll show you my CSS transition technique used above, followed by a slightly cooler example that I’ve been working on.

The HTML

<button class="red">Red</button>
<button class="green">Green</button>
<button class="blue">Blue</button>

<p>
This text will only have the color while the button is pressed down.
</p>
<p class="perm">
This text will keep the given color even after the button is released.
<p>

The CSS

The prefixes below have been omitted for brevity.

/* The large delay prevents the color from changing */
p.perm {
	transition: color 0s 9999999s;
}

/* When a button is pressed, overwrite the transition property
   to remove the delay, so that we can instantly change the color */
.red:active ~ p.perm, .green:active ~ p.perm, .blue:active ~ p.perm {
	transition: color 0s; 
}
.red:active ~ p {
	color: red;
}
.green:active ~ p { 
	color: green; 
}
.blue:active ~ p {
	color: blue;
}

The JavaScript

// Absolutely none

How It Works

It’s actually pretty simple. With our first CSS declaration, we’ve made it so that any changes to the color property will be delayed by approximately 116 days ( :D ). This virtually infinite delay makes sure that the color stays the same once we’ve set it.

The trick now is to somehow temporary get around this delay, so we can apply the different colors with the buttons. This is done by overriding the transition property during the button press, setting the delay to 0. Now when we release the button, the old transition property will kick back in, setting the delay to 116 days. This will make sure that the text will keep the new color instead of going back to the default.

As far as I know, this only works with animatable properties, but a cool fact is that you can end a transition halfway through and have the property still keep the exact value that it had at that point in the transition. So for example, let’s say we have a linear transition from opacity 1 to 0 over two seconds, but only let it run for one second. The opacity value should now be stuck at 0.5 because the delay prevents it from going back. If we now were to run the opacity transition again, it would continue from 0.5 instead of starting over from the beginning.

Now, before you run off and start using this technique all over the web, keep in mind that this is a very dirty hack for achieving something with CSS that ideally should be done with JavaScript.

Taking it a step further

As I mentioned, I’ve been working on something cool to show this off, so make sure to check out the demo below.

Demo

  • http://twitter.com/loktar00 loktar

    Very cool! Only thing I noticed as a bug is if I click on one direction multiple times the characters animation and movement speed decrease for that direction, until you travel in a different direction then the speed is reset to normal.

    • JoelBesada

      Yeah, the closer you are from an edge when you start walking, the slower the character will move. This is because it always transitions toward the edge of the direction over 2 seconds, so if you’re already close to the destination you’ll move much slower.

    • http://leaverou.me Lea Verou

      You can solve that by using transition-timing-function: linear; 

    • JoelBesada

      I already am, that’s not the core problem. Let me see if I can explain this a bit clearer.

      Whenever you hold down one of the directional buttons, a 2 second transition starts to move the character towards the correlating wall. This transition will *always* be 2 seconds, regardless of how far the character has to move. 

      Let’s say you start moving the character towards a wall that is 200 pixels away. This means you’ll move at a speed of 100 pixels per second. Now, let’s say that you release the button after one second, and then press it down again. The remaining distance, 100 pixels, will now also be transitioned over 2 second duration, which means the character now moves at a speed of 50 pixels per second. 

      I don’t think there is any solution to this as far as CSS goes.

    • http://leaverou.me Lea Verou

      Oohh, I get it now. Yeah, can’t think of a solution either. I’ve often wished transitions allowed speeds not just durations.

    • Alan_F

       Redraw the background as water that gets deeper towards the edges – problem solved.

    • http://blog.johnpencola.com/ John Pencola

      Good idea… except for when you reverse direction while in the water ;)

  • http://loneplacebo.com/ Tony Hue

    Neat trick! 

  • Krupinski Rafal

    If you fall asleep during play, lets say for 99999s, you can wake up with al your progress lost :D

    • http://georgedina.ro/ Dina George

      Yeah, this seems legit :)

  • http://twitter.com/prisca_eyedea Prisca Schmarsow

    very clever ;) love it ~ thanks for sharing ;)

  • http://twitter.com/mplungjan Michel Plungjan

    Is this supposed to work in Fx12 on OSX? I do not get the persistence

  • http://coderkid.co.cc/ Matt Curtis

    Me and Mike are in the same boat – not working in my version of FF either (which would be 11.0)

  • http://accessibleweb.eu/ Richard – accessibleweb

    Not working in Firefox

  • Pingback: Design | Pearltrees

  • nicolas

    neat idea! works here (firefox 14).

  • JoelBesada

    Oh right, I forgot that Firefox needs the “s” for the time values in CSS transitions, even when it’s set to 0. Should work now.

  • cballenar

    That’s pretty neat! I’m wondering if having multiple elements doing this could slow down the browser. It must be creating some kind of timer right?
    Thanks for sharing, I love to see CSS being used in new, devious ways :)

    • JoelBesada

      Just having one or a couple of delay timers ticking in the background shouldn’t slow down the browser, but I haven’t done any research on this so I’m not 100% sure. This might also vary a lot between browsers.

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | Qtiva

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays

  • http://joshnh.com/ Joshua Hibbert

    This is fantastic Joel, awesome discovery!

    I was recently playing around with a CSS ‘hover to check’ idea that I had, and I have been able to incorporate your concept: http://jsfiddle.net/joshnh/SAHh7/

    • JoelBesada

      Cool!

      I’m excited to see more things that this can be used for, keep ‘em coming! 

  • http://mrzhang.me/ wo_is神仙

    Coooooooooool~

  • Pingback: My Stream | Maintaining CSS Style States using “Infinite” Transition Delays | My Stream

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays - CSS Feed

  • Karl

    Heya, very cool tip.
    I have another question though, whats upp with the use of this:  ~ Haven’t seen this used in CSS before and would be glad to get a bit of input where to deepen on this. Does it actually do anything? Could I write the same with just a singe space between declarations? Couldn’t find any doc on use of that char ( ~ ).

    Thanks a million guys!

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | BorderCut

  • RaaZ Shrestha

    wow. its cool. 

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | DesignPostBookmarkThing

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | hey you design blog

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | XF Themes

  • Pingback: Maintaining CSS Style States using “Infinite” Transition Delays | Keefr.com

  • Rob Wierzbowski

    I was expecting an excruciatingly complex mess of css rules on your Dabblet example, but it’s sooo simple. Amazingly so. 

    Hats off, very cool.

  • Rafał Krupiński

    For some usecases this would do:

    http://jsfiddle.net/wwwKC/

    • JoelBesada

      Oh, nice!
      There’s probably a lot of cool tricks and hacks using CSS animations as well, would be interesting to experiment around with these properties to see what can be done.

  • Pingback: HTML & CSS From Around the Web on March 23, 2012 – dummieshtml.com

  • Pingback: Friday Focus 03/23/12: Toned Down | Devlounge

  • Pingback: Collective #4 | Wordpress Themes

  • Pingback: Collective #4 « Blog de xkortazar

  • http://gomobile.com.ar Zim

    Interesting idea :)

  • http://about.me/adamstanley Adam Stanley

    Joe – great demo!  In your demo on dabblet, you mentioned “
    please keep in mind that things like this should ideally be handled with Javascript.” but I disagree!  With CSS you can get native hardware acceleration from some browsers (not the case w JavaScript).

    I don’t think this is a hack at all :)  Totally legit way of building awesome web content!

    Have you seen this?
    http://www.html5gamedevs.com/2012/01/19/css-panic-whack-a-mole-style-game-css/ 

  • Guillaume Esquevin

    You could use
    animation-fill-mode: forward;

    To stay on your ending state
    http://dev.w3.org/csswg/css3-animations/#the-animation-fill-mode-property-

  • http://twitter.com/4esn0k Ivanov

    it does not work on Opera 11.62

  • gentlemedia

    I like this very much… played a bit with it because I wanted to see if this also works with the hover pseudo class, but unfortunately this doesn’t work. Why does it work on :active and not on :hover?

  • gentlemedia

    Forget my comment… you can delete it and this one too if you want… my target element  was not a sibling from the trigger element. All good now :)

    • JoelBesada

      I’m glad you figured it out :)

  • Sandeep Virk

    Hi joel,

    can you explain why CHAR stick to 224px dimension because when i increase the width of .screen DIV but CHAR still stop at 224px width.

  • http://www.facebook.com/people/ชนม์บวร-โกมุทบพิตร/100002564835362 ชนม์บวร โกมุทบพิตร

    What about if user visiting more 9999999s ?

  • Roto2store

    great tip, thank u!

  • http://ecommercesoftwarereviewss.com/ ecommerce review

    Nice post! I know t

  • Interested

    Nice concept. I like it a lot. Though if you move to any direction several times it tends to get slower and slower until you move some other direction :)