splide icon indicating copy to clipboard operation
splide copied to clipboard

Bad cumulative layout shift (CLS) with lazyloading enabled

Open Dekadinious opened this issue 2 years ago • 2 comments

Checks

  • [X] Not a duplicate.
  • [X] Not a question, feature request, or anything other than a bug report directly related to Splide. Use Discussions for these topics: https://github.com/Splidejs/splide/discussions

Version

v4.1.3

Description

There seems to be a case of a large cumulative layout shift in the Splide-slider when lazyloading images. The height of the images is not reserved. We are changing all our Slick-sliders to Splide, but this is kind of a deal breaker. The height and width of the images should be reserved so that lazy loading works without cumulative layout shifts and with padding set on the slider.

Reproduction Link

https://jsfiddle.net/Dekadinious/29d5mtr1/1/

Steps to Reproduce

Create a lazy-loaded slider with a lot of images. Flick fast through the slides. Observe the flash of unstyled content. If added to a page with a lot of other elements, you should also see the cumulative layout shift happening.

The fiddle I have linked to is loading the images very fast, but you can clearly see the text visible and then getting pushed down when flicking fast through the slides. It is very apparent with large layout shifts in our staging environment. The whole slider increases in height and pushes other content down as soon as the first image is loaded.

Expected Behaviour

I would expect the slider to reserve the height and width of the image so no layout shift happens.

Dekadinious avatar Feb 08 '23 15:02 Dekadinious

@Dekadinious

If your use case allows it, a workaround for now is to set the width and height for the item images through CSS (with breakpoint definitions).

If the images are not 'fixed' sizes for various use cases with multiple instances of the slider, then this of course won't work as intended.

MartinHaun avatar Feb 10 '23 10:02 MartinHaun

I ended up using CSS aspect-ratio since I have access to the images width and height.

const mostVerticalMediaAspectRatio = images.reduce((acc, m) => {
    const itemAspectRatio = m.width / (m.height || 1)
    return acc > itemAspectRatio ? itemAspectRatio : acc
}, 1)

return (
  <Splide
    ref={mainRef}
    options={{
      type: 'loop',
      rewind: true,
      pagination: false,
      gap: '2rem'
    }}
    className="align-middle [&_#splide01-list]:items-center"
    style={{ aspectRatio: mostVerticalMediaAspectRatio.toString() }}
  >
    {images.map(m => {
      return (
        <SplideSlide key={m.src} className="flex justify-center">
          <Image
            width={m.width}
            height={m.height}
            className="h-full w-full object-contain object-center"
            src={m.src}
            alt={`image for ${title}`}
          />
        </SplideSlide>
      )
    })}
  </Splide>
)

magoz avatar Jul 16 '23 14:07 magoz