Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ClaytonSeager/InifinityScroll/llms.txt

Use this file to discover all available pages before exploring further.

Infinity Scroll ships with four purpose-built UI components that enhance the browsing experience: a sticky header that compresses as you scroll, a live image counter, a full-screen loading overlay, and a scroll-to-top button that fades in when relevant. Every component is implemented in plain CSS and vanilla JavaScript — no UI framework required. The .Title__Column element houses the app title and the image counter. It sticks to the top of the viewport using position: sticky; top: 0 so it remains visible at all times.
.Title__Column {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    margin: 0;
    padding: 15px 0;
    position: sticky;
    top: 0;
    background-color: whitesmoke;
    transition: all 0.3s ease;
    z-index: 100;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.Title__Column.scrolled {
    opacity: 0.8;
    padding: 5px 0;
    backdrop-filter: blur(5px);
    background-color: rgba(245, 245, 245, 0.9);
}
The scroll listener in Infinity.js adds or removes the scrolled class based on whether scrollY has passed 50 pixels:
if (scrollY > 50) {
    titleColumn.classList.add('scrolled');
} else {
    titleColumn.classList.remove('scrolled');
}
When scrolled is active the header:
  • Reduces its vertical padding from 15px to 5px, making it take up less screen space
  • Lowers its opacity to 0.8
  • Applies backdrop-filter: blur(5px) with a slightly translucent background (rgba(245, 245, 245, 0.9)) so content scrolling behind it is softly blurred rather than jarring
All three changes transition smoothly because the base rule includes transition: all 0.3s ease.

Image counter

The #image-counter span sits inside a .counter pill that is absolutely positioned to the left of the header. It tracks the cumulative total of every image loaded across all batches and is updated in real time inside imageLoaded():
imageCounter.textContent = totalLoadedImages;
The 🖼 frame emoji icon to its left animates with a gentle infinite bounce defined by the @keyframes bounce rule:
.counter-icon {
    font-size: 14px;
    opacity: 0.8;
    animation: bounce 2s infinite;
}

@keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50%       { transform: translateY(-3px); }
}
The icon rises 3px at the halfway point of each 2-second cycle and returns to its resting position, looping indefinitely. The counter pill styling:
.counter {
    position: absolute;
    left: 50px;
    display: flex;
    align-items: center;
    font-size: 12px;
    gap: 8px;
    font-weight: 500;
    background-color: white;
    padding: 6px 12px;
    border-radius: 12px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
    letter-spacing: 0.5px;
    color: #333;
    border: 1px solid rgba(0, 0, 0, 0.05);
}

Loading spinner

The #Loader div covers the entire viewport with a semi-transparent white overlay while images are fetching. It is position: fixed so it sits above all page content regardless of scroll position:
.Loader {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(255, 255, 255, 0.8);
}

.Loader img {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
The overlay stretches edge-to-edge via top: 0; bottom: 0; left: 0; right: 0. The assets/loader.svg image inside it is centred using the classic top: 50%; left: 50%; transform: translate(-50%, -50%) technique. The hidden attribute is toggled in JavaScript to show and hide the overlay:
// Show the loader before a fetch begins
loader.hidden = false;

// Hide the loader once all images in the batch have loaded
loader.hidden = true;  // set inside imageLoaded() when imagesLoaded === totalImages
The loader is shown with loader.hidden = false at the start of every fetch — including the initial page load and each subsequent scroll-triggered or search-triggered fetch. It only disappears once every image in that batch fires its load event.

Scroll-to-top button

The #scrollTop element is a fixed-position button rendered at the bottom-right corner of the viewport. It starts invisible and off-position, then animates into view once the user has scrolled past one full viewport height:
.scroll-top {
    position: fixed;
    bottom: 30px;
    right: 30px;
    background-color: white;
    padding: 12px;
    border-radius: 12px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    opacity: 0;
    transform: translateY(20px);
    transition: all 0.3s ease;
    border: 1px solid rgba(0, 0, 0, 0.05);
    z-index: 1000;
}

.scroll-top.visible {
    opacity: 1;
    transform: translateY(0);
}
The visible class is added and removed by the scroll listener based on scrollY relative to innerHeight:
if (scrollY > innerHeight) {
    scrollTopBtn.classList.add('visible');
} else {
    scrollTopBtn.classList.remove('visible');
}
The button slides up from translateY(20px) to translateY(0) and fades in from opacity: 0 to opacity: 1 — both driven by the transition: all 0.3s ease on the base rule. Clicking the button scrolls smoothly back to the top:
scrollTopBtn.addEventListener('click', () => {
    window.scrollTo({
        top: 0,
        behavior: 'smooth'
    });
});
The .scroll-text label (“Back to Top”) is hidden by default (display: none) on desktop and only becomes visible on mobile — see the responsive design section below.

Responsive design

Two @media (max-width: 600px) blocks in style.css adapt the layout for small screens. Layout and image container:
@media (max-width: 600px) {
    .Title__Column {
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
    .Image__Container {
        margin: 10px 0;
    }
    .counter {
        position: static;
        margin-right: 15px;
        font-size: 11px;
        padding: 4px 10px;
    }
    .counter-icon {
        font-size: 12px;
    }
}
On mobile the .counter switches from position: absolute to position: static, flowing inline inside the header row instead of being anchored to the left edge. The #Image__Container removes its horizontal margin (margin: 10px 0) so images span the full screen width. Scroll-to-top button:
@media (max-width: 600px) {
    .scroll-top {
        bottom: 0;
        right: 0;
        width: 100%;
        justify-content: center;
        padding: 12px;
        border-radius: 0;
        background-color: rgba(255, 255, 255, 0.6);
        backdrop-filter: blur(8px);
    }
    .scroll-text {
        display: inline;
        font-size: 14px;
        font-weight: 500;
        letter-spacing: 0.5px;
    }
}
On mobile the button expands to span the full viewport width along the bottom edge (bottom: 0; right: 0; width: 100%), loses its border radius, gains a frosted-glass background, and reveals the .scroll-text “Back to Top” label (display: inline) alongside the 🔼 icon.

Build docs developers (and LLMs) love