드롭다운 메뉴를 구현하다보니 display: none ↔ block을 왔다갔다할 때의 애니메이션이 있으면 좋겠다고 생각했다. (스르륵)
하지만 display가 none에서 block으로 변경되는 경우에는 다른 요소들과는 다르게 transition이 먹히지 않았다.
@keyframes 애니메이션 이름 {~ }
props로 조건을 줘서 isToggleOpen이 true, false로 바뀔 때마다 keyframes 값이 변경되게 하려고 했는데..
display가 none → block으로 바뀔 때는 적용이 되지만
block → none으로 바뀔 때 적용이 되지 않는다.
const CategorySelectBox = Styled.ul<{ isToggleOpen: boolean }>`
display: ${props => (props.isToggleOpen ? 'block' : 'none')};
position: absolute;
margin-top: 2em;
padding: 1em;
background-color: #fff;
border: 1px solid #EDEDED;
animation-name: slide-modal;
animation-duration: 500ms;
@keyframes slide-modal {
from {
margin-top: ${props => (props.isToggleOpen ? '0' : '2em')};
opacity: ${props => (props.isToggleOpen ? '0' : '1')};
}
to{
margin-top: ${props => (props.isToggleOpen ? '2em' : '0')};
opacity: ${props => (props.isToggleOpen ? '1' : '0')};;
}
}
`;
찾아보니 display=none
은 CSS를 통해 숨겨지는 노드이므로 브라우저의 렌더링 과정 중 렌더 트리에서 제외된다고 한다.
렌더 트리에 없는 상태에서 갑자기 display=block
으로 바뀌면서 노드가 나타나기 때문에.. transition등의 시작점이 필요한 애니메이션은 적용이 되지 않는다고 한다.
(출처: display none이 transition이 안먹히는 이유)
그래서 생각한 해결방법은 다음과 같다.
1. opacity
내가 필요한 건 display=none을 대체할 수 있는 속성이어서 visibility를 사용해서 적용해보았다. (스르륵 사라지는 효과를 위해 opacity 속성도 추가했다.)
const CategorySelectBox = Styled.ul<{ isToggleOpen: string }>`
visibility: ${props =>
props.isToggleOpen === 'open' ? 'visible' : 'hidden'};
position: absolute;
margin-top: 2em;
padding: 1em;
background-color: #fff;
border: 1px solid #EDEDED;
animation-name: ${props =>
props.isToggleOpen ? 'slide-modal-open' : 'slide-modal-close'};
animation-duration: 500ms;
@keyframes slide-modal-open {
from {
visibility: hidden;
margin-top: 0;
opacity: 0;
}
50% {
visibility:visible;
}
to{
visibility: visible;
margin-top: 2em;
opacity: 1;
}
}
@keyframes slide-modal-close {
from {
visibility: visible;
margin-top: 2em;
opacity: 1;
}
50% {
visibility:visible;
}
to{
visibility: hidden;
margin-top: 0;
opacity: 0;
}
}
`;