Product Images not loading on mobile

Topic summary

A Shopify store owner reports product images displaying as grey boxes on mobile devices, despite acceptable site speed (54/55). The issue affects product thumbnails, collection page first images, and homepage hero banners.

Root Cause Identified:
A missing closing quotation mark in the HTML class attribute within the theme code was discovered. The malformed code appeared in the image.load.liquid snippet.

Troubleshooting Steps Taken:

  • Added missing quotation mark after square{% endif %} in the class attribute
  • Fixed hanging comma in data-srcset attributes by modifying the img_set capture block
  • Adjusted code to properly format responsive image srcset values

Current Status:
Partially resolved - most images now load correctly, but the first item in each collection still shows no image on mobile (not even grey boxes). Desktop displays properly.

Additional Issues Noted:

  • Theme uses responsive images improperly (missing ‘sizes’ parameter)
  • Store running outdated theme version (2.0.4 vs current 5.0.1)
  • Concerns about losing custom modifications if updating theme
  • Another user reports identical grey box issue on iOS devices

The discussion remains open with the primary mobile image loading issue unresolved.

Summarized with AI on November 1. AI used: claude-sonnet-4-5-20250929.

We are having issues with images for products loading on mobile devices. According to the admin page of our site, site speed is around 54/55 so the site itself is not snail pace. But for some reason the images on mobile just don’t load. The thumbnails are just grey boxes, no matter how many times I refresh the page. The website is advancedacoustics-uk.com. Is there something we need to chance with the code. We’ve knocked the size of the image files down. Try to attach a screenshot but this thing won’t let me.

Any help would be appreciated

Thank you @Danishshopdev Could you tell me where in the admin panel I can turn off lazy loading?

I’ve got considerably less options than you. Will have to change the code? Could you direct me?

https://prnt.sc/oGFuY3p4qlh0

You have a problem with HTML on your product grid items.

Can you see that the “class” attribute misses closing quotation mark? You can also tell because the “src” on the next line is blue in color.

Looks like somebody has modified your theme code and missed the quote mark.

I’d start by fixing this.

Thank you Tim,

I’m confident changing the code but I am having problems finding the correct file where that code is located. Would you be able to direct me?

https://prnt.sc/H67VFYh7YF8B

I don’t have that file name but I do have this but I can’t find an error if it the correct file;

https://prnt.sc/JdAXwrgg4Jes

I think I have found the line, all the quotation marks after this line are black telling me there’s one missing? When I put a quotation mark at the end it automatically adds another as if that is in the wrong place.

class="{% if alt contains ‘3D’ %}easySpanOpacity {% endif %}{{ screen }}{% unless nopad %}nopad {% endunless %}js lazyload {% if background or swatch %}lazybackground {{ position }} {% endif %}img-align {% if img_src.aspect_ratio > 1 %}landscape{% elsif img_src.aspect_ratio < 1 %}vertical{% else %}square{% endif %} {% if image.alt contains ‘3D’ %}style=“opacity:0.3;” {% endif %}

So I have done this

class=“{% if alt contains ‘3D’ %}easySpanOpacity {% endif %}{{ screen }}{% unless nopad %}nopad {% endunless %}js lazyload {% if background or swatch %}lazybackground {{ position }} {% endif %}img-align {% if img_src.aspect_ratio > 1 %}landscape{% elsif img_src.aspect_ratio < 1 %}vertical{% else %}square{% endif %}”{% if image.alt contains ‘3D’ %}style=“opacity:0.3;” {% endif %}

However there is still no change with the grey boxes showing instead of images. Same problem is with the first picture of every collection page. Grey boxes everywhere!

Do I need to replace the code or add the code?

I’ve done that but still seem to be having the same issue

https://1drv.ms/i/s!AsSpT6bsX8y9gqYetj3CqY5Ao27PgQ?e=ABX64a

Also the first picture in every collection is greyed out

Same with the home page, the first two pictures are plain plus the hero banner is not showing.

20230406_074741919_iOS.png

Can you restore the code to its original state and change it from

