Learn how to create infinite scrolling in your website using HTML, CSS, and JavaScript with this easy step-by-step guide.
Table of Contents
Infinite scrolling is a popular technique used in modern websites to load content as users scroll down the page. Instead of requiring users to click on "Next" or "Load More," new content is automatically loaded when the user reaches the end of the page. This feature enhances user experience by providing continuous content without interruptions.
In this tutorial, we’ll guide you through the process of creating an infinite scrolling concept using HTML, CSS, and JavaScript. By the end of this tutorial, you'll have a basic yet powerful infinite scrolling system integrated into your website.
Prerequisites
Before we dive into the code, here are a few prerequisites for this tutorial:
- Basic knowledge of HTML and CSS.
- Familiarity with JavaScript.
- A code editor like VS Code or Sublime Text.
- A modern web browser to test the infinite scroll.
Source Code
Step 1 (HTML Code):
Start by creating the basic HTML file. In this file, we'll create the structure where the content will be displayed.
Here’s a breakdown of each part:
1. <!DOCTYPE html>
- Declares the document as an HTML5 document.
2. <html lang="en">
- Opens the HTML document and sets the language to English.
3. <head>
- The
<head>
section contains metadata about the document, links to stylesheets, and the title.
<meta charset="UTF-8">
- Sets the character encoding to UTF-8, which supports most characters and symbols.
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- Sets the viewport to make the website responsive on different devices, ensuring it scales properly on mobile screens.
<title>Infinite Scrolling</title>
- Sets the title of the page, displayed in the browser tab.
<link rel="stylesheet" href="https://fonts.go..">
- Links to Google Fonts to use the "Poppins" font with various font weights.
<link rel="stylesheet" href="styles.css">
- Links to an external CSS file (
styles.css
) for styling the page.
4. <body>
- The
<body>
section contains the visible content and elements on the page.
<div id="content">
- A container
div
with the IDcontent
to hold the initial cards displayed on the page. - This container will dynamically load more content as the user scrolls.
<div class="card">
- Each card is represented by a
div
with the classcard
. - Cards are designed to display an image, a title, and a description.
<img src="https://placehold.co/300" alt="Placeholder Image">
- Displays a placeholder image with a size of 300px. The
alt
attribute provides alternative text.
- <div class="card-content">
- A
div
containing the text content of each card.
<h3>Title 1</h3>
- A heading for the card, displaying the title.
<p>This is a sample description for the first card.</p>
- A paragraph providing a description for the card.
<div id="loading">Loading more content...</div>
- A
div
with the IDloading
to display a loading message when additional content is being fetched.
5. <script src="script.js"></script>
- Links to an external JavaScript file (
script.js
) that will handle the infinite scrolling logic, adding new cards to the#content
div when the user reaches the bottom of the page.
Step 2 (CSS Code):
In the styles.css
file, we will add some styles for the content cards and the loading message.
Here's a breakdown of each section of the CSS code:
1. body
body {
font-family: 'Poppins', Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #825CFF;
}
font-family: 'Poppins', Arial, sans-serif;
: Sets the font for the page to "Poppins" (a Google font), falling back to Arial or any generic sans-serif font if "Poppins" is unavailable.margin: 0;
: Removes any default margin from the body element.padding: 20px;
: Adds 20px padding inside the body, creating space between the page content and the edge of the browser window.background-color: #825CFF;
: Sets the background color of the page to a shade of purple (#825CFF
).
2. #content
#content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
display: grid;
: Defines the#content
div as a grid container, which enables a flexible and responsive layout for the items inside.grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
: Creates a grid where the columns automatically adjust based on the content size:auto-fill
: Fills the container with as many columns as can fit.minmax(250px, 1fr)
: Each column will have a minimum width of 250px but can grow to take up available space (1fr
represents a fraction of the available space).
gap: 20px;
: Sets the gap (spacing) between grid items (cards) to 20px.
3. .card
.card {
position: relative;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
position: relative;
: Positions the.card
element relative to its normal position, allowing for absolute positioning of any child elements (if needed).background-color: #ffffff;
: Sets the background color of the card to white.border-radius: 10px;
: Rounds the corners of the card with a radius of 10px, giving it a smoother, more modern appearance.box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
: Adds a subtle shadow effect to the card, creating depth. It is a soft, 4px shadow with a slight blur (12px).overflow: hidden;
: Ensures that any content (e.g., images) that exceeds the card boundaries is hidden, ensuring a clean, contained look.transition: transform 0.3s ease, box-shadow 0.3s ease;
: Adds a smooth transition effect when the card is hovered over, affecting both the transform and box-shadow properties.
4. .card img
.card img {
width: 100%;
height: 180px;
object-fit: cover;
transition: transform 0.3s ease;
}
width: 100%;
: Ensures the image takes up the full width of the card.height: 180px;
: Sets the height of the image to 180px, maintaining a consistent size for the card images.object-fit: cover;
: Ensures that the image fully covers the assigned dimensions of the image container, cropping the image if necessary without distorting it.transition: transform 0.3s ease;
: Adds a smooth transition effect for the transform property, which will be used for zooming in the image on hover.
5. .card:hover img
.card:hover img {
transform: scale(1.05);
}
transform: scale(1.05);
: When the card is hovered, the image inside it will slightly zoom in by 5% (scale of1.05
), creating a subtle zoom effect for interactivity.
6. .card-content
.card-content {
padding: 15px;
}
padding: 15px;
: Adds padding inside the.card-content
div to create space around the text content.
7. .card-content h3
.card-content h3 {
font-size: 1.25em;
margin: 0 0 10px;
color: #333;
}
font-size: 1.25em;
: Sets the font size of the card title (h3
) to 1.25 times the base font size, making it larger and more prominent.margin: 0 0 10px;
: Removes the default margin on the top and sides, and adds a 10px margin at the bottom to space out the title from the description.color: #333;
: Sets the title color to a dark shade of gray (#333
), making it easy to read.
8. .card-content p
.card-content p {
margin: 0;
color: #777;
font-size: 0.9em;
line-height: 1.5;
}
margin: 0;
: Removes the default margin from the paragraph.color: #777;
: Sets the text color to a lighter gray (#777
), creating contrast with the title.font-size: 0.9em;
: Sets the font size to 0.9 times the base font size, making it smaller than the title.line-height: 1.5;
: Sets the line height (space between lines of text) to 1.5, improving readability.
9. .card:hover
.card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
transform: translateY(-5px);
: When the card is hovered, it is moved 5px upwards (translateY(-5px)
), creating a floating effect.box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
: Adds a stronger shadow effect when the card is hovered, making it appear more prominent by increasing the shadow spread and blur.
10. #loading
#loading {
text-align: center;
padding: 20px;
font-size: 18px;
color: #fff;
}
text-align: center;
: Centers the loading text inside the#loading
div.padding: 20px;
: Adds padding inside the#loading
div, making the loading text more spaced out.font-size: 18px;
: Sets the font size of the loading text to 18px.color: #fff;
: Sets the text color to white, which stands out against the background color.
body {
font-family: 'Poppins', Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #825CFF;
}
#content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
max-width: 700px;
margin: auto;
}
.card {
position: relative;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card img {
width: 100%;
height: 180px;
object-fit: cover;
transition: transform 0.3s ease;
}
.card:hover img {
transform: scale(1.05);
}
.card-content {
padding: 15px;
}
.card-content h3 {
font-size: 1.25em;
margin: 0 0 10px;
color: #333;
}
.card-content p {
margin: 0;
color: #777;
font-size: 0.9em;
line-height: 1.5;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
#loading {
text-align: center;
padding: 20px;
font-size: 18px;
color: #fff;
}
Step 3 (JavaScript Code):
Next, we write the JavaScript to add infinite scrolling functionality. In script.js
, we will load more content as the user scrolls down.
Let's break down how it works:
1. Initial Setup
const content = document.getElementById('content');
const loading = document.getElementById('loading');
let cardCounter = 2;
let loadingMore = false;
content
: This variable stores the reference to the#content
element, which is the container where the cards will be added.loading
: This stores the reference to the#loading
element, which will be used to detect when the user scrolls to the bottom.cardCounter
: This keeps track of the number of cards loaded so far. Initially set to2
(since one card is already hardcoded in the HTML).loadingMore
: A flag to prevent multiple simultaneous loading operations. It ensures that new content isn't loaded if the previous operation is still in progress.
2. loadMoreContent
Function
function loadMoreContent() {
if (loadingMore) return;
loadingMore = true;
setTimeout(() => {
for (let i = 0; i < 3; i++) {
const card = document.createElement('div');
card.className = 'card';
const img = document.createElement('img');
img.src = `https://placehold.co/300?text=Image+${cardCounter}`;
img.alt = `Image ${cardCounter}`;
const cardContent = document.createElement('div');
cardContent.className = 'card-content';
const title = document.createElement('h3');
title.textContent = `Title ${cardCounter}`;
const description = document.createElement('p');
description.textContent = `This is a sample description for card ${cardCounter}. Enjoy the modern look!`;
cardContent.appendChild(title);
cardContent.appendChild(description);
card.appendChild(img);
card.appendChild(cardContent);
content.appendChild(card);
cardCounter++;
}
loadingMore = false;
}, 1000);
}
loadMoreContent()
: This function dynamically creates and appends 3 new content cards to the#content
container.if (loadingMore) return;
: IfloadingMore
istrue
, it means new content is already being loaded, so the function exits without doing anything.loadingMore = true;
: Marks that the loading process has started to avoid multiple calls to load content at the same time.setTimeout(() => { ... }, 1000);
: Simulates a delay of 1 second (1000 milliseconds) to mimic an actual API call or loading process.- Inside the
setTimeout
block:- A loop is used to create and append 3 new cards to the page.
- For each card:
const card = document.createElement('div');
: A newdiv
element is created with the classcard
for each new card.- Image (
img
): A newimg
element is created with a source URL that dynamically includes thecardCounter
(to differentiate the images) and sets itsalt
attribute. - Card Content (
cardContent
): Adiv
with the classcard-content
is created and appended with a title (h3
) and description (p
), both of which contain dynamic text based on thecardCounter
. - Appending: The image and content are added to the card, and the card is appended to the
#content
container. cardCounter++
: ThecardCounter
is incremented to ensure that the titles, descriptions, and image links are unique for each new card.
loadingMore = false;
: Marks the loading process as complete, allowing the next loading operation to occur.
3. IntersectionObserver
for Infinite Scrolling
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting && !loadingMore) {
loadMoreContent();
}
});
});
observer.observe(loading);
IntersectionObserver
: This is an API that allows you to observe when an element enters or exits the viewport (or is about to be visible). It is used here to trigger the loading of more content when the#loading
element is about to be visible in the user's viewport.entries.forEach(entry => { ... });
: Loops through each entry observed (there's only one in this case, the#loading
element).if (entry.isIntersecting && !loadingMore)
: Checks if the#loading
element is intersecting (i.e., is visible within the viewport) and ensures that content is not already being loaded (loadingMore
isfalse
).- If both conditions are true, it calls
loadMoreContent()
to load more cards.
rootMargin: '0px 0px 200px 0px'
: This defines a margin around the viewport. When the#loading
element comes within 200px of the bottom of the viewport, it will trigger the loading process.observer.observe(loading);
: Starts observing the#loading
element to see when it becomes visible within the viewport.
const content = document.getElementById('content');
const loading = document.getElementById('loading');
let cardCounter = 2;
let loadingMore = false;
function loadMoreContent() {
if (loadingMore) return;
loadingMore = true;
setTimeout(() => {
for (let i = 0; i < 3; i++) {
const card = document.createElement('div');
card.className = 'card';
const img = document.createElement('img');
img.src = `https://placehold.co/300?text=Image+${cardCounter}`;
img.alt = `Image ${cardCounter}`;
const cardContent = document.createElement('div');
cardContent.className = 'card-content';
const title = document.createElement('h3');
title.textContent = `Title ${cardCounter}`;
const description = document.createElement('p');
description.textContent = `This is a sample description for card ${cardCounter}. Enjoy the modern look!`;
cardContent.appendChild(title);
cardContent.appendChild(description);
card.appendChild(img);
card.appendChild(cardContent);
content.appendChild(card);
cardCounter++;
}
loadingMore = false;
}, 1000);
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting && !loadingMore) {
loadMoreContent();
}
});
});
observer.observe(loading);
Final Output:
Conclusion:
In this tutorial, we learned how to create an infinite scrolling feature for a webpage using HTML, CSS, and JavaScript. By following these simple steps, you can improve your website’s user experience by offering seamless content loading as users scroll. Infinite scrolling is widely used in social media platforms, blogs, and e-commerce sites to engage users and keep them on the page longer.
Feel free to customize the design and functionality further to suit your project’s needs. You can add features like infinite scrolling for images, articles, or even dynamically loading products in an online store.
Implement this on your website today to provide a smooth and engaging user experience.
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