CSS 유틸리티

[@starting-style] 순수 CSS로 나타나고 사라지는 등장/퇴장 애니메이션

@starting-style 와 transition-behavior: allow-discrete 한 묶음이면 display:none에서 나타나거나 사라지는 요소도 라이브러리 없이 부드럽게 움직여요. React는 boolean 하나만 뒤집어요.

@starting-styletransition-behaviorallow-discreteCSS transitionstransitionend@supports
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

한 줄 요약 - @starting-style(요소가 처음 나타나는 순간의 시작 값을 정하는 규칙)과 transition-behavior: allow-discrete(display처럼 원래 전환이 안 되던 속성도 전환되게 허용)를 함께 쓰면, 토스트나 작은 패널이 나타나고 사라지는 모션을 순수 CSS만으로 만들 수 있어요.

이럴 때 필요해요

알림 토스트나 모달을 부드럽게 띄우고 닫고 싶을 때, 보통은 애니메이션 라이브러리를 깔거나 setTimeout으로 클래스를 붙였다 떼는 코드를 직접 짭니다. 특히 사라질 때가 골치인데, 요소를 곧바로 display:none 하거나 언마운트하면 퇴장 모션이 잘려서 그냥 뚝 없어져요. 이 두 CSS 기능이 그 보일러플레이트를 대신해 줍니다.

어떻게 동작하나

  1. 토스트가 평소 머무는 도착 값(opacity:1, 제자리)을 정하고, transition에 opacity/transform과 함께 display까지 allow-discrete로 넣어 둡니다.

  2. @starting-style 안에 '처음 나타나는 순간의 값'(opacity:0, 살짝 아래+축소)을 적어두면, DOM에 붙는 즉시 시작 값에서 도착 값으로 CSS가 알아서 등장시켜요.

  3. 닫을 때는 leave 클래스를 붙여 퇴장 transition을 시작하고, transitionend 신호를 받은 뒤에야 실제로 언마운트합니다. 그래서 사라지는 모션도 끝까지 보여요.

핵심은 이거예요

JavaScript는 'boolean을 뒤집어 요소를 보이고 숨길지'만 결정하고, fade/slide/scale 같은 움직임은 전부 CSS가 만듭니다. @starting-style이 '등장 시작점'을, allow-discrete가 '사라질 때도 끊기지 않게'를 담당한다는 한 쌍만 기억하면 됩니다.

놓치기 쉬운 것

  • @starting-style 없이 transition만 주면 등장 모션이 안 보입니다. 브라우저가 시작 값을 모른 채 바로 도착 값으로 켜버리기 때문이에요.

  • allow-discrete가 없으면 사라질 때 display:none이 곧바로 적용돼 퇴장 모션이 잘립니다. 그리고 언마운트는 transitionend를 기다린 뒤에 해야 모션이 끝까지 재생돼요.

  • 미지원 브라우저에서는 모션 없이 즉시 나타났다 사라질 뿐 기능은 정상이라, @supports로 감지해 안내만 두면 됩니다.

이런 곳에 써요

  • 저장 완료/메일 전송 같은 토스트 알림이 쌓이고 사라지는 화면

  • 모달/팝오버/드롭다운처럼 떴다 닫히는 작은 패널의 등장과 퇴장

소스 코드

· 데모 페이지에서 자동 추출
import type { Metadata } from "next";
import { StartingStyleDemo } from "./-components/StartingStyleDemo";

export const metadata: Metadata = {
  title: "CSS @starting-style (데모)",
  description:
    "@starting-style + transition-behavior: allow-discrete 한 묶음이면 display:none에서 나타나거나 사라지는 요소도 순수 CSS로 부드럽게 등장/퇴장시킬 수 있습니다. Framer Motion 없이 React는 boolean 하나만 뒤집어요.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return (
    <main className="flex min-h-[100dvh] items-center justify-center bg-white">
      <StartingStyleDemo />
    </main>
  );
}
53조회수

댓글