AI CSS Animations

Falling Letters Pile Up

Letters drop in one by one, squash on impact, bounce and come to rest in a tumbled heap, until a trapdoor floor swings open and drops them all. Each fall is a keyframe built from a short table.

Also known as: falling letters animation, letters falling physics css, gravity text animation.

HTML

<div class="txt-letters-pile-up" aria-label="Gravity"><span aria-hidden="true"><b class="txt-letters-pile-up-l0">G</b><b class="txt-letters-pile-up-l1">R</b><b class="txt-letters-pile-up-l2">A</b><b class="txt-letters-pile-up-l3">V</b><b class="txt-letters-pile-up-l4">I</b><b class="txt-letters-pile-up-l5">T</b><b class="txt-letters-pile-up-l6">Y</b></span></div>

CSS

.txt-letters-pile-up {
  --c: var(--txt-color, #3b82f6);
  font-size: var(--txt-size, 32px);
  font-family: system-ui, sans-serif;
  font-weight: 700;
  line-height: 1.2;
  position: relative;
  width: 8em;
  height: 5.2em;
  overflow: hidden;}
/* the floor: two halves hinged at the outside edges */
.txt-letters-pile-up::before,
.txt-letters-pile-up::after {
  content: "";
  position: absolute;
  bottom: 0.5em;
  width: calc(50% - 0.6em);
  height: 0.09em;
  border-radius: 0.05em;
  background: color-mix(in srgb, currentColor 30%, transparent);
  animation: txt-letters-pile-up-door 6.2s infinite;
}
.txt-letters-pile-up::before { left: 0.6em; transform-origin: 0 50%; --s: 1; }
.txt-letters-pile-up::after { right: 0.6em; transform-origin: 100% 50%; --s: -1; }
.txt-letters-pile-up b {
  position: absolute;
  left: 50%;
  bottom: calc(0.59em / 1.75);
  font-size: 1.75em;
  font-weight: 900;
  line-height: 0.76;
  transform-origin: 50% 100%;
}
.txt-letters-pile-up b:last-child { color: var(--c); }
.txt-letters-pile-up .txt-letters-pile-up-l0 { animation: txt-letters-pile-up-l0 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l1 { animation: txt-letters-pile-up-l1 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l2 { animation: txt-letters-pile-up-l2 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l3 { animation: txt-letters-pile-up-l3 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l4 { animation: txt-letters-pile-up-l4 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l5 { animation: txt-letters-pile-up-l5 6.2s infinite; }
.txt-letters-pile-up .txt-letters-pile-up-l6 { animation: txt-letters-pile-up-l6 6.2s infinite; }
@keyframes txt-letters-pile-up-l0 {
  0%, 2.42% { translate: calc(-1.2em - 50%) -4.6em; rotate: -40deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  9.19% { translate: calc(-1.2em - 50%) 0em; rotate: -8deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  11.77% { translate: calc(-1.2em - 50%) -0.2em; rotate: -4.8deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  14.35% { translate: calc(-1.2em - 50%) 0em; rotate: -8deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  16.94%, 72.58% { translate: calc(-1.2em - 50%) 0em; rotate: -8deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(-1.2em - 50%) 3.6em; rotate: -36deg; opacity: 0; }
  82.58%, 100% { translate: calc(-1.2em - 50%) -4.6em; rotate: -40deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l1 {
  0%, 7.58% { translate: calc(-0.4em - 50%) -4.6em; rotate: 35deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  14.35% { translate: calc(-0.4em - 50%) 0em; rotate: 6deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  16.94% { translate: calc(-0.4em - 50%) -0.2em; rotate: 3.6deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  19.52% { translate: calc(-0.4em - 50%) 0em; rotate: 6deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  22.1%, 72.58% { translate: calc(-0.4em - 50%) 0em; rotate: 6deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(-0.4em - 50%) 3.6em; rotate: 34deg; opacity: 0; }
  82.58%, 100% { translate: calc(-0.4em - 50%) -4.6em; rotate: 35deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l2 {
  0%, 12.74% { translate: calc(0.42em - 50%) -4.6em; rotate: -30deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  19.52% { translate: calc(0.42em - 50%) 0em; rotate: -4deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  22.1% { translate: calc(0.42em - 50%) -0.2em; rotate: -2.4deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  24.68% { translate: calc(0.42em - 50%) 0em; rotate: -4deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  27.26%, 72.58% { translate: calc(0.42em - 50%) 0em; rotate: -4deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(0.42em - 50%) 3.6em; rotate: -32deg; opacity: 0; }
  82.58%, 100% { translate: calc(0.42em - 50%) -4.6em; rotate: -30deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l3 {
  0%, 17.9% { translate: calc(1.2em - 50%) -4.6em; rotate: 50deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  24.68% { translate: calc(1.2em - 50%) 0em; rotate: -16deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  27.26% { translate: calc(1.2em - 50%) -0.2em; rotate: -9.6deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  29.84% { translate: calc(1.2em - 50%) 0em; rotate: -16deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  32.42%, 72.58% { translate: calc(1.2em - 50%) 0em; rotate: -16deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(1.2em - 50%) 3.6em; rotate: -44deg; opacity: 0; }
  82.58%, 100% { translate: calc(1.2em - 50%) -4.6em; rotate: 50deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l4 {
  0%, 23.06% { translate: calc(-0.8em - 50%) -4.6em; rotate: 60deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  29.84% { translate: calc(-0.8em - 50%) -0.72em; rotate: -14deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  32.42% { translate: calc(-0.8em - 50%) -0.92em; rotate: -8.4deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  35% { translate: calc(-0.8em - 50%) -0.72em; rotate: -14deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  37.58%, 72.58% { translate: calc(-0.8em - 50%) -0.72em; rotate: -14deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(-0.8em - 50%) 2.88em; rotate: -42deg; opacity: 0; }
  82.58%, 100% { translate: calc(-0.8em - 50%) -4.6em; rotate: 60deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l5 {
  0%, 28.23% { translate: calc(0.04em - 50%) -4.6em; rotate: -45deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  35% { translate: calc(0.04em - 50%) -0.74em; rotate: 12deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  37.58% { translate: calc(0.04em - 50%) -0.94em; rotate: 7.2deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  40.16% { translate: calc(0.04em - 50%) -0.74em; rotate: 12deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  42.74%, 72.58% { translate: calc(0.04em - 50%) -0.74em; rotate: 12deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(0.04em - 50%) 2.86em; rotate: 40deg; opacity: 0; }
  82.58%, 100% { translate: calc(0.04em - 50%) -4.6em; rotate: -45deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-l6 {
  0%, 33.39% { translate: calc(-0.4em - 50%) -4.6em; rotate: 70deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  40.16% { translate: calc(-0.4em - 50%) -1.46em; rotate: -22deg; scale: 1.14 0.86; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  42.74% { translate: calc(-0.4em - 50%) -1.66em; rotate: -13.2deg; scale: 0.96 1.04; animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.5); }
  45.32% { translate: calc(-0.4em - 50%) -1.46em; rotate: -22deg; scale: 1.04 0.96; animation-timing-function: ease-out; }
  47.9%, 72.58% { translate: calc(-0.4em - 50%) -1.46em; rotate: -22deg; scale: 1; opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); }
  82.26% { translate: calc(-0.4em - 50%) 2.14em; rotate: -50deg; opacity: 0; }
  82.58%, 100% { translate: calc(-0.4em - 50%) -4.6em; rotate: 70deg; opacity: 0; }
}
@keyframes txt-letters-pile-up-door {
  0%, 71.29% { rotate: 0deg; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
  74.52% { rotate: calc(var(--s) * 64deg); animation-timing-function: ease-out; }
  77.1%, 88.71% { rotate: calc(var(--s) * 58deg); animation-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1); }
  96.77%, 100% { rotate: 0deg; }
}
@media (prefers-reduced-motion: reduce) {
  .txt-letters-pile-up::before, .txt-letters-pile-up::after { animation: none; }
  .txt-letters-pile-up .txt-letters-pile-up-l0 { animation: none; translate: calc(-1.2em - 50%) 0em; rotate: -8deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l1 { animation: none; translate: calc(-0.4em - 50%) 0em; rotate: 6deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l2 { animation: none; translate: calc(0.42em - 50%) 0em; rotate: -4deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l3 { animation: none; translate: calc(1.2em - 50%) 0em; rotate: -16deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l4 { animation: none; translate: calc(-0.8em - 50%) -0.72em; rotate: -14deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l5 { animation: none; translate: calc(0.04em - 50%) -0.74em; rotate: 12deg; }
  .txt-letters-pile-up .txt-letters-pile-up-l6 { animation: none; translate: calc(-0.4em - 50%) -1.46em; rotate: -22deg; }
}

@media (prefers-reduced-motion: reduce) {
  .txt-letters-pile-up, .txt-letters-pile-up *, .txt-letters-pile-up::before, .txt-letters-pile-up::after, .txt-letters-pile-up *::before, .txt-letters-pile-up *::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