AI CSS Animations

AI Summarizing Loader

A small document with a highlighter sweeping across its lines one at a time, as if the model is reading it, and a sparkle badge in the corner. Two synced animations, one moving down in steps.

Also known as: ai reading document animation, document scanning loader, summarize loading.

HTML

<div class="ldr-ai-summarizing" role="status" aria-label="Summarizing">
  <span class="ldr-ai-summarizing-mark" aria-hidden="true"><i></i></span>
  <span class="ldr-ai-summarizing-line"></span>
  <span class="ldr-ai-summarizing-line"></span>
  <span class="ldr-ai-summarizing-line"></span>
  <span class="ldr-ai-summarizing-line"></span>
  <span class="ldr-ai-summarizing-line"></span>
  <svg class="ldr-ai-summarizing-badge" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 0C13 7 17 11 24 12C17 13 13 17 12 24C11 17 7 13 0 12C7 11 11 7 12 0Z"/></svg>
</div>

CSS

.ldr-ai-summarizing {
  --s: var(--ldr-size, 48px);
  --c: var(--ldr-color, #3b82f6);
  --row: calc(var(--s) / 5);
  position: relative;
  isolation: isolate;
  display: grid;
  align-content: start;
  width: calc(var(--s) * 1.15);
  padding: calc(var(--s) / 5) calc(var(--s) / 6);
  border-radius: calc(var(--s) / 9);
  background: color-mix(in srgb, var(--ldr-color, #3b82f6) 6%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ldr-color, #3b82f6) 28%, transparent);
}
.ldr-ai-summarizing-line {
  height: var(--row);
  background: linear-gradient(color-mix(in srgb, var(--ldr-color, #3b82f6) 40%, transparent), color-mix(in srgb, var(--ldr-color, #3b82f6) 40%, transparent)) 0 50% / 100% calc(var(--s) / 14) no-repeat;
  border-radius: calc(var(--s) / 28);
}
.ldr-ai-summarizing-line:nth-of-type(3) { width: 82%; }
.ldr-ai-summarizing-line:nth-of-type(5) { width: 90%; }
.ldr-ai-summarizing-line:nth-of-type(6) { width: 55%; }
.ldr-ai-summarizing-mark {
  position: absolute;
  left: calc(var(--s) / 8);
  right: calc(var(--s) / 8);
  top: calc(var(--s) / 5);
  z-index: -1;
  height: var(--row);
  animation: ldr-ai-summarizing-down 3s steps(5, end) infinite;
}
.ldr-ai-summarizing-mark i {
  position: absolute;
  inset: 12% 0;
  border-radius: calc(var(--s) / 20);
  background: color-mix(in srgb, var(--ldr-color, #3b82f6) 30%, transparent);
  transform-origin: left;
  animation: ldr-ai-summarizing-sweep 0.6s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.ldr-ai-summarizing-badge {
  position: absolute;
  right: calc(var(--s) / -7);
  top: calc(var(--s) / -7);
  width: calc(var(--s) / 2.6);
  height: calc(var(--s) / 2.6);
  fill: var(--c);
  animation: ldr-ai-summarizing-twinkle 1.5s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes ldr-ai-summarizing-down {
  from { transform: translateY(0); }
  to   { transform: translateY(500%); }
}
@keyframes ldr-ai-summarizing-sweep {
  0%        { transform: scaleX(0); opacity: 1; }
  75%       { transform: scaleX(1); opacity: 1; }
  100%      { transform: scaleX(1); opacity: 0.4; }
}
@keyframes ldr-ai-summarizing-twinkle {
  0%   { transform: scale(1) rotate(0deg); }
  50%  { transform: scale(0.72) rotate(45deg); }
  100% { transform: scale(1) rotate(90deg); }
}

@media (prefers-reduced-motion: reduce) {
  .ldr-ai-summarizing, .ldr-ai-summarizing *, .ldr-ai-summarizing::before, .ldr-ai-summarizing::after, .ldr-ai-summarizing *::before, .ldr-ai-summarizing *::after {
    animation-duration: 3s;
  }
}

Customizing this loader

  • Color: set --ldr-color on the element or a parent. Currently previewing #3b82f6.
  • Size: set --ldr-size. Every dimension in the snippet is derived from it. Currently previewing 64px.
  • Speed: change the duration on the animation shorthand. Delays on the children are relative, so they keep their rhythm.
  • Accessibility: the root carries role="status" and an aria-label so screen readers announce the wait. The reduced-motion rule at the end slows the animation for users who asked for less motion.

Similar loaders