Implementacja nieskończonego przewijania na stronie internetowej
Nieskończone przewijanie to mechanizm, który umożliwia dynamiczne doładowywanie treści w miarę przewijania strony przez użytkownika. Eliminuje potrzebę tradycyjnego podziału na strony z przyciskami nawigacyjnymi. Takie rozwiązanie zapewnia bardziej intuicyjną i płynną nawigację, zwłaszcza na urządzeniach mobilnych.
W niniejszym artykule omówimy, jak wdrożyć nieskończone przewijanie, wykorzystując podstawowe technologie internetowe: HTML, CSS i JavaScript.
Konfiguracja warstwy prezentacji
Pierwszym krokiem jest stworzenie szkieletu HTML, który będzie wyświetlał treść. Poniżej przedstawiono przykładowy kod:
<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>
Powyższy fragment przedstawia kontener, w którym umieszczone są przykładowe obrazy. Kod odwołuje się również do zewnętrznych arkuszy stylów CSS i plików JavaScript, które zostaną omówione w dalszej części artykułu.
Stylizacja CSS dla przewijalnej zawartości
Aby poprawnie wyświetlić elementy (w tym przypadku obrazki) w formie siatki, należy odpowiednio ostylować stronę za pomocą CSS. Poniższy kod powinien zostać umieszczony w pliku `style.css`:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html { font-size: 62.5%; }
body {
font-family: Cambria, Times, "Times New Roman", serif;
}
h1 {
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%);
}
Dzięki tym stylom obrazki będą wyświetlane w trzech kolumnach, a dodatkowo dodany jest prosty styl dla wskaźnika ładowania.
W tym momencie strona powinna prezentować się podobnie do:

Logika nieskończonego przewijania w JavaScript
Kluczowym elementem wdrożenia nieskończonego przewijania jest kod JavaScript. Edytuj plik `script.js` i umieść w nim następujący kod:
"use strict";
window.addEventListener("scroll", () => {
if (
window.scrollY + window.innerHeight >=
document.documentElement.scrollHeight - 100
) {
fetchMoreContent();
}
});
Ten fragment kodu nasłuchuje zdarzenia przewijania strony i uruchamia funkcję `fetchMoreContent()`, gdy użytkownik zbliży się do dolnej krawędzi strony (dokładnie 100 pikseli przed jej końcem).
Kolejny kod dotyczy funkcji, która pobiera dane:
async function fetchMoreContent() {
try {
let response = await fetch("https://fakestoreapi.com/products?limit=3");
if (!response.ok) {
throw new Error("Network response was not ok");
}
let data = await response.json();
console.log(data);
} catch (error) {
console.error("There was a problem fetching new content:", error);
} finally {
console.log("Fetch function fired");
}
}
Funkcja ta pobiera z API fakestoreapi trzy nowe elementy (w tym przypadku są to produkty). W konsoli przeglądarki powinny pojawiać się pobrane dane.

Aby uniknąć nadmiernego obciążania serwera i przeglądarki poprzez wielokrotne wywoływanie funkcji pobierającej dane, warto wprowadzić dodatkową zmienną, która będzie informowała, czy aktualnie trwa pobieranie:
let isFetching = false;
Teraz należy zmodyfikować funkcję pobierającą dane, aby pobierała je dopiero po zakończeniu poprzedniej operacji:
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("Network response was not ok");
}
let data = await response.json();
} catch (error) {
console.error("There was a problem fetching new content:", error);
} finally {
console.log("Fetch function fired");
isFetching = false;
}
}
Prezentacja pobranych danych
Po pobraniu danych konieczne jest ich wyświetlenie. W tym celu należy pobrać referencję do elementu nadrzędnego (kontenera), w którym umieszczane będą nowe obrazki:
const productsList = document.querySelector(".products__list");
Następnie należy stworzyć funkcję, która na podstawie pobranych danych wygeneruje elementy HTML i doda je do kontenera:
function displayNewContent(data) {
data.forEach((item) => {
const imgElement = document.createElement("img");
imgElement.src = item.image;
imgElement.alt = item.title;
productsList.appendChild(imgElement);
});
}
Ostatnim krokiem jest zmodyfikowanie funkcji `fetchMoreContent()` tak, aby po pobraniu danych przekazała je do funkcji `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("Network response was not ok");
}
let data = await response.json();
displayNewContent(data);
} catch (error) {
console.error("There was a problem fetching new content:", error);
} finally {
console.log("Fetch function fired");
isFetching = false;
}
}
Po tych zmianach nieskończone przewijanie powinno działać prawidłowo, a nowe elementy będą pojawiać się w miarę przewijania strony.

Aby podnieść komfort użytkowania, warto dodać wskaźnik ładowania, który będzie informował użytkownika o trwającym procesie pobierania danych. Zacznijmy od dodania do HTML elementu wskaźnika:
<h1 class="loading-indicator">Ładowanie...</h1>
Następnie pobierzmy do niego referencję w JS:
const loadingIndicator = document.querySelector(".loading-indicator");
Teraz stwórzmy dwie funkcje, które będą kontrolować widoczność wskaźnika:
function showLoadingIndicator() {
loadingIndicator.style.display = "block";
console.log("Ładowanie...");
}
function hideLoadingIndicator() {
loadingIndicator.style.display = "none";
console.log("Zakończono ładowanie.");
}
Na koniec zmodyfikuj funkcję `fetchMoreContent`, aby pokazywała wskaźnik na czas pobierania danych i ukrywała go po zakończeniu:
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("Network response was not ok");
}
let data = await response.json();
displayNewContent(data);
} catch (error) {
console.error("There was a problem fetching new content:", error);
} finally {
console.log("Fetch function fired");
hideLoadingIndicator();
isFetching = false;
}
}
Wprowadzone zmiany spowodują, że w trakcie ładowania nowych treści, użytkownik będzie widział wskaźnik „Ładowanie…”.
Warto pamiętać o kilku dobrych praktykach przy implementacji nieskończonego przewijania:
- Unikaj pobierania zbyt dużej ilości danych na raz, gdyż może to negatywnie wpłynąć na wydajność przeglądarki.
- Zastosuj funkcję opóźniającą (debounce) przy zdarzeniu przewijania, aby nie wysyłać zbyt wielu żądań w krótkim czasie.
- Daj użytkownikowi wybór, czy chce korzystać z nieskończonego przewijania, czy tradycyjnej paginacji.
- Poinformuj użytkownika, jeśli nie ma już więcej treści do załadowania.
Podsumowanie
Nieskończone przewijanie jest wygodnym rozwiązaniem, które ułatwia przeglądanie treści. Szczególnie sprawdza się w przypadku stron mobilnych. Wykorzystując omówione techniki i wskazówki, można łatwo wdrożyć tę funkcjonalność na swojej witrynie.
Zawsze należy pamiętać o perspektywie użytkownika i zapewnić mu informacje o aktualnym stanie działania aplikacji, np. poprzez wyświetlanie wskaźników ładowania czy komunikatów o błędach.
newsblog.pl
Maciej – redaktor, pasjonat technologii i samozwańczy pogromca błędów w systemie Windows. Zna Linuxa lepiej niż własną lodówkę, a kawa to jego główne źródło zasilania. Pisze, testuje, naprawia – i czasem nawet wyłącza i włącza ponownie. W wolnych chwilach udaje, że odpoczywa, ale i tak kończy z laptopem na kolanach.