스크롤이 쏘아올린 작은 공

스크롤이 쏘아올린 작은 공

작성자 hectodata

안녕하세요. 서비스 개발팀 Somi 입니다. 🐥

오늘은 저희 헥토데이터 최초의 마이데이터 기반 자산관리 서비스인 핀퐁 finpong 웹 프로젝트 작업 중 메인화면에서 발생한 스크롤 오류와 오류 해결 과정에 대해 살펴보려고 합니다.

😱 스크롤 오류

1. scroll-snap 속성과의 첫만남

💡
“ 라이브러리 없이 css 속성만으로 간단하게 스와이프 애니메이션을 구현할 수 있다니 혁명이다! ”
스와이프없이 간단하게 스와이프 효과내기
  • scroll-snap-type: x mandatory;
  • scroll-snap-align: start;

🎨 스크롤을 부드럽게 - Scroll Snap 속성

//=== 사용예시 ===//
/* 부모 컨테이너에 scroll-snap 속성 적용 */
.container {
  overflow-x: scroll;
  scroll-snap-type: x mandatory; /* x축 방향으로 스크롤 스냅 적용 */
}

/* 각 스냅 지점의 스크롤 포인트 지정 */
.item {
  scroll-snap-align: start; /* 스냅 지점의 정렬을 시작 지점에 맞춤 */
}
다양한 속성 활용해보기
<SubHeader v-if="isMobile"></SubHeader>
<Header v-if="!isMobile" :scrollColor="scrollColor"></Header>
<div id="main" class="main-page">
	<div class="scroll-wrapper" ref="scrollEl">
		<Section1 />
		<Section2 />
		<Section3 />
		<Section4 />
		<Section5 />
		<Section6 />
		<Section7 />
	</div>
