현재 개발중인 웹의 레이아웃에 사이드바가 있다. 이 사이드바는 반응형으로 넓은 화면에서만 렌더링 하고 있으며, 사이드바 우측의 버튼을 클릭할때마다 사이드바를 부드럽게 열고 닫기 위해 keyframes를 이용해 애니메이션 처리 하고 있는 상황이었다.
코드를 살펴보자.
Sidebar.tsx
interface IProps {
isSidebarOpen: boolean | null;
setIsSidebarOpen: Dispatch<SetStateAction<boolean | null>>;
}
function Sidebar({ isSidebarOpen, setIsSidebarOpen }: IProps): JSX.Element {
const closeButtonClass = `${styles.closeButton} ${
isSidebarOpen || isSidebarOpen === null ? styles.open : styles.close
}`;
const openButtonClass = `${styles.openButton} ${
isSidebarOpen || isSidebarOpen === null ? styles.open : styles.close
}`;
const sidebarClass = `${styles.container} ${
isSidebarOpen ? styles.open : styles.close
}`;
return (
<nav className={sidebarClass}>
<LeftOutlined
className={closeButtonClass}
onClick={() => {
setIsSidebarOpen(() => false);
}}
/>
<RightOutlined
className={openButtonClass}
onClick={() => {
setIsSidebarOpen(() => true);
}}
/>
</nav>
);
}
export default Sidebar;
상위 컴포넌트로부터 props로 내려받은 isSidebarOpen 상태를 이용하여 class를 동적으로 할당하고 있는 상황이다.
Sidebar.module.scss
@import "/src/styles/breakpoints";
@import "/src/styles/mixins";
@keyframes openSidebar {
0% {
min-width: 0;
}
100% {
min-width: 28rem;
}
}
@keyframes closeSidebar {
0% {
min-width: 28rem;
}
100% {
min-width: 0;
}
}
.container {
position: relative;
display: none;
&.close {
animation: closeSidebar 0.3s ease forwards;
}
&.open {
animation: openSidebar 0.3s ease forwards;
}
@include respond-above("md") {
display: block;
min-width: 28rem;
background-color: #001529;
}
... 생략
}
keyframes를 이용하여 상태가 변함에 따라 애니메이션을 주고 있다.
작은 화면에서는 사이드바가 보이지 않고, 큰 화면에서는 버튼을 통해 사이드바를 열고 닫을 수 있다. 하지만, 작은 화면에서 큰 화면으로 전환할 때, 미디어 쿼리의 변경에 따라 애니메이션이 불필요하게 트리거되는 문제가 발생했다. 내가 원하는 것은 버튼을 클릭 할 때에만 애니메이션이 활성화되는 것이었다.
문제의 원인은 미디어 쿼리와 CSS 애니메이션 간의 상호작용에 있었다. 화면 크기가 변경될 때, .container 요소에 적용되는 스타일이 미디어 쿼리에 의해 변경되었고, 이로 인해 정의된 @keyframes 애니메이션이 트리거되었던 것이다.
생각보다 간단하게 해결할 수 있었다. CSS transition 속성을 사용하는 방법을 시도했다. transition은 요소의 특정 속성(여기서는 min-width)의 변화에 시간에 따른 부드러운 전환 효과를 적용한다. 이 방식으로, 화면 크기가 변경되어도 불필요한 애니메이션이 트리거되지 않게 되었다.
Sidebar.module.scss
@import "/src/styles/breakpoints";
@import "/src/styles/mixins";
// keyframes 애니메이션 제거!
.container {
position: relative;
display: none;
// min-width 속성에 지연효과 추가
transition: min-width 0.3s ease;
&.open {
// 직접 min-width 변경
min-width: 28rem;
}
&.close {
// 직접 min-width 변경
min-width: 0;
}
@include respond-above("md") {
display: block;
min-width: 28rem;
background-color: #001529;
}
...생략
}
이 사례는 CSS transition 속성을 활용함으로써, 화면 크기 변화에 따른 불필요한 애니메이션 트리거를 효과적으로 방지할 수 있음을 보여준다. 이로 인해 더 나은 UX를 제공하고, 브라우저 환경에서의 예측 가능한 UI 동작을 보장하는 방법을 제시할 수 있었다.