Xumulus Blog

Kill the Loader – How to Improve Your Magento 2 Product Page Load Time

I knew from the moment I laid eyes on it I hated it.  The spinny thing just sitting there making the page look oh so damn slow. Yuck!!  Surely when the images are loaded in the cache and I see a page refresh it will go away, right?  Nope. still there and still as clunky looking as ever. Oh my, how did it take me this long to try and kill it?  This is why I had to fix the Magento 2 image loader speed.

This is what it looks like in the Magento 2 Demo store.

Magento Fotorama Image loading Default via GIPHY

Now there is a lot of motion on this page and most of it does not do much good. The most offending is the image loading, instead of loading the first image it loads a spinner.  Not a great user experience if you ask me.

Now let’s take a look at what it looks like if we replace the loading image with the first one in the list.

Magento Fotorama Image loading Optimized via GIPHY

Much better!  I still think we can improve this more by trying to remove almost all motion from the page, like the breadcrumb ajax load. But we can deal with that at another time.

Now there are still a few issues with the Fotorama gallery.  It flashes when the Fotorama js applies the logic that makes the gallery come to life. We will try and work on that later. See it live here.

The Core Problem

I went looking to see if there was any solution anyone else came up with and there were none that looked interesting. We found sites that have fixed it themselves.  I also came across this in the Magento 2 GitHub issue repository. There seemed to be some misunderstanding in the thread of the core issue here. It’s basically built like this:

1. The HTML is built with a spinner gif as the primary image in the product image location in gallery.phtml.
<div class="gallery-placeholder _block-content-loading" data-gallery-role="gallery-placeholder">
    <div data-role="loader" class="loading-mask">
        <div class="loader">
            <img src="<?= /* @escapeNotVerified */ $block->getViewFileUrl('images/loader-1.gif') ?>"
                 alt="<?= /* @escapeNotVerified */ __('Loading...') ?>">
        </div>
    </div>
</div>
2. The page is loaded by the browser and loads the spinner in the page in place of a product image.
3. Javascript then fires after the page is loaded (and is competing with lots of other scripts loading)

This loads the data-gallery object which then takes setting and image data from Magento and builds the Fotorama gallery.  This is where a lot of the problems are since the HTML above is then replaced by all the gallery HTML, you can get motion, resizing and such. It also makes styling it a bit tricky as the HTML is generated in Javascript. The gallery data should be loaded into HTML not Javascript.

4. Finally when all that is complete the spinner is removed and the real images are shown (maybe after 3-8 seconds)

With other scripts competing on the page, it could take a while after the page is loaded to fully complete. Worse yet is that even if the images are cached, it sill needs to process the page build and js before the spinner goes away since it is basically loaded as the core image in step 1.

Perception and Performance Are the Same Things

Many merchants, hosting companies, and agencies spend lots of time optimizing theirs or their client’s websites for speed. The issue is that you can still have a time to first byte (TTFB) that is stellar, but the product page will load very slow because all the JavaScript has to process first. So even if you have a 50ms TTFB you are going to have 4 seconds for the spinner to disappear, and it’s going to look and feel slow.

Let’s look at Sole Society’s Magento 2 site, it has a stellar 76MS TTFB and loads the HTML in just 120MS.  Yet the image loader does not go away for 4 seconds. and there is zero improvement from the browser cache. Yuk.

Now here is Chanel Magento 2 site they opted for a huge mega resolution image. Its TTFB is about 60MS does load in about 2 seconds for me (results may vary) but it feels even faster. If you refresh the page and the image is cached and loads instantly.

Both of these sites share a very similar TTFB but the perception of speed for me was cleary with Chanel.

The Solution

The solution is to generate as much of the HTML/CSS on the server side, then when the page first builds this is loaded by the browser and then rendered almost immediately.  If you ask me this is how it should be built in the core.  And, I might add the practice around the internet of putting image loaders up in sliders, gallery and such needs to stop. It’s way out of control with WordPress plugins and the like. In this day and age, we simply need to put the intended images up and if your optimizing mobile you should just put up a smaller one.

