4 Pure CSS3 with JSPublished 2026-10-05Free · no sign-up
Seven demos that show how CSS transitions behave: easing curves side by side, different timings for each property, a panel that fades in and out of display: none, a smooth theme change, menu items with staggered delays, scaling from different origins and a stepped transition.
Four dots travel the same distance on hover or focus with linear, ease, ease-in-out and a cubic-bezier that overshoots. Watching them together shows why easing matters: linear looks mechanical, and an overshoot feels springy. The durations are identical.
View code
<div class="tr1" tabindex="0" aria-label="Hover or focus to run the comparison"><p><span>linear</span><i style="--e:linear"></i></p><p><span>ease</span><i style="--e:ease"></i></p><p><span>ease-in-out</span><i style="--e:ease-in-out"></i></p><p><span>back-out</span><i style="--e:cubic-bezier(.34,1.56,.64,1)"></i></p></div>
One transition declaration can give each property its own duration and delay: here the colour changes quickly, the lift is slower and the shadow follows a moment later. Listing properties explicitly also avoids transition: all, which animates things you did not mean to.
Panels shown and hidden with display used to pop in and out. transition-behavior: allow-discrete lets display wait for the fade to finish, and @starting-style gives the entry animation its first frame. In older browsers the panel still opens and closes, just instantly.
View code
<div class="tr3"><button aria-expanded="false" aria-controls="tr3p">Show details</button><div id="tr3p" class="p">Ships in 2-3 working days from our studio in Porto. Free returns within 30 days.</div></div>
var b = document.querySelector('.tr3 button'), p = document.getElementById('tr3p');
b.onclick = function () { var o = p.classList.toggle('open'); b.setAttribute('aria-expanded', o); b.textContent = o ? 'Hide details' : 'Show details'; };
04. Smooth Theme Colour Change
TransitionTheme
Switching a card between light and dark transitions its colours over a quarter of a second instead of flashing. The colours are custom properties on the card, and only background-color, color and border-color are transitioned so nothing else is affected.
var c = document.querySelector('.tr4'), b = c.querySelector('button');
b.onclick = function () { var on = c.classList.toggle('dk'); b.setAttribute('aria-pressed', on); };
05. Menu Items with Staggered Delays
TransitionDelay
A menu whose items slide in one after another, using transition-delay calculated from each item's index. Closing reverses quickly with no delay, because people expect things to leave faster than they arrive.
var w = document.querySelector('.tr5'), b = w.querySelector('button');
b.onclick = function () { var o = w.classList.toggle('open'); b.setAttribute('aria-expanded', o); };
06. Scaling from Different Origins
Transitiontransform-origin
Three dropdown-style panels scale from a different transform-origin: top left, top centre and top right. A menu should grow out of the button that opened it, and the origin is the one line that makes that happen.
View code
<div class="tr6" tabindex="0" aria-label="Hover or focus to compare origins"><div style="--o:top left">top left</div><div style="--o:top center">top center</div><div style="--o:top right">top right</div></div>
steps(4) turns a smooth transition into four equal jumps, useful for ticking counters, sprite sheets and retro effects. Here a battery goes from one bar to five in discrete jumps on hover or focus instead of a smooth slide.
View code
<div class="tr7" tabindex="0" role="img" aria-label="Battery icon, fills on hover"><span></span></div>
transition: all animates every property that changes, including ones you did not intend, such as width during a resize. Naming the properties (transform .3s, opacity .3s) is clearer and cheaper.
Easing sets the personality
ease-out feels responsive for things entering, ease-in suits things leaving, and a cubic-bezier() with a value above 1 overshoots for a springy feel. Linear motion looks mechanical except for loaders and progress.
Transitioning to and from display: none
Add transition-behavior: allow-discrete (or allow-discrete in the shorthand) so display flips at the right moment, and set the entry starting point in @starting-style.
Faster out than in
Elements that appear can take 250 to 400ms; elements that leave should be quicker, because the person has already decided to move on. Use a delay of zero on the way out.
Frequently asked questions
What is the difference between a transition and an animation?
A transition runs between two states when a property changes; an animation runs keyframes on its own, and can loop.
Why does my transition not run on page load?
Transitions need a change. Use @starting-style or a keyframe animation for the first appearance.
How do I respect reduced motion?
Each demo shortens or removes its movement inside a prefers-reduced-motion media query, keeping colour changes.