Thursday, April 25, 2024
HomeProgrammingGetting Inventive with Infinite Loop Scrolling

Getting Inventive with Infinite Loop Scrolling



From our sponsor: Get customized content material suggestions to make your emails extra partaking. Join Mailchimp immediately.

Infinite scrolling is an online design method that permits customers to scroll by means of a unending listing of content material by robotically loading new gadgets because the consumer reaches the underside of the web page. As a substitute of getting to click on by means of to a brand new web page to see extra content material, the content material is robotically loaded and appended to the underside of the web page because the consumer scrolls. This could create a seamless and fascinating looking expertise for customers, as they will simply entry a considerable amount of content material with out having to attend for brand spanking new pages to load. Neglect about reaching the footer, although!

Looping the scroll of a web page refers back to the means of robotically taking customers again to the highest of the web page as soon as they attain the tip of the scroll. Which means that they’ll be capable of repeatedly scroll by means of the identical content material again and again, quite than being offered with new content material as they scroll down the web page.

On this article, we’ll present some examples artistic loop scrolling, after which reimplement the impact appear on Bureau DAM. We can be utilizing Lenis by Studio Freight to implement the looping impact and GSAP for the animations.

What’s loop scrolling?

When your content material is proscribed, you are able to do artistic issues with loop scrolling, which is principally infinite scrolling with repeating content material. An awesome instance for such a artistic use is the impact seen on Bureau DAM:

Some nice concepts how looping the scroll can be utilized in a artistic approach and add worth to a web site:

  • It might create an immersive expertise for customers. By repeatedly scrolling by means of the identical content material, customers can really feel extra immersed within the web site and engaged with the content material. This may be notably helpful for web sites that need to create a robust emotional reference to their viewers.
  • It may be used to create a recreation or interactive expertise. By including interactive parts to the content material that’s being looped, builders can create a recreation or interactive expertise for customers. For instance, a web site might use looping the scroll to create a scrolling recreation or to permit customers to work together with the content material in a novel approach.
  • It may be used to create a “time loop” impact. By looping the scroll in a selected approach, builders can create the phantasm of a “time loop,” the place the content material seems to repeat itself in a steady loop. This may be notably efficient for web sites that need to convey a way of continuity or timelessness.

A easy instance

Let’s create a easy instance. We’ll arrange a grid of 6 photos that repeat on scroll. How can we obtain this? It’s easy: we have to repeat the content material in a approach that when reaching the tip, we are able to merely reset the scroll to the highest with out anyone noticing! We’ve beforehand explored this idea in our CSS-only marquee impact. In one other demo we additionally present easy methods to play with this type of infinite animation.

So, for our first instance we’ve the next markup:

<div class="grid">
	<div class="grid__item" model="background-image:url(img/1.jpg);"></div>
	<div class="grid__item" model="background-image:url(img/4.jpg);"></div>
	<div class="grid__item" model="background-image:url(img/3.jpg);"></div>
	<div class="grid__item" model="background-image:url(img/5.jpg);"></div>
	<div class="grid__item" model="background-image:url(img/2.jpg);"></div>
	<div class="grid__item" model="background-image:url(img/6.jpg);"></div>
</div>

Our kinds will create a 3×3 grid:

.grid {
	show: grid;
	grid-template-columns: repeat(3, 1fr);
	hole: 5vh;
}

.grid__item {
	top: 47.5vh; /* 50vh minus half of the hole */
	background-size: cowl;
	background-position: 50% 20%;
}

.grid__item:nth-child(3n-2) {
	border-radius: 0 2rem 2rem 0;
}

.grid__item:nth-child(3n) {
	border-radius: 2rem 0 0 2rem;
}

.grid__item:nth-child(3n-1) {
	border-radius: 2rem;
}

Lenis comes with a helpful possibility for making the scroll infinite. In our script we’ll ensure to repeat the seen grid gadgets (on this case it’s 6):

const lenis = new Lenis({
    clean: true,
    infinite: true,
});

operate raf(time) {
    lenis.raf(time);
    requestAnimationFrame(raf);
}

requestAnimationFrame(raf);