square{% endif %} {% if image.alt

to

square{% endif %}" {% if image.alt

Basically this adds a quotemark, but be sure there is a space after it.

Ideally, you should share the snippet code, either here, but use an “Insert/Edit code” functionality, or use service like pastebin.

Otherwise it’s really difficult to read.

Sorry, I’ve been away for a few days. Thank you Tim, I have put the code back and done as you suggested

class="{% if alt contains '3D' %}easySpanOpacity {% endif %}{{ screen }}{% unless nopad %}nopad {% endunless %}js lazyload {% if background or swatch %}lazybackground {{ position }} {% endif %}img-align {% if img_src.aspect_ratio > 1 %}landscape{% elsif img_src.aspect_ratio < 1 %}vertical{% else %}square{% endif %}" {% if image.alt contains '3D' %}style="opacity:0.3;" {% endif %}

However I still have the issue of greyed out product images.

Hmm. They lazy load properly on my android phone.

I do not have iPhone and can only use IOS Simulator and there only the first product in collection is not loaded properly.

It may be because data-srcset properties are not 100% percent proper – they have hanging comma at the end, but I need to see the entire snippet source code to suggest anything.


I wasn’t sure how much of the code you needed to see so here is what I think is relevant.


Hmm, this code does not seem to quite match the output.

In the output above data-src looks like:

data-srcset="XXX_220x.jpg **220w 165h**,XXX_320x.jpg **320w 240h**,"

the code you shared has this

data-srcset="
{% if datawidth == false %}
  {{ img_src | img_url: img_size }} **1x**, {{ img_src | img_url: img_size, scale: 2 }} **2x**
{% else %}
  {{ **img_set** }}
{% endif %}"

So it should either output srcset in 1x/2x notation, or content of the img_set variable/snippet parameter.

The code of product.images.liquid which you’ve shared initially does not use any img_set but it’s code code for product page as far as I can see (but it does not match the actual output as well).

This is not enough code to suggest a fix.

That code was from file image.load.liquid. Again, I’m not sure how much code you want to see but here is the code from product.images.liquid

{%- assign featured_media = product.selected_or_first_available_variant.featured_media | default: product.featured_media -%}

  {% for media in product.media %}
  

    
    {% case media.media_type %}
    {% when 'image' %}
      {% if media.alt contains '3D' %}
        

            
        

      {% else %}
    
      

        {%- liquid
          render 'image.load', id: media.id, img_src: media, size: 600, alt: media.alt
        -%}
      

    

      {% endif %}
    {% when 'external_video' %}
    {{ media | external_video_tag }} 
    {% when 'model' %}
    
      {{ media | model_viewer_tag: reveal: 'interaction', toggleable: true, data-model-id: media.id, image_size: '600x600' }}
    

    
    {% when 'video' %}
    

    {{ media | video_tag: controls: true, image_size: '600x600' }}
    

    {% else %}
    {{ media | media_tag: image_size: '600x600' }}
    {% endcase %}
  

  {% endfor %}

{% if product.media.size > 1 %}

  

  {% if product.media.size > 4 %}
  
    
    
  

  {% endif %}

{% endif %}

This is product.images.liquid – a snippet used to output images on product page (not product image on collection page).

Anyway, the relevant part here is this:


   {%- liquid
      render 'image.load', id: media.id, img_src: media, size: 600, alt: media.alt
   -%}

Which means that actual tag is output by the image.load snippet.

Then we have the snippet code you’ve shared above which has the following code:

data-srcset="
{% if datawidth == false %}
  {{ img_src | img_url: img_size }} **1x**, {{ img_src | img_url: img_size, scale: 2 }} **2x**
{% else %}
  {{ **img_set** }}
{% endif %}"

Which should either output data-srcset in 1x/2x notation, which is not happens on site,
or content of the img_set variable/snippet parameter, but none of the code you’ve shared calculates this variable.
So my only guess is that this img_src is calculated somewhere in the image.load snippet but you have not shared the entire code of the snippet?

Sorry about that, I wasn’t sure how much you needed/wanted to see. Here is the entire code for image.load.liquid

{%- liquid
  assign img_size = size | append: 'x'
  capture img_height
    if img_src.width < size
      echo img_src.height
    else
      echo size | divided_by: img_src.aspect_ratio
    endif
  endcapture
  assign img_height = img_height | round
  capture img_width
    if img_src.width < size
      echo img_src.width
    else
      echo size
    endif
  endcapture
  assign img_width = img_width | round
  capture img_set
    if img_src.width < 220
      assign height = img_src.width | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: 'master' | append: ' ' | append: img_src.width | append: 'w ' | append: height | append: 'h,'
    endif    
    if size < 220
      assign height = size | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: img_size | append: ' ' | append: size | append: 'w ' | append: height | append: 'h,'
    endif    
    if background or img_src.width >= 220 and size >= 220
      assign height = 220 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '220x' | append: ' 220w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 320 and size >= 320
      assign height = 320 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '320x' | append: ' 320w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 480 and size >= 480
      assign height = 480 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '480x' | append: ' 480w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 600 and size >= 600
      assign height = 600 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '600x' | append: ' 600w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 768 and size >= 768
      assign height = 768 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '768x' | append: ' 768w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 960 and size >= 960
      assign height = 960 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '960x' | append: ' 960w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 1024 and size >= 1024
      assign height = 1024 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '1024x' | append: ' 1024w ' | append: height | append: 'h,'
    endif
    if background or img_src.width >= 1280 and size >= 1280
      assign height = 1280 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '1280x' | append: ' 1280w ' | append: height | append: 'h,'
    endif
    if background and img_src.width >= 1600
      assign height = 1600 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '1600x' | append: ' 1600w ' | append: height | append: 'h,'
    endif
    if background and img_src.width >= 1900
      assign height = 1900 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '1900x' | append: ' 1900w ' | append: height | append: 'h,'
    endif
    if background and img_src.width >= 2560
      assign height = 2560 | divided_by: img_src.aspect_ratio | round
      echo img_src | img_url: '2560x' | append: ' 2560w ' | append: height | append: 'h,'
    endif
  endcapture 
-%}

Ok, I see.

Try this – change from

endcapture 
 -%}

to

endcapture 
   assign img_src=img_src | split: "," | join: ", "
 -%}

This will remove the hanging comma.

Hopefully, it will solve the problem.

I must add that in my opinion the theme uses responsive images improperly – they do not supply the sizes parameter which means that the biggest image is always used and you may as well remove the srcset/data-srcset at all…

That seems much better however for the first item in every collection we now have no images at all showing, not even a coloured box. Desktop is all fine, the issue is still with mobile.

As for the issue with the theme they have brought out a new update but since the last update we have done a little custom work and I’m not sure how much of it we will loose such as custom add to cart colour, additional tabs in the product description, 3d images. We are on 2.0.4 and it’s now 5.0.1

Avenue Theme - Casual - Ecommerce Website Template (shopify.com)

Should really bite the bullet and get it done.

Hi I am having the same issue with product image thumbnails not loading on iphone ios and only showing grey boxes. website is luggagebase.com