AI CSS Animations

Moving Light Shadow Text

A small light swings in an arc above the word and its soft shadow slides the other way, short when the light is overhead and long when it is low. Light and shadow share one alternating clock.

Also known as: dynamic text shadow css, text shadow follows light, light source shadow animation.

SHADOW

HTML

<div class="txt-moving-light-shadow-text"><span class="txt-moving-light-shadow-text-light" aria-hidden="true"></span><span class="txt-moving-light-shadow-text-shadow" aria-hidden="true">SHADOW</span><span class="txt-moving-light-shadow-text-word">SHADOW</span></div>

CSS

.txt-moving-light-shadow-text {
  --c: var(--txt-color, #3b82f6);
  font-size: calc(var(--txt-size, 32px) * 1.6);
  font-family: system-ui, sans-serif;
  font-weight: 900;
  line-height: 1.2;
  position: relative;
  display: inline-grid;
  letter-spacing: 0.04em;}
.txt-moving-light-shadow-text-shadow,
.txt-moving-light-shadow-text-word {
  grid-area: 1 / 1;
}
.txt-moving-light-shadow-text-word {
  position: relative;
  color: var(--c);
}
.txt-moving-light-shadow-text-shadow {
  color: color-mix(in srgb, color-mix(in srgb, var(--c) 40%, #000) 35%, transparent);
  animation: txt-moving-light-shadow-text-cast 2.8s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}
/* the light: a glowing dot on an arc over the word */
.txt-moving-light-shadow-text-light {
  position: absolute;
  left: 50%;
  top: -0.7em;
  width: 0.3em;
  height: 0.3em;
  margin-left: -0.15em;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--c) 55%, #fff) 0 30%, var(--c) 60%);
  box-shadow: 0 0 0.3em color-mix(in srgb, var(--c) 60%, transparent);
  animation: txt-moving-light-shadow-text-orbit 2.8s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}
@keyframes txt-moving-light-shadow-text-orbit {
  0%   { transform: translate(-2.6em, 0.35em); }
  50%  { transform: translate(0, -0.15em); }
  100% { transform: translate(2.6em, 0.35em); }
}
/* the shadow falls away from the light: long and soft when it is low */
@keyframes txt-moving-light-shadow-text-cast {
  0%   { transform: translate(0.28em, 0.16em); filter: blur(0.045em); }
  50%  { transform: translate(0, 0.08em); filter: blur(0.015em); }
  100% { transform: translate(-0.28em, 0.16em); filter: blur(0.045em); }
}

@media (prefers-reduced-motion: reduce) {
  .txt-moving-light-shadow-text, .txt-moving-light-shadow-text *, .txt-moving-light-shadow-text::before, .txt-moving-light-shadow-text::after, .txt-moving-light-shadow-text *::before, .txt-moving-light-shadow-text *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --txt-color on the element or a parent. Currently previewing #3b82f6.
  • Font size: set --txt-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 40px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar text animations