개발 마라톤

9/20 - 부모보다 큰 자식 나열하기 본문

--- Project ---/CharFlyer : 캐플라이어

9/20 - 부모보다 큰 자식 나열하기

망__고 2023. 9. 20. 17:37

BannerSection 애니메이션

이번 애니메이션을 구현하면서 이슈가 존재했다.

자식이 부모보다 커지지 못하는 이슈

어찌보면 당연하게 생각했던 내용일 수도 있겠다.

자식은 크기를 기본적으로 부모에게 상속받으며, 자식은 부모 컨테이너 내에서 존재하는 것이 기본적인 설계이다.

브라우저 렌더링 순서와 원리 (velog.io)

 

브라우저 렌더링 순서와 원리

사전지식 1. 🖥 브라우저? 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것 이때 자원은 HTML문서, PDF, 이미지 등 다양한 형태를 띌 수 있음 자원의 주소는 URL(Uniform Resource Identifi

velog.io

각 요소의 정확한 생성 방식은 찾아보지 못했지만, 생성되는 DOM 트리를 보면 어느정도 내용을 유추 가능할 것 같다.

출처 : 브라우저 렌더링 순서와 원리 (velog.io)

어디까지나 유추의 내용이니 나중에 정확한 문서를 찾아보는 것이 좋을 것이다.

 

브라우저는 화면을 어떻게 렌더링 하는지 살펴보면,

HTML을 통해 DOM트리를 성생하고 CSS를 통해 각 요소 별 CSSOM을 생성한다.

DOM 트리, CSSOM 트리를 통해 Render Tree를 생성하고,

이후 레이아웃 배치와 페인트를 통해 화면을 출력하게된다.

 

이 작업 중에 자식요소는 필연적으로 부모요소의 하위에 있도록 생성되며, 부모의 CSS 속성을 상속받는다.

또한, 이것이 최초 설계자의 의도일지는 모르겠지만, 따라서 자식 요소는 부모 요소의 내부에 존재하게 된다.

 

결론 ) DOM 트리 생성 방식 때문에 자식은 부모보다 커지지 못하는 것이라고 추측한다.

 

추가적으로는

자식 요소의 페인팅 크기가 커지면 부모요소를 넘어버리는 듯한 현상도 존재하는데 이를 overflow 현상이라고 한다.

이는 CSS의 overflow 속성을 통해 해당 페인팅을 숨기거나, 스크롤로 확인할 수 있도록 조치해줄 수 있다.

본격적인 애니메이팅

애니메이팅을 하기 위해 이번 컴포넌트가 어떻게 작동하는지 다시 짚어보도록 하겠다.

[개발] 9/19 이슈 정리 (tistory.com)

 

[개발] 9/19 이슈 정리

bannerSection 컴포넌트 설계 bannerSection은 어떻게 보면 디자인적인 부분의 한 요소일 뿐이지만, 이 프로젝트를 하면서 나의 큰 관심사 중 하나였다. 구상은 비행기 이미지에 섬네일 사진만을 결합하

lee-ju-0.tistory.com

중요한 요소는 다음과 같다.

 

  1. page.tsx 의 server component 에서 props를 통해 api 내용 20개를 전달받는다.
  2. 해당 내용이 20개를 넘지 못한다면, 내용을 반복해서라도 내용을 20개 가지는 배열을 만든다.
  3. 해당 배열의 map() 함수를 통해 `비행기`로 보이는 구성요소를 생성한다.
  4. 즉, 한 BannerList.tsx 컴포넌트는 최종적으로 20개의 비행기를 가지는 컴포넌트이다.
  5. 추가적으로, 비행기 방향으로 흐르고, 루프되는 애니메이션을 구현한다.

 

해당 내용을 구현할 것이며 1번의 내용은 전에 구현하였고, 윗 글에 정리되어 있다.

2, 3, 4 번의 내용 또한 1번의 내용을 통해 적용시켰고, 이번 구현의 중점은 애니메이션이다.

 

React - 무한 롤링 슬라이드(배너) 구현하기 :: 개발 흔적 남기기 (tistory.com)

 

React - 무한 롤링 슬라이드(배너) 구현하기

🎞️ 롤링 슬라이드 주식이나 뉴스같은 곳에서 한줄로 끊임없이 텍스트가 물처럼 한방향으로 흐르거나 요즘 트렌드의 스타일로 작성된 사이트들을 구경하다 보면 자주 접할 수 있는 스타일의

myhappyman.tistory.com

[CSS] CSS 애니메이션으로 상하 무한 슬라이드 구현 (velog.io)

 

[CSS] CSS 애니메이션으로 상하 무한 슬라이드 구현

