Skip to content

CSS animation: Live coding

Reduced motion media query

One way to respect users’ preferences for reduced motion is via a CSS media query that detects if they have selected reduced motion in their operating system settings.

Warning

This web page has a large triangle that moves down the left side of the page if you do not have reduced motion set on your browser.

View in browser

html
<div id="triangle"></div>
css
#triangle {
  position: absolute;
  background-color: #fdf3e3;
  width: 100px;
  height: 100px;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  left: 0;
  top: 2rem;
}

@media (prefers-reduced-motion: no-preference) {
  #triangle {
    animation-name: fall;
    animation-duration: 4s;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
  }
  @keyframes fall {
    0% {
      top: calc(0vh - 100px);
    }
    100% {
      top: 100vh;
    }
  }
}

Color transition

View in browser

html
<button class="button">Rainbows</button>
<button class="button">Sunshine</button>
<button class="button">Moonbeams</button>
css
:root {
  --primary: oklch(0.97 0.02 80);
  --shadow: oklch(from var(--primary) 0.65 c h);
  --darker-shadow: oklch(from var(--primary) 0.45 c h);
  --accent: oklch(from rebeccapurple 0.75 c h)
}
css
.button {
  font-family: "Space Mono", monospace;
  padding: 1rem;
  background-color: var(--primary);
  box-shadow: 10px 5px var(--shadow);
  max-width: 12rem;
  border: none;
  transition-property: background-color, box-shadow, translate;
  transition-duration: 200ms;
  transition-timing-function: ease-in;
}
.button:hover {
  background-color: var(--accent);
  box-shadow: 8px 3px var(--darker-shadow);
  translate: 2px 2px;
  transition-timing-function: ease-out;
}

View in browser

html
<h1 id="site-title">A new way</h1>
css
#site-title {
  margin-top: 8rem;
  font-size: 2.2rem;
  font-family: "Space Mono", monospace;
  max-width: fit-content;
  padding-block: 1rem;
}
#site-title::after {
  content: "_" / "";
  animation-duration: 400ms;
  animation-timing-function: steps(2, jump-none);
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-name: blink;
}
@keyframes blink {
  0% {
    opacity: 100%;
  }
  100% {
    opacity: 0%;
  }
}

Bounce

This example is by Eric Meyer and Estelle Weyl.

View in browser

html
<div class="ball"></div>
css
.ball {
  height: 50px;
  width: 50px;
  border-radius: 50%;
  background-color: oklch(from red 0.5 0.2 h);
  animation-name: bounce;
  animation-duration: 5s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
}
@keyframes bounce {
  0% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
  30% {
    transform: translateY(100px);
    animation-timing-function: ease-in;
  }
  58% {
    transform: translateY(200px);
    animation-timing-function: ease-in;
  }
  80% {
    transform: translateY(300px);
    animation-timing-function: ease-in;
  }
  95% {
    transform: translateY(360px);
    animation-timing-function: ease-in;
  }
  15%,
  45%,
  71%,
  89%,
  100% {
    transform: translateY(380px);
    animation-timing-function: ease-out;
  }
}

Content CC BY 4.0 | Code AGPL 3.0