We created a base extension that does just that to the standard Magento theme.  The problem is though that many theme vendors and agencies are going to customize the gallery.phtml and so you may still have to do some development work to override that customization. You can get our fast image load Magento 2 extension on GitHub that greatly improves the experience.  Though there are some things that make it a challenge, this will work int he Magento base theme Luma but may not in your solution, any good developer can probably figure out how to do the same in your site. (or email us)

I think this whole thing could be hugely improved in the core. We would simply need to engineer the gallery to load an image of choice first, the improve the transition when the gallery is loaded to avoid a flash. Or remove Fotorama (Magento’s image gallery plugin) altogether, with some simple HTML and a touch of JavaScript.  As a side note and the subject of another blog, we need to get the amount of JavaScrip in Magento way down, most of it is not needed.

We would love some feedback on your thoughts for a longer term fix. Comment below or send us an email.

How can you kill your loader?

Here is how you can fix your Magento 2 image loader speed.

  • If you’re a developer you can check out our git hub project.  You surely will need to make some adjustments in your theme though.
  • Email us [email protected] we are putting together a program where we can help merchants out by fixing their loader starting at about $500 US.
  • Beg your theme developer to fix the issue by sending them a link to this post
  • “But my developer said it was not possible to fix this?”  Well, they were wrong. Let us know if you need help.

Join the Movement, Kill the Loader!

As I look around at other sites, themes and trends the practice of adding image loaders are all too prevalent.  It’s bad UX! It seems someone came up with the concept as part of some widget and then everyone copied this bad construct. Over, and over and over again!!!!

Additionally with AJAX here to stay many features of pages pop in after the initial load, so pages end up with a lot of motion. That may be OK for an app, but for consumer-facing websites, you want rock solid page load time with a solid stable viewport. I get very picky on motion, we need to eliminate as much as possible, don’t push things down, over across or up.  Load the page in the viewport and it should stay as solid as possible. Motion is awkward at best but surely will kill the perception of speed as things move and change on the page, it looks incomplete (because it is) to the user.

#killtheloader

 

4 thoughts on “Kill the Loader – How to Improve Your Magento 2 Product Page Load Time

  1. I totally agree with all you said in article and I am facing same problem myself right now. Thank you for the code, I will check it right now.

    PS: Fix the link “fast image load Magento 2 extension on GitHub”

    Best regards!

  2. Your post doesn’t address the fact that this spinning issue gets progressively worse over time until the browser cache is emptied. From then on, it spins very briefly (true, could still do without the spinner altogether) and displays the image very quickly thereafter.

    Before emptying the browser, it’s banner/ajax/load/?sections which is held up according to Chrome’s networking tab. I understand it’s a cache busting, hole punching mechanism to load private user data as well as FPC cached data. For whatever reason, when the browser cache fills up, this process gets slower and slower.

    So it makes me wonder, even if we remove the spinner and hence fix the image loading part, the actual problem of a hanging AJAX call might still remain.

  3. Well maybe I should dig into why the cache flush works, I actually never tried it as I figured it was built wrong to begin with, loading the first image is the way to go, so I figured why not pursue that route. It’s built to have the spinning thing loaded at all times in the first-page load though, so no matter how fast it works you will probably see it a spin, and if you see it at all its too long for me.

    It’s ironic that you mention the ajax as we have been doing a lot of work optimizing lately and that is a huge performance bottleneck, it is a contributor to the this issue as you mention. There are several issues around the AJAX calls. One is that the PHP sessions use read locking and effectively if you have 5 AJAX calls they all will process almost sequentially (ugh). This means that if the JS on the page is dependent on the callback for the AJAX return you have to wait for it to be done for it to be run. The other is that there is 0 caching on any of them. Though that should be the case for the cart and some other ones, it should be a developer option as even putting 5 minutes on these can greatly improve the user experience. For example, a theme we use has an ajax call to load a promo message, perfect for a 1-hour cache or maybe even 5-minute cache. (And would help solve the session locking issue)

    The session issue is a difficult one and one that is problematic in M2 with its use of Ajax for private data. Here is a good write up not specific to M2 but a good one. https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.