// repeat first six gadgets by cloning them and appending them to the .grid
const repeatItems = (parentEl, complete = 0) => {
    const gadgets = [...parentEl.children];
    for (let i = 0; i <= total-1; ++i) {
        var cln = gadgets[i].cloneNode(true);
        parentEl.appendChild(cln);
    }
};
repeatItems(doc.querySelector('.grid'), 6);

The result’s a grid that repeats on scroll:

We are able to additionally change the course of the scroll and go sideways!

Taking part in with animations

Whereas we scroll, we are able to add some fancy animations to our grid gadgets. Paired with switching the remodel origin in the best time, we are able to get one thing playful like this:

We are able to additionally play with the size and opacity values to create one thing like a vanishing impact:

Or, add some excessive stretchiness:

We are able to additionally play with a 3D animation and an extra filter impact:

The Bureau DAM instance

Now, let’s see how we are able to remake the Bureau DAM animation. As we don’t have a grid right here, issues get a bit easier. Similar to them, we’ll use an SVG for the typography ingredient, as we need to stretch it over the display:

<div class="grid">
	<div class="grid__item grid__item--stack">
		<svg class="grid__item-logo" width="100%" top="100%" viewBox="0 0 503 277" preserveAspectRatio="none">
		<path d="M56.3 232.3 56.3 193.8C56.3 177.4 54.7 174.1 48.5 165.9 35.4 148.8 17.6 133 8.5 120.8.7 110.3.1 103.7.1 85.6L.1 45.2C.1 14.9 13.5.5 41 .5 68.8.5 79.1 15.3 79.1 45.2L79.1 94.5 56.9 94.5 56.9 48.5C56.9 35 53.5 25.8 40.7 25.8 29.8 25.8 24.1 32.4 24.1 45.2L24.1 85.3C24.1 96.8 25.1 100.1 29.8 106.3 41 121.8 59.1 137.6 68.8 150.4 77.2 161.6 80 169.8 80 193.5L80 232.3C80 260.9 68.8 277 40.4 277 12.3 277 .1 261.5.1 232.3L.1 174.7 22.9 174.7 22.9 228.7C22.9 243.1 26.9 252.3 40.1 252.3 51.6 252.3 56.3 245.1 56.3 232.3ZM176.5 277 101.5 277 101.5.5 127.1.5 127.1 251.8 176.5 251.8 176.5 277ZM290 277 264.5 277 258.4 230.6 217.1 230.6 211 277 186.2 277 224.1.5 254.1.5 290 277ZM218.1 207.1 253.4 207.1C247.7 159.7 241.6 114 236.3 65.3 230.5 114 224.5 159.7 218.1 207.1ZM399.6 277 374 277 326.3 75.1C326.6 117.1 326.6 155.7 326.6 197.7L326.6 277 304.5 277 304.5.5 335 .5 377.4 203.1C377 165.1 377 129.2 377 91.2L377 .5 399.6.5 399.6 277ZM471.5 277 446.3 277 446.3 26.3 415.3 26.3 415.3.5 502.4.5 502.4 26.3 471.5 26.3 471.5 277Z" id="SLANT" fill="#fff"></path>
		</svg>
		<p class="grid__item-text credit">An infinite scrolling demo primarily based on <a href="https://www.bureaudam.com/">Bureau DAM</a></p>
	</div>
	<div class="grid__item">
		<div class="grid__item-inner">
			<div class="grid__item-img" model="background-image:url(img/1.jpg);"></div>
			<p class="grid__item-text"><a href="#">View all initiatives →</a></p>
		</div>
	</div>
</div>

In our CSS we set a few kinds that may ensure the gadgets are stretched to full display:

.grid {
    show: flex;
    flex-direction: column;
    hole: 5vh;
}

.grid__item {
    top: 100vh; 
	place-items: heart;
    show: grid;
}

.grid__item-inner {
	show: grid;
	hole: 1rem;
	place-items: heart;
	text-align: heart;
}

.grid__item--stack {
	show: grid;
	hole: 2rem;
	grid-template-rows: 1fr auto;
}

.grid__item-logo {
	padding: 8rem 1rem 0;
}

.grid__item-img {
	background-size: cowl;
    background-position: 50% 50%;
	top: 70vh;
	aspect-ratio: 1.5;
}