</div>
스와이프없이 간단하게 스와이프 효과내기
.main-page {
	position: relative;
	.scroll-wrapper {
		overflow-y: scroll;
		height: 100vh;
		scroll-behavior: smooth;
		scroll-snap-type: y mandatory;
		section {
			position: relative;
			width: 100%;
			scroll-snap-align: start;
			scroll-snap-stop: always;
			&.section6 {
				display: flex;
				align-items: center;
				justify-content: center;
				padding: 138px 0 138px;
				**scroll-margin-top: 56px;**
		}
	}
}

원페이지 작업할때 헤더 영역만큼이 fixed 여서 색이 있는 영역은 잘린것처럼 보일때가 있었는데 scroll-margin-top으로 간단하게 해결! 웬만한 스와이프 슬라이드 기능은 다 구현할 수 있어서 굳이 라이브러리 안쓰고 css로만 사용이 가능해서 편리합니다.

참고 URL : https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top


기쁜마음으로 정보를 공유하고자 정리하여 팀원들에게도 scroll-snap 공유했었는데요.

물론 정말 간단한 스와이프 기능은 이 속성만으로도 충분합니다. 가볍게 구현이 가능하므로 오히려 효율적이죠.

하지만 크롬 브라우저 스크롤 이슈라는 크리티컬한 문제가 있었어요.

2. 메인화면 scroll-snap 적용하기

2.1 메인에서 필요했던 애니메이션

  • 원페이지 스크롤
  • 원하는 스크롤 위치로 포커싱
  • 특정위치 일반 스크롤

2.2 scroll-snap 으로 원페이지 스크롤 구현

.main-page {
  position: relative;
  .scroll-wrapper {
    overflow-y: scroll;
    max-height: 100vh;
    scroll-behavior: smooth;
    scroll-snap-type: y mandatory;
    -ms-scroll-snap-destination: 0 0;
    scroll-snap-destination: 0 0;
    section {
      position: relative;
      width: 100%;
      scroll-snap-align: start;
      scroll-snap-stop: always;
      scroll-behavior: smooth;
    }
}

⇒ 문의하기 영역이 펼쳐지면 스크롤, 닫혀있으면 스와이프 휠 모션을 구현했어야 했는데 아무래도 스크롤 속성으로 스와이프 모션 느낌을 내는거여서 스크롤 + 휠 느낌을 자연스럽게 접목시킬 수 있었습니다.

단 몇줄만으로 swiper 기능이 구현된 것입니다. 하! 지! 만!

2.3 문제점

원페이지 스크롤 , 원하는 스크롤 위치로 포커싱

이 모든것이 완벽하게 동작했다면 scroll-snap은 좋았겠지만…

이 애니메이션은 매직마우스에서만 제대로 동작하였고 휠이 있는 마우스에서는 원페이지가 스크롤이

스무스하게 동작하지 않고 버벅거리면서 일반 스크롤조차 되지 않는다는 것을 확인했습니다.

근데 알고보니 크롬에서의 scroll-snap 동작에 버그가 있던 것!

많은 개발자들이 이를 수정하려고 노력하였으나 해당 버그는 난제로 남은 것 같습니다…

왜 많은 사람들이 편한 이 속성을 멀리하고 라이브러리를 사용하는지 깨닫게 되었던 순간이었어요.

휠이 있는 마우스에서 스크롤이 스무스하지 않고 버벅거리며 스크롤이 잘 되지 않는 경우입니다.

저와 같이 scroll-snap 에러로 인해 이 속성을 멀리하게 된 분들의 이야기 입니다…

[CSS] scroll-snap이 이상해요

CSS Scroll snap으로 fullpage.js를 대체하고 싶었다

2.4 scroll-snap를 사용하고 싶어서 해결하려고 했던 시도

  • 키보드 방향키로는 잘 동작해서 방향키를 누른 효과를 적용
  const scrollDirection = getScrollDirection(e);
  const simulateKeyDown = keyValue => {
  const event = new KeyboardEvent('keydown', { key: keyValue });
		document.dispatchEvent(event);
  };
  console.log(scrollDirection);
  
  if (scrollDirection === 'up') {
		 // 스크롤이 위로 올라갔을 때의 처리: 방향키 위를 누름
	   console.log('up');
	   simulateKeyDown('ArrowUp');
  } else if (scrollDirection === 'down') {
     // 스크롤이 아래로 내려갔을 때의 처리: 방향키 아래를 누름
     console.log('down');
     simulateKeyDown('ArrowDown');
  }
};

 const getScrollDirection = e => {
    // 스크롤 방향을 확인하는 함수
 const currentScroll = e.target.scrollTop;
 const direction = currentScroll > lastScroll.value ? 'down' : 'up';
	  lastScroll.value = currentScroll; // 변수를 업데이트
		return direction;
};

3. 결국엔 swiper 로 돌아오다…

swiper를 사용했을 때도 문제가 첫번째 섹션에서 문의하기가 펼쳐졌을 때 일반 스크롤 + 휠을 함께 사용하려다보니 모션 자체가 굉장히 어색하고 자연스럽게 구현되지 않았습니다. 여러가지 방법을 적용해보다가 결국에는 문의하기를 펼쳤을 때도 마우스휠 이벤트로 원페이지 스크롤처럼 변경했습니다. 이후에라도 크롬 브라우저에서 지원한다던지 더 좋은 개선 방법이 있다면 적용하고 알려드리도록 하겠습니다.

4. 결론

scroll-snap은 간단한 스와이퍼 기능이나 효과를 내고 싶다면 사용하기 좋은 css 속성이다! 하지만 다양한 효과가 들어가야 한다거나 큰 모션의 경우는 잘 되어 있는 라이브러리를 쓰자! 언젠간 이런 버그들이 해결된다면 아주 유용한 속성이 될 것이다!!! 라는 결론을 내리게 되었습니다.

😲 콘텐츠 떨림 현상

검정색 부분 영역이 넓어질때 드드득 하며 커지게 되고 가운데 글자들이 미세하게 떨리는 경우입니다.

1. 문제

메인이 렌더링되고 section1에 검은 상자가 풀화면으로 채워지는 애니메이션을 적용했음 → 검은화면으로 채워지면서 가운데 콘텐츠 요소들이 떨리는 현상이 생김

2. 원인

  • 리플로우(reflow) : 생성된 DOM 노드의 레이아웃 변경시 레이아웃 트리(렌더 트리)를 재생성하는 작업 (수치가 변경될 때!)
  • 발생하게 하는 속성: width, height, padding, margin, float, position 등등 레이아웃에 영향을 주는 모든 속성
  • 리페인트(repaint) : reflow 과정이 끝나고 재생성된 레이아웃 트리(렌더 트리)를 다시 레이어에 그리는 작업 (시각적인 요소가 변경할 때)
  • 발생하게 하는 속성
  • color, border-radius, background, box-shadow 등등 시각적으로 보여지는 모든 속성
  • 레이아웃에 영향을 주는 것은 아니지만, 시각적 요소가 바뀔 경우

⇒ width와 height가 애니메이션에 따라 100%로 채워지면서 변화를 감지하여 재조정하면서 화면에 그리게 되는데 이때 영역이 크다보니 눈에 띄게 떨림 현상이 발생했던 것입니다.

3. 오류 해결을 위한 시도

⇒ 타이머 함수인 setInterval() 와setTimeout() 의 문제점은 주어진 시간내에 동작을 할 뿐 프레임을 신경 쓰지 않고 동작한다는 점입니다. 타이머 함수는 프레임 단위로 프레임 시작 시간에 맞춰 실행됨을 보장하지 못하기 때문입니다.

requestAnimationFrame 함수는 시스템이 프레임을 그릴 준비가 되면 애니메이션 프레임을 호출하여 애니메이션 웹페이지를 보다 원활하고 효율적으로 생성할 수 있도록 해줍니다. 실제 화면이 갱신되어 표시되는 주기에 따라 함수를 호출해주기 때문에 자바스크립트가프레임 시작 시 실행되도록 보장해주어 위와 같은 밀림 현상을 방지해줍니다.

requestAnimationFrame(실행할 애니메이션 함수)
function updateScreen(time) {
  	// 요 함수에서 애니메이션이 수행됨!
}

requestAnimationFream(updateScreen);

⇒  구현되는 방식이 다르므로 결과적으로는 실패! 하지만 화면에서 계속 애니메이션이 일어나야 하는 경우 잘 알고 사용하면 버벅임없이 부드럽게 구현되기 때문에 유용할 듯합니다.

4. 해결방법

떨림 현상을 방지하기 위해 콘텐츠가 있는 영역 자체를 확장시키지 않고 뒤에 따로 만든 div 요소의 배경을 확장시켰습니다.

<div class="con-wrapper">
	<div class="con-box"> // 기존에 확장시켰던 요소는 가만 두고
		<div class="text-wrapper">
			<div class="left-box">
				<h3>소중한 마이데이터 헥토데이터 핀퐁에서</h3>
				<h4>쉽고 빠르게 안전하게</h4>
			</div>
			<div class="right-box">
				...
			</div>
		</div>
	</div>
	<div class="bg-box"> // 배경만 컨트롤 할 수 있는 div를 만들어 확장시킴
		<div class="bg-mask">
			<img class="bg" src="/assets/images/main/symbol_finpong.png" alt="" />
		</div>
	</div>
</div>

5. 결론

그동안에도 레이아웃을 변경시키는 css 속성을 자주 사용하지만 브라우저 렌더링에 직접적인 영향을 주는 것은 발견하지 못했습니다. 하지만 이번에는 변경되는 영역이 꽤 크다보니 눈에 띄는 떨림현상을 발견할 수 있었습니다.

우선 문제를 해결하긴 했지만 더 좋은 방법이 있을 것 같아 꾸준히 개선 방법을 찾아보려고 합니다.

부족하지만 긴 글 읽어주셔서 오늘도 감사합니다! 🙇‍♂️ 🙇‍♀️

헥토데이터는 데이터 기반 다양한 서비스를 지원하는 기업입니다. 온라인에 분산된 데이터를 실시간으로 제공하기 위해 클라이언트 엔진과 웹 API를 활용합니다. 유수의 비대면 대출 핀테크 서비스가 선택한 헥토데이터의 CODEF API. 꼼꼼한 보안과 빠른 대응으로 기업이 자사 서비스에만 집중할 수 있도록 돕는 CODEF API에 대해 아래 배너를 눌러 확인해 보세요.

02_----------------_230616-1본 페이지 내의 모든 콘텐츠는 저작권법에 의해 보호받는 저작물로서, 모든 사용 권리는 ㈜헥토데이터에게 있습니다. 별도의 저작권 표시 없이 무단으로 사용하는 것을 금지하며, 자세한 저작권 정책은 해당 링크를 참고하시기 바랍니다. Copyright 2024.㈜헥토데이터 All rights reserved.

© Hecto Data Co., Ltd. All right reserved. Published with Ghost


(주)헥토데이터ㅣ대표자 : 오승철

사업자 등록번호 : 113-86-32627


개인정보 처리방침