개발/개발일지

한 박스에서 이미지와 비디오 엘리먼트 서서히 변하게하기

pizzaYami 2024. 1. 22.

 

 

문제

마우스를 올렸을 때 화면이 서서히 변하는 걸 하고 싶다.

transition만 추가하면 될지 알았는데 생각보다 오랜 시간이 걸렸다.

 

스택

React, styeld component, typescript

 

코드 분석

관련없는 코드는 삭제하고 왼쪽화면 관련된 코드만 남겼다.

 

컴포넌트

화면에 마우스를 올리면 숫자가 1씩 증가하여 화면을 변경시키는 로직이다.

const Home = () => {
  const [leftNum, setLeftNum] = useState(0);

  const leftPlusNum = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
    setTimeout(function () {
      setLeftNum(leftNum + 1);
    }, 100);

  return (
        <LeftScreenS onMouseEnter={leftPlusNum}>
          {leftScreenData.map((imageUrl, index) => (
            <img
              src={imageUrl}
              alt='leftScreen'
            />
          ))}
          <video
            src={leftVideo}
            muted
            loop
            autoPlay
          />
        </LeftScreenS>
  );
};

 

CSS

display : none;으로 화면을 없애고 해당하는 img와 video만을 보여주고 있다.

const LeftScreenS = styled.article<{ leftNum: number }>`
  @media screen and (max-width: 768px) {
    width: 100%;
    height: 50vh;
  }
  width: 50%;
  height: 100%;
  img,
  video {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  img {
    display: ${(props) => (props.leftNum % 4 === 3 ? 'none' : null)};
  }
  video {
    display: ${(props) => (props.leftNum % 4 === 3 ? null : 'none')};
  }
`;

 

 

시도

첫 번째 시도 

css에 transition : all 1s; 를 추가하였다. 하지만 안 됐다.

 

실패 원인

css가 변화한 게 아니라 display : none;으로 아예 엘리멘트가 사라진 것으로 변화가 안 일어났다.

 

두 번째 시도

클래스를 넣어서 opacity를 추가하여 시도

const LeftScreenS = styled.article<{ leftNum: number }>`
  //.. 기존의 코드
  
  transition: opacity 1s;
  display: block;
  opacity: 1;
  .hide {
    display: none;
    opacity: 0;
  }
  
  // 아래부분은 삭제
  img {
    display: ${(props) => (props.leftNum % 4 === 3 ? 'none' : null)};
  }
  video {
    display: ${(props) => (props.leftNum % 4 === 3 ? null : 'none')};
  }
`;

 

실패 원인

hidden을 사용하면 블록을 사용하기 때문에 스크롤이 생긴다.

근본적으로 display : none을 사용하지 않아야 하는데 방법이 떠오르지 않는다.

 

 

해결

이미지와 비디오를 relative와 absolute를 사용해서 겹치게 놓고 opacity를 변경하여서 보여주었다.

<LeftScreenS onMouseEnter={leftPlusNum}>
  {leftScreenData.map((imageUrl, index) => (
    <img
      src={imageUrl}
      alt='leftScreen'
      className={leftNum % 4 === index ? 'visible' : 'hidden'}
    />
  ))}
  <video
    src={leftVideo}
    muted
    loop
    autoPlay
    className={leftNum % 4 === 3 ? 'visible' : 'hidden'}
  />
</LeftScreenS>

 

const LeftScreenS = styled.article`
  // .. 기존과 동일
  position: relative;
  overflow: hidden;
  img,
  video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transition: opacity 1s;
    object-fit: cover;
  }
  .visible {
    opacity: 1;
  }

  .hidden {
    opacity: 0;
  }
`;

 

배운 점

transition은 css의 변경사항에만 작동을 한다는 것을 알았다.

 

처음부터 요구사항을 정리를 안 하고 무작정 코드를 짜놓으니 내가 해놓은 로직이 잘 못되어 있다는 것을 깨닫는데 오래 걸렸다.

그리고 기존의 로직을 변경 안 하려는 마음이 자꾸 생겼다.

그래도 잘 이겨내서 로직도 정말 변경하고 내가 원하는 화면도 구현을 해서 좋았다. 

 

댓글