스크롤이 쏘아올린 작은 공
안녕하세요. 서비스 개발팀 Somi 입니다. 🐥
오늘은 저희 헥토데이터 최초의 마이데이터 기반 자산관리 서비스인 핀퐁 finpong 웹 프로젝트 작업 중 메인화면에서 발생한 스크롤 오류와 오류 해결 과정에 대해 살펴보려고 합니다.
😱 스크롤 오류
1. scroll-snap 속성과의 첫만남
스와이프없이 간단하게 스와이프 효과내기
- scroll-snap-type: x mandatory;
- scroll-snap-align: start;
//=== 사용예시 ===//
/* 부모 컨테이너에 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으로 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에 대해 아래 배너를 눌러 확인해 보세요.
본 페이지 내의 모든 콘텐츠는 저작권법에 의해 보호받는 저작물로서, 모든 사용 권리는 ㈜헥토데이터에게 있습니다. 별도의 저작권 표시 없이 무단으로 사용하는 것을 금지하며, 자세한 저작권 정책은 해당 링크를 참고하시기 바랍니다. Copyright 2024.㈜헥토데이터 All rights reserved.