Motion & Effects

Lesson 10

CSS motion has evolved dramatically. Today you can create scroll-linked animations, glass morphism cards, and clip-path reveals — all without a single line of JavaScript. The trick is learning how to describe animation in natural language.

Keyframe animations — describe the states

Instead of thinking in CSS @keyframes, describe what you see happening:

버튼에 pulse 효과 줘.
천천히 커졌다가 (scale 1.15) 원래 크기로 돌아오는 루프.
opacity도 같이 살짝 변해서 빛나는 느낌.
2초 주기, ease-in-out.

AI generates the @keyframes block. You just described the visual.

CSS Scroll-driven animations — no JS needed

The new animation-timeline: scroll() API lets you tie any CSS animation to scroll progress — no JavaScript:

스크롤 진행률 바 만들어줘.
화면 상단 고정, 높이 3px, accent 색상.
페이지 스크롤에 따라 width 0% → 100%.
animation-timeline: scroll() 사용.

This is a massive shift: effects that once required a scroll listener are now pure CSS. Browser support is growing fast (Chrome, Edge, Firefox) — always add a JS fallback for Safari.

Clip-path reveal

Clip-path cuts elements into shapes and animates the cut smoothly:

텍스트 reveal 효과:
clip-path: inset(0 100% 0 0) 에서 inset(0 0% 0 0) 로 전환.
0.6초, cubic-bezier(0.16, 1, 0.3, 1) — springy feel.
버튼 클릭으로 트리거.

The easing cubic-bezier(0.16, 1, 0.3, 1) is the “Expo Out” curve — it starts fast, finishes with a satisfying snap.

Glass morphism

Glass cards need a few specific values to look right:

유리 카드 컴포넌트:
배경: linear-gradient(135deg, #667eea, #764ba2) 위에 올려줘.
카드 자체: backdrop-filter: blur(16px),
background: rgba(255,255,255,0.2),
border: 1px solid rgba(255,255,255,0.3),
border-radius 16px.

The key: backdrop-filter blurs what’s behind the element — so the card must have a semi-transparent background, not opaque.

Shimmer hover effect

A sweeping light highlight on hover is one of the most polished button effects. It uses a ::after pseudo-element:

버튼 hover시 빛이 왼쪽에서 오른쪽으로 스쳐가는 shimmer 효과.
::after pseudo-element 사용.
linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent).
position: absolute, overflow: hidden on button.

Key prompting tip

When prompting for animations, always specify: what changes, from what to what, how fast, what triggers it, and what the easing feels like (springy, smooth, sharp). These five points give AI everything it needs.

The demo shows all five effects live — keyframe pulse, scroll progress bar, clip-path reveal, glass card, and shimmer button.

Source Code style.css
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: system-ui, -apple-system, sans-serif;
  background: #fff;
  color: #111;
  line-height: 1.6;
}

/* ========================
   Scroll Progress Bar
   ======================== */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  background: #2563eb;
  z-index: 100;
  width: 0%;

  /* Native CSS scroll-driven animation — Chrome/Edge/Firefox */
  animation: grow-width linear both;
  animation-timeline: scroll();
}

@keyframes grow-width {
  from { width: 0%; }
  to   { width: 100%; }
}

/* ========================
   Nav
   ======================== */
nav {
  padding: 16px 40px;
  border-bottom: 1px solid #e5e5e5;
}

nav a {
  color: #2563eb;
  text-decoration: none;
  font-size: 0.875rem;
}

nav a:hover { text-decoration: underline; }

/* ========================
   Layout
   ======================== */
main {
  max-width: 860px;
  margin: 0 auto;
  padding: 40px 40px 120px;
}

.page-header {
  margin-bottom: 56px;
}

.page-header h1 {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 8px;
}

.page-desc {
  color: #444;
  font-size: 1rem;
}

/* ========================
   Effect Cards
   ======================== */
.effect-card {
  border: 1px solid #e5e5e5;
  border-radius: 12px;
  padding: 28px 32px;
  margin-bottom: 32px;
}

.effect-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #888;
  margin-bottom: 6px;
}

.effect-title {
  font-size: 1.2rem;
  font-weight: 600;
  margin-bottom: 10px;
}

.effect-desc {
  font-size: 0.9rem;
  color: #444;
  line-height: 1.6;
  margin-bottom: 24px;
}

.effect-desc code {
  font-family: 'Menlo', 'Monaco', monospace;
  font-size: 0.85em;
  background: #f0f0f0;
  padding: 2px 5px;
  border-radius: 4px;
}

/* Demo areas */
.demo-area {
  background: #f8f8f8;
  border-radius: 8px;
  border: 1px solid #e5e5e5;
  padding: 32px 24px;
}

.demo-area--center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.demo-area--code {
  padding: 20px 24px;
}

.demo-area--code pre {
  font-family: 'Menlo', 'Monaco', monospace;
  font-size: 0.78rem;
  color: #444;
  line-height: 1.7;
  overflow-x: auto;
  white-space: pre;
}

.demo-area--code code {
  font-family: inherit;
}

.demo-area--reveal {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
}

/* ========================
   1. Pulse Circle
   ======================== */
@keyframes pulse {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.15);
    opacity: 0.7;
  }
}

.pulse-circle {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: #2563eb;
  animation: pulse 2s ease-in-out infinite;
}

.demo-label {
  font-size: 0.75rem;
  color: #888;
  font-family: 'Menlo', 'Monaco', monospace;
}

/* ========================
   3. Clip-path Reveal
   ======================== */
.reveal-wrapper {
  overflow: hidden;
  border-radius: 4px;
}

.reveal-text {
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: #111;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.reveal-text.is-revealed {
  clip-path: inset(0 0% 0 0);
}

.play-btn {
  padding: 10px 20px;
  background: #111;
  color: #fff;
  border: none;
  border-radius: 6px;
  font-size: 0.875rem;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s;
}

.play-btn:hover {
  background: #2563eb;
}

/* ========================
   4. Glass Morphism
   ======================== */
.demo-area--glass {
  background: linear-gradient(135deg, #667eea, #764ba2);
  padding: 48px 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.glass-card {
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 28px 32px;
  max-width: 320px;
  width: 100%;
}

.glass-eyebrow {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: 6px;
}

.glass-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: #fff;
  margin-bottom: 8px;
}

.glass-body {
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.85);
  line-height: 1.5;
}

/* ========================
   5. Shimmer Button
   ======================== */
@keyframes shimmer-sweep {
  from { left: -100%; }
  to   { left: 100%; }
}

.shimmer-btn {
  position: relative;
  overflow: hidden;
  padding: 14px 32px;
  background: #111;
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  font-family: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
}

.shimmer-btn::after {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 60%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.3) 50%,
    transparent 100%
  );
}

.shimmer-btn:hover::after {
  animation: shimmer-sweep 0.5s ease-in-out;
}

.shimmer-btn:hover {
  background: #2563eb;
}

/* ========================
   Mobile
   ======================== */
@media (max-width: 640px) {
  main {
    padding: 24px 20px 80px;
  }

  .effect-card {
    padding: 20px 20px;
  }
}