saewoo
githubemail
2022-12-17

가로 스크롤 아이템 가운데 정렬시키기

디테일은 어려워

가로로 스크롤 되는 영역에서 item 클릭시 화면의 가운데 정렬될 수 있도록

clientWidth, offsetLeft, scrollTo를 활용하여 구현해 보겠습니다.

align-target

계획: 어떻게 할 수 있을까?

align-plueprint

클릭한 element를 가운데 정렬하는 방법은 D값을 구하는것이 핵심일 것 같습니다.

D값을 구했다면

element.scrollLeft 프로퍼티를 사용하거나,

$container.scrollLeft = D;

element.scrollTo 메서드를 사용하여 스크롤을 이동시키면 됩니다.

$container.scrollTo({
  left: D
  behavior: "smooth"
});

구현

HTML과 CSS는 아래와 같습니다.

<style>
  .container {
    position: relative;
    overflow-x: scroll; 

    display: flex;
    gap: 20px;

    margin-top: 200px;
    padding: 20px;

    background-color: blue;
  }
  .item {
    padding: 0 50px; 
    background-color: orange;
  }
</style>
<body>
  <div class="container">
    <div class="item">item1</div>
    <div class="item">item2</div>
    <div class="item">item3</div>
    <div class="item">item4</div>
    <div class="item">item5</div>
  </div>
</body>

JS 코드는 다음과 같습니다.

const moveToCenter = (e) => {
  // React라면 스크롤되는 컨테이너에 useRef 훅을 사용한다.
  const $container = document.querySelector('.container');

  const A = $container.clientWidth; 
  const B = A / 2; 
  const C = e.target.offsetLeft 
  const D = C - B; 

  // $container.scrollLeft = D도 가능합니다.
  $container.scrollTo({
    left: D,
    behavior: "smooth"
  });
}
document
  .querySelectorAll('.item')
  .forEach(el => el.addEventListener('click',moveToCenter));

align-plueprint

D값을 구하고 스크롤을 이동시켰지만, 가운데 정렬이 덜 된 느낌입니다. 😅

'item3' 글자가 가운데로 가야 더 자연스러울 것 같습니다.

그러기 위해선 container에서 준 gap과 item에서 준 padding 길이만큼 추가로 스크롤 시키겠습니다.

const moveToCenter = (e) => {
  // React라면 스크롤되는 컨테이너에 useRef 훅을 사용한다.
  const $container = document.querySelector('.container');

  const A = $container.clientWidth; 
  const B = A / 2; 
  const C = e.target.offsetLeft 
  const D = C - B; 

  const GAP = 10;
  const PADDING = 50;

  // $container.scrollLeft = D도 가능합니다.
  $container.scrollTo({
    left: D + GAP + PADDING,
    behavior: "smooth"
  });
}
document
  .querySelectorAll('.item')
  .forEach(el => el.addEventListener('click',moveToCenter));

한결 자연스러운것 같습니다. 😄

align-plueprint

참조