Preventing image flickering in SvelteKit: A guide

Upon the initial loading of a website, you may notice that the images tend to flicker or flash when transitioning between them. However, once these images are stored in the browser's cache, subsequent visits to the site will display the images seamlessly and without any flashing or delays.

<script lang="ts">
    import {onMount} from "svelte";
    import {writable} from "svelte/store";

    // Specify the URLs for your images here
    const images = [
        {
            path: "https://static.bunnycdn.ru/i/cache/images/5/58/5806a16f2892768b4930c39ebf6ce756.jpg",
            id: "Image 1",
        },
        {
            path: "https://static.bunnycdn.ru/i/cache/images/0/03/0307ce050517b8fde68134b23fa9b1d1.jpg",
            id: "Image 2",
        },
    ];

    let currentIndex = writable(0);

    let interval: ReturnType<typeof setInterval>;

    onMount(() => {
        interval = setInterval(() => {
            currentIndex.update((value) => (value + 1) % images.length);
        }, 3000); // Change slide every 3 seconds
        return () => {
            clearInterval(interval);
        };
    });
</script>

<div class="slideshow">
    <div class="list">
        {#each images as image, i (image)}
            <div
                class="item"
                style="position: relative; display: {$currentIndex === i ? 'block' : 'none'};"
            >
                <img
                    class="slide {i === $currentIndex ? 'active' : ''}"
                    src={image.path}
                    alt={`Slide ${i + 1}`}
                />
            </div>
        {/each}
    </div>
</div>

This piece of code showcases my work in action.

My goal is for the website to load smoothly without any flickering when transitioning between images.

Answer №1

It's important to note that when all images are added to the DOM and begin loading simultaneously, it can lead to wasted bandwidth and potential delays in displaying the current image.

To avoid this issue, consider rendering only the current image instead of using an #each loop.

In the provided example, there is no need for currentIndex to be a store or for interval to be declared outside of the onMount function.

The initial image may not always load first, but you can ensure subsequent images are loaded before transitioning to the next slide by utilizing the Image constructor to preload the source.

Instead of using an interval, consider implementing timeouts which prevent premature switching if loading takes longer than anticipated.

onMount(() => {
    const loadImage = item => new Promise((resolve, reject) => {
        const image = new Image();
        image.onload = () => resolve();
        image.onerror = () => reject();
        image.src = item.path;
    });

    let timeout;
    let destroyed = false;

    const nextSlide = async () => {
        const nextIndex = (currentIndex + 1) % images.length;
        await loadImage(images[nextIndex]);
        currentIndex = nextIndex;

        if (!destroyed)
            timeout = setTimeout(nextSlide, 3000);
    }

    timeout = setTimeout(nextSlide, 3000);

    return () => {
        clearTimeout(timeout);
        destroyed = true;
    };
});

If you still require currentIndex to be a store, simply use $currentIndex directly without the need to call set() or update().

The loaded Image can also be inserted into the DOM upon loading by incorporating the slide-switching functionality as a Svelte action, passed with the corresponding DOM node.


Alternatively, you can add on:load directly to the <img> element in the markup, but it must coordinate with the timing logic for slides. One approach is storing a promise on each image and resolving it:

<script>
  // ...

  const deferred = () => {
    let funcs;
    const promise = new Promise((resolve, reject) => funcs = { resolve, reject });
    return Object.assign(promise, funcs);
  };

  // Potential SSR issues
  const images = [...].map(x => ({ ...x, loaded: deferred() }));

  let currentIndex = 0;

  onMount(() => {
    let timeout;
    let destroyed = false;
    const nextSlide = async () => {
      const nextIndex = (currentIndex + 1) % images.length;
      await images[nextIndex].loaded;
      currentIndex = nextIndex;

      if (!destroyed) timeout = setTimeout(nextSlide, 3000);
    };
    timeout = setTimeout(nextSlide, 3000);

    return () => {
      clearTimeout(timeout);
      destroyed = true;
    };
  });
</script>

...
<img ...
     on:load={() => image.loaded.resolve()} />

This method relies on the assumption that the next image is already in the DOM to trigger its loading.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When trying to upload a file with ng-upload in Angular, the error 'TypeError: Cannot read properties of undefined (reading 'memes')' is encountered

Struggling with an issue for quite some time now. Attempting to upload an image using ng-upload in angular, successfully saving the file in the database, but encountering a 'Cannot read properties of undefined' error once the upload queue is comp ...

What is the process of 'initializing' an object in TypeScript?

Is it possible that retrieving a json from a mongodb database and casting it does not trigger the typescript constructor? What could be causing this issue? I have a Team class export class Team { transformations: { [transformationId: string]: Transfor ...

Incorporate dynamic HTML snippets into the DOM with Angular 4

Looking to populate an unordered list element <ul> with small, straightforward snippets from my JavaScript. Just basic lines like <li>Label: Text</li>. Using the ViewContainerRef.createComponent(ItemComponent) method to create a new comp ...

Retrieve information from an XML document

I have some XML content that looks like this: <Artificial name="Artifical name"> <Machine> <MachineEnvironment uri="environment" /> </Machine> <Mobile>taken phone, test when r1 100m ...

Display the concealed mat-option once all other options have been filtered out

My current task involves dynamically creating multiple <mat-select> elements based on the number of "tag types" retrieved from the backend. These <mat-select> elements are then filled with tag data. Users have the ability to add new "tag types, ...

Jasmine has detected an undefined dependency

Testing out the following code: constructor(drawingService: DrawingService) { super(drawingService); //... } private writeOnCanvas(): void { this.drawingService.clearCanvas(this.drawingService.previewCtx); this.drawing ...

Can you explain the distinction between the controls and get methods used with the FormGroup object?

I have encountered an interesting issue with 2 lines of code that essentially achieve the same outcome: this.data.affiliateLinkUrl = this.bookLinkForm.controls['affiliateLinkUrl'].value; this.data.affiliateLinkUrl = this.bookLinkForm.get(' ...

TypeORM: establishing many-to-one relationships between different types of entities

Trying to represent a complex relationship in TypeORM: [ItemContainer]-(0..1)---(0..n)-[ContainableItem]-(0..n)---(0..1)-[ItemLocation] In simpler terms: A ContainableItem can exist either within an ItemContainer or at an ItemLocation. Although it cannot ...

Generating and setting an object property in TypeScript at runtime

In my code, I have defined an interface as follows: export interface OurHistory { ourHistory?: object; step1?:object; step2?:object; } Within the HistoryComponent class, I am doing the following: export class HistoryComponent implements OnInit, On ...

The TypeScript compiler throws an error when encountering nulls in conjunction with the isNull function

Whenever I set strictNullChecks: true in tsconfig.json and utilize the isNull function for null checks, the compiler throws the error TS2531: Object is possibly 'null'. Interestingly, isNull doesn't trigger any errors in VsCode, however, the ...

TS1316 Error: You can only have global module exports at the top level of the file

Encountering difficulties while trying to compile an older typescript project that I am revisiting. The build process is failing due to an issue with q. I suspect it may be related to the tsc version, but no matter which version I try, errors persist. Som ...

Vanilla JavaScript error: Unable to access property

I am working on implementing a header with a logo and navigation that includes a menu toggle link for smaller viewports. My goal is to achieve this using Vanilla JS instead of jQuery. However, when I click on the menu toggle link, I encounter the followin ...

You cannot assign type void to type any

I'm currently working on a component that involves some code: export class AddNewCardComponent { public concept = []; constructor( private _router: Router, private _empDiscService: empDiscService) { } ngOnIni ...

Error in Angular 5: Google Maps not defined

Having trouble implementing Google Maps on my Angular 5 app. Upon loading the view, I am encountering this error in the JavaScript console: LoginComponent_Host.ngfactory.js? [sm]:1 ERROR ReferenceError: google is not defined at LoginComponent.ngAfterVie ...

Error: An unauthorized attempt was made to modify property settings for certain users, which are designated as read-only

Within my Ionic app, there exists a specific page where users have the ability to modify information related to a particular city. What I aim to achieve is for these modifications to only be visible to other users who are also located within the same "City ...

Incorporating data from an api call to establish the starting state of a react component

I have been delving into the world of React and TypeScript while working on a fun project - a word guessing game inspired by Hangman. In this game, players have 5 chances to guess the correct word, which is retrieved from an API call. I populate an array w ...

Empty Angular-chart.js Container

How can I resolve the issue of getting a blank div and no output while trying to display a chart where the options, labels, and other data are initialized in the TypeScript controller and then used on the HTML page? I added the angular-chart.js library us ...

Leveraging Shared Modules Component across multiple modules in Angular can enhance code re

In my project structure, I have a shared folder containing shared.module.ts. Additionally, there is a modules folder with sub-modules, one of which is Dashboard.module.ts. Inside the shared module, I created a custom sidebar menu that I intend to use withi ...

Troubleshooting Next.js Mobile Freeze Issue: Unresponsive Scroll After Page Transition

Encountered a strange bug while testing my Next.js + Bootstrap demo project on mobile view. When using the burger menu to navigate to a new page on a mobile phone, attempting to scroll down causes it to stick/freeze/hang inexplicably. Despite my efforts to ...

Encountering TypeScript errors when trying to reference Angular2 within a Gulp setup

The issue at hand is: [11:16:06] TypeScript: 103 semantic errors [11:16:06] TypeScript: emit succeeded (with errors) I am currently using node v5.7.0 and npm 3.6.0 gulp -v: [11:26:58] Requiring external module babel-register [11:26:58] CLI version 3.9 ...