AI CSS Animations

Skeleton Morphing Into Text

Shimmering skeleton bars, each already the width of its line, flatten toward the baseline as the real reply blurs up through them line by line. Bars and text share one grid cell per line.

Also known as: ai response skeleton, skeleton loading to content, shimmer skeleton text, placeholder to text animation.

Cold starts come from the 140 MB image.

Move the model weights to a volume and

boot drops to about 900 ms.

HTML

<div class="aia-skeleton-to-text" role="status" aria-label="Writing a reply">
  <p class="aia-skeleton-to-text-line" style="--i: 0"><span>Cold starts come from the 140 MB image.</span></p>
  <p class="aia-skeleton-to-text-line" style="--i: 1"><span>Move the model weights to a volume and</span></p>
  <p class="aia-skeleton-to-text-line" style="--i: 2"><span>boot drops to about 900 ms.</span></p>
</div>

CSS

.aia-skeleton-to-text {
  --c: var(--aia-color, #7c5cff);
  font-size: var(--aia-size, 16px);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.4;
  display: grid;
  gap: 0.3em;
  font-size: calc(var(--aia-size, 16px) * 1.05);
}
.aia-skeleton-to-text-line {
  display: grid;
  width: fit-content;
  margin: 0;
  line-height: 1.5;
}
.aia-skeleton-to-text-line::before,
.aia-skeleton-to-text-line span {
  grid-area: 1 / 1;
}
.aia-skeleton-to-text-line::before {
  content: "";
  align-self: center;
  height: 0.78em;
  border-radius: 0.4em;
  background: linear-gradient(90deg, color-mix(in srgb, currentColor 9%, transparent) 30%, color-mix(in srgb, currentColor 17%, transparent) 50%, color-mix(in srgb, currentColor 9%, transparent) 70%) 0 0 / 300% 100%;
  animation:
    aia-skeleton-to-text-shimmer 1.6s linear infinite,
    aia-skeleton-to-text-bar 7s infinite both;
  animation-delay: 0s, calc(var(--i) * 0.14s);
}
.aia-skeleton-to-text-line span {
  white-space: nowrap;
  animation: aia-skeleton-to-text-text 7s infinite both;
  animation-delay: calc(var(--i) * 0.14s);
}
@keyframes aia-skeleton-to-text-shimmer {
  from { background-position: 100% 0; }
  to   { background-position: -50% 0; }
}
@keyframes aia-skeleton-to-text-bar {
  0%, 36% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(0.5, 0, 0.2, 1); }
  46%, 88% { opacity: 0; transform: translateY(0.35em) scaleY(0.15); }
  96%, 100% { opacity: 1; transform: none; }
}
@keyframes aia-skeleton-to-text-text {
  0%, 38% { opacity: 0; transform: translateY(0.25em); filter: blur(0.25em); animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); }
  50%, 86% { opacity: 1; transform: none; filter: blur(0); }
  92%, 100% { opacity: 0; transform: none; filter: blur(0.1em); }
}
@media (prefers-reduced-motion: reduce) {
  .aia-skeleton-to-text-line::before,
  .aia-skeleton-to-text-line span { animation: none; }
  .aia-skeleton-to-text-line::before { opacity: 0; }
}

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

Customizing this snippet

  • Color: set --aia-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --aia-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • 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 ai animations