부드러운 UI 전환 마스터하기: 'Height: Auto' 해킹의 종말
Source: Dev.to
이 글에서는 CSS 개발에서 가장 짜증나는 장애물 중 하나인 동적 높이를 가진 요소를 애니메이션하는 방법을 최종적으로 해결하는 방법을 보여드리겠습니다.
웹 개발을 오래 해오셨다면, 아코디언이나 드롭다운을 애니메이션하려고 할 때 겪는 좌절감을 한 번쯤은 경험했을 겁니다. 수년간 우리는 max-height를 거대한 임의의 값으로 애니메이션하거나, 픽셀을 측정하기 위해 JavaScript 라이브러리를 도입하는 “해킹”에 의존해 왔습니다. 작동은 하지만, 저에게는 결코 “올바른 방법”처럼 느껴지지 않았습니다.
오늘은 interpolate-size 와 transition-behavior 라는 두 새로운 속성이 등장하면서, 수학적 계산과 로직을 네이티브하게 처리할 수 있게 되었습니다. 이제 이를 구현하는 과정을 단계별로 살펴보겠습니다.
“Auto” 문제란?
문제는 애니메이션 자체가 아니라 수학이었습니다. 브라우저는 0px와 500px 사이의 거리를 계산하는 데는 뛰어나지만, 전통적으로 0px와 auto 같은 키워드 사이의 중간점을 계산할 수 없었습니다.
클래스를 토글하면 브라우저는 따라갈 수 있는 숫자 경로가 없기 때문에 최종 높이로 바로 “스냅”하게 됩니다.
1. Animating Intrinsic Sizes with interpolate-size
수학을 맞추기 위해 interpolate-size를 사용합니다. 이것은 브라우저에게 “계산할 수 없는” 값을 계산하도록 허용하는 것과 같습니다.
이를 구현하는 가장 좋은 방법은 :root 레벨에 설정하는 것입니다. 상속되는 속성이므로 한 번만 활성화하면 사이트의 모든 컴포넌트에 적용됩니다.
/* root opt‑in */
:root {
/* This tells the engine to allow animations for keywords like auto or fit-content */
interpolate-size: allow-keywords;
}
.accordion-content {
height: 0;
overflow: hidden;
transition: height 0.4s ease-in-out;
}
.accordion-content.is-open {
/* Thanks to the root property, this now slides smoothly */
height: auto;
}
2. transition-behavior 로 이산 상태 처리
높이 문제를 해결했더라도 여전히 display 속성을 다루어야 합니다. 깔끔한 DOM과 접근성을 위해 요소가 숨겨질 때 보통 display: none을 사용합니다.
문제는? display는 이산적인 속성으로, 있거나 없거나입니다. 보통 토글하면 요소가 즉시 사라져서 부드러운 높이 또는 불투명도 전환이 중간에 끊깁니다.
transition-behavior: allow-discrete가 해결책입니다. 브라우저에게 전환 기간이 끝날 때까지 실제로 display 스위치를 전환하지 말라고 알려줍니다.
.dropdown {
display: none;
opacity: 0;
/* 'allow-discrete' ensures the element stays 'block' until the fade ends */
transition:
display 0.3s allow-discrete,
opacity 0.3s;
}
.dropdown.is-open {
display: block;
opacity: 1;
}
3. 실전 적용: “올바른 방법”
우리를 결합하면 성능이 뛰어나고 접근성이 보장되며 부드러운 컴포넌트를 얻을 수 있습니다. 여기서는 슬라이드와 페이드 효과가 모두 필요한 패널을 보통 어떻게 구조화하는지 보여드립니다.
전환 값을 왼쪽에서 오른쪽 순서대로 설명합니다: 먼저 속성(예: display)을 정의하고, 그 다음 지속 시간(0.5s)을 지정한 뒤, 마지막으로 동작(allow-discrete)을 지정합니다.
:root {
interpolate-size: allow-keywords;
}
.panel {
display: none;
height: 0;
opacity: 0;
overflow: hidden;
/* Walkthrough: display waits for the others, height slides, opacity fades */
transition:
display 0.5s allow-discrete,
height 0.5s,
opacity 0.5s;
}
.panel.is-active {
display: block;
height: auto;
opacity: 1;
}
4. 실제 적용 및 지원
저는 점진적 향상을 강력히 옹호합니다. 폴백이 허용 가능한 한, 100 % 지원을 기다릴 필요 없이 바로 이러한 도구들을 사용할 수 있습니다.
transition-behavior: 현재 매우 안정적이며(지원률 약 89 %). Chrome, Firefox, Safari에서 바로 사용할 수 있습니다.interpolate-size: 비교적 최신(지원률 약 71 %). Chromium 기반 브라우저에서 아름답게 동작하며, 다른 엔진도 빠르게 따라잡고 있습니다.
사용자가 오래된 브라우저를 사용하고 있더라도 레이아웃이 깨지지는 않습니다; 패널이 즉시 열리는 식으로 동작합니다. 제 경험상, 이는 더 깔끔하고 유지보수가 쉬운 CSS 작성을 위해 충분히 괜찮은 폴백입니다.
조금 더 신중하게 접근하고 싶다면, 루트 옵트‑인을 기능 쿼리로 감싸면 됩니다:
@supports (interpolate-size: allow-keywords) {
:root {
interpolate-size: allow-keywords;
}
}
이 방법을 사용하면 기존의 1000px max-height 해킹을 버리고, 우리가 의도한 대로 정확히 동작하는 코드를 작성할 수 있습니다. 다음 프로젝트에서 한 번 시도해 보세요—훨씬 더 만족스러운 빌드 방식을 경험할 수 있을 것입니다.