Snug Gallery / Guides

Does a photo gallery slow down your Shopify store?

How a 40-image gallery affects LCP, CLS and page weight on Shopify, what Snug Gallery does about each, and the one placement mistake that undoes all of it.

A gallery is the heaviest thing most Shopify pages carry. Forty photos at a few hundred kilobytes each is more data than the rest of the page combined, so it is a fair question to ask before adding one: what does this do to my speed score? The answer depends almost entirely on how the images are requested, not how many there are. This guide explains which of Google's Core Web Vitals a gallery can hurt, how Snug Gallery handles each of them, and the one placement decision that matters more than any setting.

The three numbers Google actually measures

Google's Core Web Vitals are three metrics, each judged at the 75th percentile of real visits. Largest Contentful Paint (LCP) is how long the biggest thing in the first screen takes to appear; good is 2.5 seconds or less. Cumulative Layout Shift (CLS) measures how much the page jumps around while loading; good is 0.1 or less. Interaction to Next Paint (INP) measures how quickly the page responds to a tap or click; good is 200 milliseconds or less. Those are the thresholds on web.dev at the time of writing. You may have seen articles claiming Google tightened LCP to two seconds in 2026; we checked, and Google's own documentation still says 2.5. Be wary of speed advice that starts from a number Google has not published.

A gallery can hurt all three, but in very different ways. It hurts LCP if one of its images is the largest element in the first screen and that image loads late. It hurts CLS if tiles appear without reserved space and push the page down as they arrive. It hurts INP if the script that runs the lightbox or filters is heavy or blocks the main thread. Total page weight, the number people usually worry about, is not a Core Web Vital at all; it matters, but only through its effect on the three above.

Weight: request the size you display

The biggest saving in any gallery is not sending a 2400-pixel image to a tile that is 300 pixels wide. Snug Gallery renders every image through Shopify's image_url and image_tag filters, which means the browser is offered six candidate widths, from 320 to 1600 pixels, and picks the smallest that covers the space it has. That choice depends on the sizes attribute, and this is where most gallery apps are lazy: they declare 100vw for every image, so the browser assumes each tile is full-width and downloads far more than it draws.

Snug calculates sizes per layout. A grid with four desktop columns tells the browser each tile is a quarter of the viewport above 990 pixels, a third or a half on tablets, and whatever the mobile column count gives below that. Row layouts, where widths follow aspect ratios, get a per-image share of the viewport. Slider tiles are 100vw because they really are. Collage tiles that span two columns say so. A phone rendering a two-column grid therefore fetches 320- or 480-pixel files, not the 1600 it would be sent by a gallery that declares 100vw. The 1600-pixel version is used only where it is needed, in the lightbox, and the lightbox fetches an even larger 2048-pixel file on demand when a shopper opens it, then preloads the neighbour so swiping does not stall.

Files are served from Shopify's CDN in whatever format the browser accepts, so a JPEG upload arrives as WebP or AVIF where supported without you converting anything. Our guide on Shopify Files versus app-hosted images covers why that hosting choice also matters for reliability. The one thing the CDN cannot fix is an upload that is enormous to begin with: it will be resized, but the 1600-pixel lightbox version is still derived from your original, so uploading at around 2000 pixels on the long edge is plenty.

Layout shift: reserve the space before the pixels arrive

Layout shift is what happens when an image tag has no idea how tall it will be, the browser lays out the page with a zero-height box, and then everything below jumps down when the file arrives. A gallery of forty images with no reserved space can produce a CLS score several times the threshold on its own. Snug Gallery writes each image's aspect ratio into the tile as a CSS variable, along with the original width and height as data attributes, so the browser knows the exact shape of every tile from the first layout pass. Grid and collage layouts additionally fix a ratio per gallery from the block setting, so tiles are uniform whether or not the photos are. The result is that a Snug gallery reserves its full height before a single image has loaded, and CLS from the gallery itself is effectively zero.

The remaining source of shift is web fonts in captions, which is a theme matter rather than a gallery one. If captions jump when the font swaps in, the fix is in the theme's font loading settings, not in the gallery block.

Interaction: how much script a gallery needs

Snug Gallery's storefront script is about 10 kilobytes minified and has no dependencies: no jQuery, no slider library, no analytics beacon. It handles the carousel controls and the lightbox, and it is loaded by Shopify as part of the theme app extension, once per page no matter how many galleries are on it. The tag filter bar and the shoppable product cards are separate small files that only load on galleries that use those features. Nothing is fetched from our servers, which is the reason a Snug gallery keeps working if our app is ever offline; the guide on gallery apps that stop working when their script host does explains why that matters. For INP the relevant fact is simpler: a few kilobytes of plain script that attaches a couple of click handlers does not block the main thread in any measurable way.

