무한 스크롤은 기존의 페이지 번호 매기기 방식과 다르게, 사용자가 페이지를 아래로 스크롤할 때 콘텐츠가 지속적으로 로드되는 방식입니다. 이는 특히 모바일 환경에서 더욱 매끄러운 사용자 경험을 제공하는 데 유용합니다.
이 글에서는 표준 HTML, CSS, 그리고 JavaScript를 사용하여 무한 스크롤을 구현하는 방법을 상세히 알아보겠습니다.
프런트엔드 설정
콘텐츠를 보여주기 위한 기본적인 HTML 구조부터 시작해보겠습니다. 아래 예시 코드를 참고하세요:
<div> <link rel="stylesheet" href="https://wilku.top/how-to-implement-infinite-scroll-in-a-web-application/style.css" /> <h2>무한 스크롤 페이지</h2> <div class="products__list"> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg" /> </div> </div>
이 기본 페이지는 여러 개의 이미지 자리 표시자를 포함하고 있으며, CSS 파일과 JavaScript 파일 두 가지 외부 리소스를 참조합니다.
스크롤 가능한 콘텐츠를 위한 CSS 스타일링
자리 표시자 이미지들을 그리드 형태로 배치하기 위해, style.css 파일에 다음과 같은 CSS 코드를 추가합니다:
* { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 62.5%; } body { font-family: Cambria, Times, "Times New Roman", serif; } h2 { text-align: center; font-size: 5rem; padding: 2rem; } img { width: 100%; display: block; } .products__list { display: flex; flex-wrap: wrap; gap: 2rem; justify-content: center; } .products__list > * { width: calc(33% - 2rem); } .loading-indicator { display: none; position: absolute; bottom: 30px; left: 50%; background: #333; padding: 1rem 2rem; color: #fff; border-radius: 10px; transform: translateX(-50%); }
위 스타일을 적용하면 현재 페이지는 아래 이미지와 유사하게 나타날 것입니다.
JavaScript를 활용한 핵심 기능 구현
이제 script.js 파일을 편집하여 무한 스크롤 기능을 구현해보겠습니다. 사용자가 콘텐츠 영역이나 페이지 하단 근처에 도달했을 때를 감지하는 것이 핵심입니다.
"use strict"; window.addEventListener("scroll", () => { if ( window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 100 ) { fetchMoreContent(); } });
위 코드는 스크롤 이벤트가 발생할 때마다 특정 조건을 확인하고, 해당 조건이 만족되면 `fetchMoreContent()` 함수를 호출합니다. 다음은 추가 콘텐츠를 가져오는 함수입니다.
async function fetchMoreContent() { try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("네트워크 응답이 실패했습니다."); } let data = await response.json(); console.log(data); } catch (error) { console.error("새 콘텐츠를 가져오는 데 문제가 발생했습니다:", error); } finally { console.log("데이터 가져오기 함수 실행 완료"); } }
이 예제에서는 fakestoreapi를 사용하여 데이터를 가져옵니다.
콘솔을 확인하면 스크롤할 때마다 데이터가 성공적으로 로드되는 것을 확인할 수 있습니다.
스크롤 시 데이터가 여러 번 로드되는 것을 볼 수 있으며, 이는 성능 저하를 일으킬 수 있습니다. 이를 방지하기 위해 데이터 로딩 상태를 관리해야 합니다.
let isFetching = false;
이제 데이터를 가져오기 전에 이전 요청이 완료되었는지 확인하도록 `fetchMoreContent` 함수를 수정합니다.
async function fetchMoreContent() { if (isFetching) return; isFetching = true; try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("네트워크 응답이 실패했습니다."); } let data = await response.json(); } catch (error) { console.error("새 콘텐츠를 가져오는 데 문제가 발생했습니다:", error); } finally { console.log("데이터 가져오기 함수 실행 완료"); isFetching = false; } }
새 콘텐츠 표시
새 콘텐츠를 화면에 표시하기 위해, 상위 컨테이너에 이미지를 추가하는 기능을 구현합니다.
먼저 상위 요소를 선택합니다:
const productsList = document.querySelector(".products__list");
다음으로, 콘텐츠를 추가하는 함수를 만듭니다:
function displayNewContent(data) { data.forEach((item) => { const imgElement = document.createElement("img"); imgElement.src = item.image; imgElement.alt = item.title; productsList.appendChild(imgElement); }); }
마지막으로, `fetchMoreContent` 함수를 수정하여 가져온 데이터를 `displayNewContent` 함수에 전달합니다.
async function fetchMoreContent() { if (isFetching) return; isFetching = true; try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("네트워크 응답이 실패했습니다."); } let data = await response.json(); displayNewContent(data); } catch (error) { console.error("새 콘텐츠를 가져오는 데 문제가 발생했습니다:", error); } finally { console.log("데이터 가져오기 함수 실행 완료"); isFetching = false; } }
이제 무한 스크롤 기능이 제대로 작동합니다.
사용자 경험을 개선하기 위해, 새 콘텐츠를 로드하는 동안 로딩 표시기를 표시할 수 있습니다. 다음 HTML 코드를 추가하여 시작하세요:
<h2 class="loading-indicator">로딩 중...</h2>
다음으로, 로딩 요소를 선택합니다:
const loadingIndicator = document.querySelector(".loading-indicator");
로딩 표시기의 가시성을 제어하는 두 가지 함수를 만듭니다:
function showLoadingIndicator() { loadingIndicator.style.display = "block"; console.log("로딩 중..."); } function hideLoadingIndicator() { loadingIndicator.style.display = "none"; console.log("로딩 완료."); }
이제 `fetchMoreContent` 함수에 로딩 표시기 기능을 추가합니다:
async function fetchMoreContent() { if (isFetching) return; isFetching = true; showLoadingIndicator(); try { let response = await fetch("https://fakestoreapi.com/products?limit=3"); if (!response.ok) { throw new Error("네트워크 응답이 실패했습니다."); } let data = await response.json(); displayNewContent(data); } catch (error) { console.error("새 콘텐츠를 가져오는 데 문제가 발생했습니다:", error); } finally { console.log("데이터 가져오기 함수 실행 완료"); hideLoadingIndicator(); isFetching = false; } }
이 기능을 통해 사용자에게 로딩 상태를 명확하게 보여줄 수 있습니다.
다음은 몇 가지 추가적인 권장 사항입니다:
- 한 번에 너무 많은 데이터를 로드하지 마세요. 이는 브라우저에 부담을 주어 성능을 저하시킬 수 있습니다.
- 스크롤 이벤트가 감지된 즉시 데이터를 로드하는 대신, 디바운스 기능을 사용하여 로딩을 지연시키세요. 이를 통해 과도한 네트워크 요청을 방지할 수 있습니다.
- 모든 사용자가 무한 스크롤을 선호하는 것은 아닙니다. 필요한 경우 페이지 번호 매기기 방식의 옵션을 제공하세요.
- 더 이상 로드할 데이터가 없는 경우, 사용자에게 이를 명확하게 알려주세요.
매끄러운 콘텐츠 로딩 마스터하기
무한 스크롤은 사용자에게 원활한 콘텐츠 탐색 경험을 제공하며, 특히 모바일 기기 사용자에게 유용합니다. 이 글에서 제시된 팁과 지침을 따르면, 여러분의 웹사이트에 이 기능을 성공적으로 추가할 수 있습니다.
사용자가 사이트를 이용하는 동안 어떤 느낌을 받는지 항상 고려하세요. 진행 상황 표시, 오류 메시지 등을 제공하여 사용자 경험을 향상시키는 것이 중요합니다.