외부 라이브러리를 사용하지 않고 상하로 움직이는 무한 슬라이드를 구현슬라이드가 진행하며 동일한 슬라이드가 한 화면에 위와 아래 동시에 보여지는 경우가 있으므로, 슬라이드를 2개씩 생

velog.io

윗 글을 참고하여 구현하도록 하였다.

 

첫 번째 글을 그대로 따라해보도록 하였고, 아래는 작업한 순서를 정리해보았다.

1. 무한 루프를 구현하기 위해 똑같은 내용 리스트를 가지는 요소를 original, clone으로 두 가지를 만든다.

enum AirplaneListTypes {
    Original = 'ORIGIN',
    Clone = 'CLONE',
  }

  // 원본, 복사본
  const AirplaineList = ({ listType }: { listType: AirplaneListTypes }) => {
    const listClasses = [
      styles.airplanList,
      stop ? styles.stop : '',
      listType == AirplaneListTypes.Original ? styles.original : styles.clone,
    ].join(' ');
    
...

  return (
    <div className={styles.listWrap}>
      <AirplaineList listType={AirplaneListTypes.Original} />
      <AirplaineList listType={AirplaneListTypes.Clone} />
    </div>
  );

enum을 통해 Original, Clone을 지정할 수 있도록 정리하였고,

해당 enum을 받는 props listType을 판별하여 styles.original, styles.clone 둘 중에 하나의 클래스를 가지도록 하였다.

 

2. original 리스트와 clone 리스트가 옆으로 이어지도록 한다.

.listWrap {
  position: relative;
  display: flex;

  .airplanList {
    white-space: nowrap;

    &.original {
      background-color: aqua;
    }
    &.clone {
      background-color: deeppink;
    }
    
    ...
    
}

display : flex; 를 통해 두 요소를 옆으로 이어지게 하고 싶었다.

이때 위에서 언급한 이슈가 발생하였다.

부모 크기만큼만 자식 크기를 가지는 문제

위의 CSS 내용과 같이, original 리스트는 aqua 색을, clone 리스트는 deeppink 색을 가지도록 작성해보았다.

하지만 두 요소는 윗 사진에서 확인할 수 있듯이,

쭉 이어지는 비행기 즉, 자식 요소로 페인팅된 내용과는 다르게, 부모 요소 만큼의 크기만 가지도록 결정되었다.

 

해당 이슈 때문에 두 자식을 나란히 정렬할 수 없었고,

나란히 따라오는 내용을 통해 무한 루프를 구현하려던 내용에 차질이 생겼었다.

이슈 해결 방법

부모의 크기와 관계 없이, 또한 지정된 레이아웃과 관계 없이 위치를 조절할 수 있는

position: absolute;

 

속성을 통해 해결하였다.

정확한 해결 방법은 다음과 같다.

@use '@/app/styles/themes.scss' as themes;

// 비행기 개수, 비율
$airplaneAmount: 20;
$airplaneRatioInWrap: 4;

.listWrap {
  position: relative;
  display: flex;
  overflow: hidden;

  .airplanList {
    white-space: nowrap;

    &.original {
      animation: 10s linear infinite normal none running originalSlide;
      background-color: aqua;
    }
    &.clone {
      position: absolute;
      left: themes.$maxWidth / $airplaneRatioInWrap * ($airplaneAmount);
      animation: 10s linear infinite normal none running cloneSlide;
      background-color: deeppink;
    }
    &.stop {
    }

    .airplane {
      display: inline-block;
      position: relative;
      box-sizing: border-box;
      width: themes.$maxWidth / $airplaneRatioInWrap;

      .airplaneImage {
      }
    }
  }
}

@keyframes originalSlide {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(
      -1 * themes.$maxWidth / $airplaneRatioInWrap * ($airplaneAmount)
    );
  }
  50.1% {
    transform: translateX(
      themes.$maxWidth / $airplaneRatioInWrap * ($airplaneAmount)
    );
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes cloneSlide {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(
      -2 * themes.$maxWidth / $airplaneRatioInWrap * ($airplaneAmount)
    );
  }
}

핵심이 되는 내용만 언급해보겠다.

1. 변수 airplaneAmount와 airplaneRatioInWrap을 정의하여 계산에 활용할 수 있도록 한다.

2. 부모요소 listWrap의 position : relative를 통해 absolute인 자식 요소를 자신 기준으로 조정할 수 있도록한다.

3. 의도대로 위치하지 못한 clone을 position : absolute 를 통해 레이아웃 상관 없이 위치할 수 있도록 한다.

4. clone의 left를 1번에서 정의한 변수를 통해 original 요소의 옆으로 올 수 있도록 left 속성을 작성한다.

결과

clone의 위치를 position: absolute를 통해 조정시켜, 의도한 위치에 놓을 수 있었다.

Comments