.grid__item-text {
	margin: 0;
}

A correct setting for the remodel origins ensures that we get the best visible impact:

gsap.registerPlugin(ScrollTrigger);

// repeat first three gadgets by cloning them and appending them to the .grid
const repeatItems = (parentEl, complete = 0) => {
    const gadgets = [...parentEl.children];
    for (let i = 0; i <= total-1; ++i) {
        var cln = gadgets[i].cloneNode(true);
        parentEl.appendChild(cln);
    }
};

const lenis = new Lenis({
    clean: true,
    infinite: true
});

lenis.on('scroll',()=>{
    ScrollTrigger.replace() // Thanks Clément!
})

operate raf(time) {
    lenis.raf(time);
    requestAnimationFrame(raf);
}

imagesLoaded( doc.querySelectorAll('.grid__item'), { background: true }, () => {

    doc.physique.classList.take away('loading');

    repeatItems(doc.querySelector('.grid'), 1);

    const gadgets = [...document.querySelectorAll('.grid__item')];

    // first merchandise
    const firtsItem = gadgets[0];
    gsap.set(firtsItem, {transformOrigin: '50% 100%'})
    gsap.to(firtsItem, {
        ease: 'none',
        startAt: {scaleY: 1},
        scaleY: 0,
        scrollTrigger: {
            set off: firtsItem,
            begin: 'heart heart',
            finish: 'backside high',
            scrub: true,
            fastScrollEnd: true,
            onLeave: () => {
                gsap.set(firtsItem, {scaleY: 1,})
            },
        }
    });

    // final merchandise  
    const lastItem = gadgets[2];
    gsap.set(lastItem, {transformOrigin: '50% 0%', scaleY: 0})
    gsap.to(lastItem, {
        ease: 'none',
        startAt: {scaleY: 0},
        scaleY: 1,
        scrollTrigger: {
            set off: lastItem,
            begin: 'high backside',
            finish: 'backside high',
            scrub: true,
            fastScrollEnd: true,
            onLeaveBack: () => {
                gsap.set(lastItem, {scaleY: 1})
            }
        }
    });
    
    // in between
    let ft;
    let st;
    const middleItem = gadgets[1];
        
    ft = gsap.timeline()
    .to(middleItem, {
        ease: 'none',
        onStart: () => {
            if (st) st.kill()
        },
        startAt: {scale: 0},
        scale: 1,
        scrollTrigger: {
            set off: middleItem,
            begin: 'high backside',
            finish: 'heart heart',
            scrub: true,
            onEnter: () => gsap.set(middleItem, {transformOrigin: '50% 0%'}),
            onEnterBack: () => gsap.set(middleItem, {transformOrigin: '50% 0%'}),
            onLeave: () => gsap.set(middleItem, {transformOrigin: '50% 100%'}),
            onLeaveBack: () => gsap.set(middleItem, {transformOrigin: '50% 100%'}),
        },
    });

    st = gsap.timeline()
    .to(middleItem, {
        ease: 'none',
        onStart: () => {
            if (ft) ft.kill()
        },
        startAt: {scale: 1},
        scale: 0,
        scrollTrigger: {
            set off: middleItem,
            begin: 'heart heart',
            finish: 'backside high',
            scrub: true,
            onEnter: () => gsap.set(middleItem, {transformOrigin: '50% 100%'}),
            onEnterBack: () => gsap.set(middleItem, {transformOrigin: '50% 100%'}),
            onLeave: () => gsap.set(middleItem, {transformOrigin: '50% 0%'}),
            onLeaveBack: () => gsap.set(middleItem, {transformOrigin: '50% 0%'}),
        },
    });
    
    requestAnimationFrame(raf);
    
    const refresh = () => {
        ScrollTrigger.clearScrollMemory();
        window.historical past.scrollRestoration = 'guide';
        ScrollTrigger.refresh(true);
    }

    refresh();
    window.addEventListener('resize', refresh);

});

The result’s a squashy and squeezy sequence of pleasure:

Try the demo

Replace: Because of Clément’s remark and assistance on conserving Lenis and GSAP in sync, it’s now a lot smoother!

And that’s it! Hope you had some enjoyable and that you simply acquired some inspiration in your subsequent initiatives.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments