모달 페이드인이 열릴 때만 동작하지 않은 이유
문제 발생
모달을 열 때 페이드인을 넣었는데, 열릴 때는 애니메이션이 없고 닫힐 때는 아예 즉시 사라졌습니다.
.modal {
display: none;
opacity: 0;
transition: opacity 0.3s;
}
.modal.open {
display: block;
opacity: 1;
}display를 바꾸는 순간 트랜지션이 통째로 무시됐습니다.
원인 분석
두 가지가 겹쳐 있습니다.
첫째, 첫 스타일 갱신에는 트랜지션이 걸리지 않습니다. MDN의 설명 그대로 — 예기치 않은 동작을 피하기 위해, CSS 트랜지션은 요소의 최초 스타일 갱신이나 display가 none에서 다른 값으로 바뀔 때 기본적으로 발동하지 않습니다. 요소가 방금 display: block이 된 순간에는 "이전 상태"가 없으므로 보간할 대상이 없는 셈입니다.
둘째, display는 이산(discrete) 속성입니다. 중간값이 없어서 원래 트랜지션 대상이 아닙니다. 그래서 닫힐 때도 display: none이 즉시 적용되어 페이드아웃할 시간이 없습니다.
각각에 대응하는 도구가 있습니다. 앞은 @starting-style, 뒤는 transition-behavior: allow-discrete입니다.
해결 방안
- 시작 상태를
@starting-style로 선언합니다.
.modal {
display: none;
opacity: 0;
transition:
opacity 0.3s,
display 0.3s allow-discrete;
}
.modal.open {
display: block;
opacity: 1;
}
/* 진입 애니메이션의 시작값 */
@starting-style {
.modal.open {
opacity: 0;
}
}-
위치가 중요합니다. MDN이 명시합니다 —
@starting-style규칙과 원래 규칙은 명시도가 같습니다. 그래서 시작 스타일이 이기려면 원래 규칙 뒤에 두어야 합니다. 앞에 두면 원래 스타일이 덮어씁니다. -
display와overlay에는allow-discrete가 필요합니다.display는 애니메이션이 끝날 때까지 요소를 보이게 유지하고,overlay는 최상위 레이어(top layer)에서 제거되는 시점을 애니메이션 종료까지 미룹니다.
[popover] {
opacity: 0;
transition:
opacity 0.4s,
display 0.4s allow-discrete,
overlay 0.4s allow-discrete;
}
[popover]:popover-open { opacity: 1; }
@starting-style {
[popover]:popover-open { opacity: 0; }
}-
<dialog>와 popover에 특히 필요합니다. MDN이 이유를 적어 둡니다 — 보일 때 최상위 레이어로 올라가고 숨을 때display: none과 함께 거기서 빠지기 때문에, 양방향 모두 동작하게 하려면 추가 단계가 필요합니다. -
새로 DOM에 추가되는 요소에도 같은 문제가 있습니다. 목록에 항목을 추가할 때 진입 애니메이션이 안 걸리는 것도 같은 원인입니다.
-
prefers-reduced-motion을 존중합니다. 진입·퇴장 애니메이션은 특히 어지러움을 유발하기 쉽습니다.
@media (prefers-reduced-motion: reduce) {
.modal { transition-duration: 0.01ms; }
}
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.