display:none, visibility: hidden 트랜지션 속성 적용이 안되는 이유

JH.P·2024년 7월 5일

문제 현상

  • 중앙에 렌더링되는 모달이 사라졌다가 나타나는게 딱딱하다고 느껴져서, 트랜지션 속성을 통해 부드럽게 렌더링하려고 시도하였다.
  • 조건부 렌더링에 따라 useState의 상태에 따라 'flex'와 'none'을 조건으로 transition을 주었는데, 적용이 되지 않았다.

원인

  • 원인은 브라우저의 Render tree에 있었다.
  • Render tree는 DOM과 CSSOM을 종합하여 화면에 렌더링 될 요소들을 결정하며, 보이지 않아도 되는 요소들(meta, script 등)은 렌더링하지 않는다.
  • 이떄, 일부 노드도 CSS를 통해 렌더링되지 않게 되는데, display:none이 이 경우에 포함된다.
  • display: none은 요소가 보이지 않는 것 뿐만 아니라, 레이아웃에서도 제외되기 때문에 Render tree에서 사라진다.
  • 결론적으로, Transition 속성은 Render tree 내 존재하는 요소의 변화 과정에 적용하는 속성이지만, display: none은 Render tree 내에 존재하지 않기 때문에 제대로 동작하지 않는 것이다.

해결

  • 따라서 display의 값에 따라 transition을 주는 방법 말고, 노드가 display:flex로 변경되어 Render tree 내 생성된 후, animation 속성을 부여하여 해결하였다.

스타일 코드

const Container = styled.div<{ display: string }>`
  display: ${(props) => props.display || "none"};
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.6);
  z-index: 1000; /* 다른 요소들보다 위에 위치하도록 설정 */
`;

const ModalBackground = styled.div`
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
`;

const ModalWindow = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;

  position: relative;
  margin-bottom: 350px;
  border-radius: 10px;
  background: ${(props) => props.theme.modalBgColor};
  padding: 40px 30px 30px 30px;
  animation: modaldown 0.3s linear;
  z-index: 1001; /* 모달 배경이 컨테이너 뒤에 위치하도록 설정 */

  @keyframes modaldown {
    from {
      transform: translateY(-10%);
      opacity: 0;
    }
    to {
      transform: translateY(0);
      opacity: 1;
    }
  }

JSX

const CenterModal = ({
  display,
  controlFunc,
  children,
}: {
  display: string;
  controlFunc: () => void;
  children: React.ReactNode;
}) => {
  return (
    <Style.Container display={display}>
      <Style.ModalBackground onClick={controlFunc} />
      <Style.ModalWindow>
        <p className="close" onClick={controlFunc}>
          &times;
        </p>
        {children}
      </Style.ModalWindow>
    </Style.Container>
  );
};

Vibility: hidden 트랜지션 적용

  • 위에 언급했던 문제를 해결하기 위해 시도했던 방법이다.
  • 이 경우에는 transition의 delay만 적용되었다.
  • transition 속성은 opacity와 같이 수치로 나타낼 수 있는 속성에만 적용이 가능하기 때문에 발생한 현상이였다.
// delay만 적용
visibility: ${(props) => (props.isVisible? 'visible' : 'hidden')};
transition: visibility 5s ease-in-out 1s;
// 정상 적용
opacity: ${(props) => (props.isCreated ? 1 : 0)};
transition: opacity 1s ease-in-out;
profile
꾸준한 기록

0개의 댓글