AleksandrHovhannisyan / aleksandrhovhannisyan.com

My online resume and blog, created with 11ty, Sass, and JavaScript.
https://aleksandrhovhannisyan.com/
109 stars 26 forks source link

Creating an Accessible Image Carousel #166

Open AleksandrHovhannisyan opened 2 years ago

sandersu commented 1 year ago

Hi Alexander,

Firstly, great article. There was only one thing I found that wasn't correct in your article.

For improved performance, I’m also using the loading="lazy" attribute to enable native lazy loading, which defers loading images that aren’t currently visible. Once we enable overflow scrolling with CSS in a future section, this will defer loading images that are overflowing horizontally beyond the carousel’s client window.

By setting loading=lazy, all images with this attribute will be loaded later. This should only be applied to images that are offscreen.

Therefore, if you are using the carousel in the first view, this attribute should only be set on the + 4th images. Otherwise it will also defer the loading of images 1, 2 & 3.

Your scroll snap problem is probably also caused by this.

Regards,

Sander van Surksum

AleksandrHovhannisyan commented 1 year ago

@sandersu Thanks for the feedback!

I didn't want to get into the details of how loading="lazy" works to keep the article focused, but to clarify: Browsers use a certain threshold from the viewport to detect whether an image should be loaded into view. You can find the thresholds for Chrome in this article: https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds. This also applies to scroll containers.

If the carousel is in view on page load and you inspect the network tab, you should see that only the first two images or so get requested (the bottom two images in the following screenshot):

Inspecting network requests for a page load, with a horizontal image carousel in view. Only two images are requested.

Once you scroll the carousel, the remaining images get requested:

Inspecting network requests for a page load, with a horizontal image carousel in view that has been scrolled to the right. Two additional images are requested.

sandersu commented 1 year ago

@sandersu Thanks for the feedback!

I didn't want to get into the details of how loading="lazy" works to keep the article focused, but to clarify: Browsers use a certain threshold from the viewport to detect whether an image should be loaded into view. You can find the thresholds for Chrome in this article: https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds. This also applies to scroll containers.

If the carousel is in view on page load and you inspect the network tab, you should see that only the first two images or so get requested (the bottom two images in the following screenshot):

Inspecting network requests for a page load, with a horizontal image carousel in view. Only two images are requested.

Once you scroll the carousel, the remaining images get requested:

Inspecting network requests for a page load, with a horizontal image carousel in view that has been scrolled to the right. Two additional images are requested.

The problem lies in the fact that the browser has to detect whether an image is in the viewport, which takes time. Because the browser has to wait until the IntersectionObserver is available.

Generally, do not lazy load images images visible in the viewport

See this comparison between lazy in viewport vs non lazy in viewport.

https://www.webpagetest.org/video/compare.php?tests=220817_BiDc5N_9MT%2C220817_AiDcGV_9PB&thumbSize=200&ival=100&end=visual

Also see https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport

AleksandrHovhannisyan commented 1 year ago

Generally, do not lazy load images images visible in the viewport

@sandersu Yup, this is a good point! I had to do that at one point on my own site because Lighthouse was flagging it (LCP images were lazily loaded). If you have control over your carousel (i.e., users aren't uploading dynamic images), and you have control over where on a page it is positioned, it's definitely worth taking this into consideration.

shyke commented 1 year ago

Hi Alexander Thanks for the wonderful article. It helped me a lot. I can't seem to find any way to set the initial scrolLeft value on the scrolable container (this.scrollContainer). The value always stays 0 (RTL), no matter how I set the value in the class. The only solution I could find for it was to change the value in the window.load event listener. However, the result is that the gallery scrolls upon load. This isn't what I want. Can you please explain how to set the scrollable position of the gallery to the center in the class constructor ?

AleksandrHovhannisyan commented 1 year ago

@shyke I should've probably clarified this in the article, but scrollLeft is a bit of a misnomer in the DOM. It should really be called scrollStart. In RTL, scrollLeft will be 0 if the container has not been scrolled. Once you start scrolling, the values increase in magnitude but will be negative. I'd recommend taking a look at the CodePen demo linked in the article: https://codepen.io/AleksandrHovhannisyan/pen/zYRVoeb.

shyke commented 1 year ago

Thanks for the replay. I probably didn't explain my self right, I understand the concept of the scroll left value is 0 on RTL. The thing I couldn't manage to solve is how to set the gallery scrolle position to the center before load (on the class constrocter) . Let say I have 3 images so image number 2 should be in the center of the scrollable container. The only way I manage to that is to listen to window load event and change the scroller position programmatically but the scroll is visible to the user so that isn't a good solution.

Another example can be that your gallery on the codepen load with the dear ( photo number 5 ) on the center of the scrollable container.

Again thank you so much for your article

On Thu, Dec 29, 2022, 6:28 PM Aleksandr Hovhannisyan < @.***> wrote:

@shyke https://github.com/shyke I should've probably clarified this in the article, but scrollLeft is a bit of a misnomer in the DOM. It should really be called scrollStart. In RTL, scrollLeft will be 0 if the container has not been scrolled. Once you start scrolling, the values increase in magnitude but will be negative. I'd recommend taking a look at the CodePen demo linked in the article: https://codepen.io/AleksandrHovhannisyan/pen/zYRVoeb.

— Reply to this email directly, view it on GitHub https://github.com/AleksandrHovhannisyan/aleksandrhovhannisyan.com/issues/166#issuecomment-1367447282, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFI3O7TWWRCDMJKJH4KCFTWPW32RANCNFSM5ZT5NTSQ . You are receiving this because you were mentioned.Message ID: <AleksandrHovhannisyan/aleksandrhovhannisyan.com/issues/166/1367447282@ github.com>

AleksandrHovhannisyan commented 1 year ago

@shyke Oh, I see. I don't think it's possible to programmatically center the carousel on a particular image initially without the user noticing. There's no CSS solution for this that I know of, so you'd need to scroll to that image on window load like you said.

Pooja22singh commented 10 months ago

Hey @AleksandrHovhannisyan Great article!!, I was wondering since you followed the approach of disabling the previous next buttons , How would you change the solution to adapt a continous scroll, ie on last image click it scrolls to first and vice-versa

AleksandrHovhannisyan commented 10 months ago

@Pooja22singh I wouldn't recommend taking that approach, as it could confuse users who normally expect the next button to take them to the next image (e.g., an image to the right).