LCP: the placement decision that matters most

Here is the part that most gallery advice skips. Every image in a Snug gallery carries loading="lazy", which means the browser defers downloading it until it is about to scroll into view. For a gallery halfway down a page that is exactly right: forty images cost nothing until the shopper reaches them, and the page above loads as if the gallery were not there. Shopify's own theme performance guidance, though, is blunt about the exception: never lazy-load the LCP image. If the largest element in the first screen is lazy-loaded, the browser waits until layout is done and an intersection observer fires before it even requests the file, and Shopify's performance team measured pages that make this mistake as roughly three seconds slower on LCP.

So the question to ask is whether your gallery is the first thing on the page. If it sits under a banner, a heading and a paragraph, its first row is probably not the LCP element and lazy loading is a pure win. If the gallery is the hero, the first row is the LCP candidate and it is being deferred. In that situation you have two honest options: put a theme image banner above the gallery, which becomes the LCP element and loads eagerly because Shopify's image_tag defaults to eager for the first sections of a page; or accept a slower LCP on that page in exchange for the gallery being the first thing shoppers see. We would rather tell you the trade-off than pretend the setting has no cost.

Checking your own gallery page

  1. Open the page with the gallery in Chrome, right-click, choose Inspect, and open the Network tab with the Img filter. Reload. Scroll slowly and watch images appear in the list only as you reach them; that is lazy loading working. Note the size column: on a laptop with a four-column grid, tiles should be a few tens of kilobytes each, not hundreds.
  2. Click any gallery image request and look at its URL. Shopify's CDN puts the requested width in the address, and it should be one of 320, 480, 640, 960, 1280 or 1600, matching roughly the pixel width of the tile on your screen. If every image is 1600 on a phone, the sizes attribute is wrong, which on a Snug gallery would be a bug worth telling us about.
  3. Run the page through PageSpeed Insights. Read the LCP element it names under the diagnostics. If it is a gallery tile, the gallery is your hero and the placement section above applies. If it is a banner or heading, the gallery is not on the critical path.
  4. Check the CLS breakdown in the same report. A Snug gallery should not appear in the list of shifting elements. If it does, check whether the block's aspect ratio setting is set to natural on a masonry layout with very tall images; switching to a fixed ratio removes the last possible source of shift.
  5. Test on a real phone over mobile data, not just the emulator. Scroll to the gallery and watch the tiles fill in. A brief grey box before each image is the reserved space doing its job; a page that jumps is not.
  6. If the gallery is the first section and LCP matters for that page, add the theme's image banner above it in the editor with one strong photo, then re-run PageSpeed. That single change typically moves LCP more than anything you can do inside the gallery.

What we chose not to do

There are speed tricks Snug Gallery deliberately does not use. It does not swap image URLs into data-src attributes for a JavaScript lazy loader, because that hides the URL from the browser's preload scanner and is slower than the native loading attribute in every modern browser. It does not inline a low-quality blurred placeholder in the HTML, which adds weight to every page to save a fraction of a second on one. It does not preconnect to or load anything from a third-party domain. And it does not load the lightbox image until a shopper opens the lightbox, because most shoppers never do.

The guiding idea is that a gallery should cost the page nothing until a shopper reaches it, and then cost exactly what the screen in front of them needs. Shopify's CDN, the native loading attribute and a correct sizes calculation get you almost all the way there. The last piece, deciding what sits at the top of the page, is yours.

Frequently asked questions

Will adding a photo gallery hurt my Shopify speed score?

Not if the gallery lazy-loads images, reserves their space and requests sizes that match the tiles, which Snug Gallery does. Images below the first screen cost nothing until the shopper scrolls to them. The exception is a gallery placed as the very first thing on the page, where its first row becomes the largest element and lazy loading delays it; put a banner above it or accept the trade-off.

Does Snug Gallery lazy-load images?

Yes. Every gallery image uses the browser's native loading attribute set to lazy, with six responsive widths from 320 to 1600 pixels and a sizes value calculated for the layout and column count. The lightbox image is only fetched when a shopper opens it. There is no JavaScript lazy-loading library and no third-party script.

How large should I upload gallery images for Shopify?

Around 2000 pixels on the long edge is enough. Shopify's CDN produces the smaller widths automatically and serves modern formats such as WebP where the browser supports them. Larger originals do not make the gallery sharper, since the lightbox uses at most a 2048-pixel version, and they slow down your own uploads and Files storage.

Why does PageSpeed Insights say my gallery image is the LCP element?

Because the gallery is the largest thing visible before scrolling, usually when it is the first section on the page. Lazy-loaded images are deferred, so an LCP image inside a gallery loads later than it could. Add an image banner or heading section above the gallery so a different, eagerly loaded element becomes the LCP candidate.

More guides