CSS - keyframe과 display

da.circle·2023년 2월 20일
0

드롭다운 메뉴를 구현하다보니 display: none ↔ block을 왔다갔다할 때의 애니메이션이 있으면 좋겠다고 생각했다. (스르륵)
하지만 display가 none에서 block으로 변경되는 경우에는 다른 요소들과는 다르게 transition이 먹히지 않았다.


@keyframes이란

  • @keyframes 애니메이션 이름 {~ }
  • 사용자가 애니메이션을 정의한다.
    • 시작 : 0% 또는 from
    • 끝 : 100% 또는 to
  • 중간에 원하는 부분에 애니메이션을 추가할 수 있다(% 단위로 구분)

animation-name

  • 사용자가 @keyframes을 사용해서 만든 애니메이션 이름
  • 요소와 애니메이션을 연결한다.

animation-duration

  • 애니메이션을 얼마 동안 재생할 것인지 설정한다.
  • 기본값 = 0
  • 단위 : s(초), ms(밀리초)
  • 속성 값을 지정하지 않으면 애니메이션 적용이 되지 않는다.

animation-direction

  • 애니메이션의 방향을 조절한다
  • normal : 기본값. 애니메이션을 실행하고 원래 위치로 돌아간다(0% → 100%)
  • reverse : 반대 쪽부터 애니메이션 실행한다(100% → 0%)
  • alternate : 실행이 끝나면 반대 방향으로 실행한다(0% → 100% → 0%)
  • alternate-reverse : 반대 쪽부터 시작해서 실행이 끝나면 반대 방향으로 실행한다
    (100% → 0% → 100%)

animation-iteration-count

  • 반복 횟수를 지정한다
  • 기본적으로 한 번만 실행하고 끝난다(1)
  • infinite : 무한반복

animation-time-function

  • 애니메이션의 시작, 중간, 끝에서의 속도를 선택해 전체적인 속도 곡선을 지정할 수 있다
  • linear
  • ease
  • ease-in
  • ease-out
  • ease-in-out
  • cubic-bezier(n, n, n, n)

display와 keyframe

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

  • 투명도를 조절할 수 있다.
  1. visibility

내가 필요한 건 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;
    }
  }
`;

profile
프론트엔드 개발자를 꿈꾸는 사람( •̀ ω •́ )✧

0개의 댓글