Ghost: Add lazy loading for images

Created on 29 Oct 2013  路  13Comments  路  Source: TryGhost/Ghost

Makes sense for posts with a lot of images...

Most helpful comment

Sorry to comment on such an old issue @ErisDS but I think this probably falls under "can only be achieved via core". Why?

  • Lazy loading is not something that writers/editors should have to worry about. Ideally, the _theme_ should decide what should be lazy loaded and what should not. This is especially true because _handling_ the load of those images will then fall to the theme. It's no good a customer installing an editor extension which implements the HTML mutation side, if the theme isn't equipped to take it from there.
  • The theme currently doesn't have any power on the server-render to modify {{content}}.
  • Modifying the HTML in the browser via JS isn't feasible, since you can't do it early enough.

The use case here is pretty clear: if you use Lighthouse to assess a site which has pages with many images, you get immediately heavily dinged since they clog up the request pipeline and slow the site down. Here's Google's "audit details" for Offscreen Images.

So what is the best way to achieve this?

As an example of one theme approach: In something like Shopify's Liquid, they'd possibly be able to use inline filters.

I think the best approach would be to give themes the power to string-modify {{content}}. You could do this a few ways (e.g. provide a mechanism for themes to set up their own Handlebars helpers - probably a bad idea though) but I'd suggest either a generic string-replace (possible third party library here) or a specific flag to content which moves image src/srcset attributes to data- attributes.

I can submit an example PR for the last approach and see what you think. Any other suggestions super-welcome!

All 13 comments

If you want to raise a concern or make a feature request, please provide a little more information.

In this case: what images, where, and why?

I'm thinking this is possibly a duplicate of #1031

Sorry, thought the term "lazy load" was clear enough.

I mean that images in a post get loaded as you scroll down (as a visitor, not editor).

Reference Project: https://github.com/tuupola/jquery_lazyload

In that case, you're talking about something that would be implemented by themes, not by Ghost itself. If you wanted to get that feature into the default theme then that's something you could make a case for over on the Casper repository.

I looked at that already, but I have to alter the img-tag to implement it and I can't find a way to edit/modify a post via a theme. All I can do is output it via the content-helper.

Thanks for the help.

You would do this easily using Javascript and a library such as jQuery with a lazyload helper. http://www.appelsiini.net/projects/lazyload This certainly would not be a core-Ghost issue.

:+1: @BiosElement That's one hell of a customizable setup!

This library is amazing! But I guess it can't be added in Ghost in current state.
All the image url attributes should be replaced by "data-original" and a class named "lazy" should also be added.
Is there a way, actually to "override" the way image tags are displayed without editing core files and breaking the upgrade path?

@MCKLMT Unfortunately no, there is no way to change this without changing core at present.

Is it possible to add this feature in the backlog? I think it could be nice to introduce this in Ghost to reduce the weight of the page at first load.

@MCKLMT You can always suggest it via our wishlist, but I don't think it really suits Ghost core - rather it would become possible when we add extensibility to the editor via apps.

Sorry to comment on such an old issue @ErisDS but I think this probably falls under "can only be achieved via core". Why?

  • Lazy loading is not something that writers/editors should have to worry about. Ideally, the _theme_ should decide what should be lazy loaded and what should not. This is especially true because _handling_ the load of those images will then fall to the theme. It's no good a customer installing an editor extension which implements the HTML mutation side, if the theme isn't equipped to take it from there.
  • The theme currently doesn't have any power on the server-render to modify {{content}}.
  • Modifying the HTML in the browser via JS isn't feasible, since you can't do it early enough.

The use case here is pretty clear: if you use Lighthouse to assess a site which has pages with many images, you get immediately heavily dinged since they clog up the request pipeline and slow the site down. Here's Google's "audit details" for Offscreen Images.

So what is the best way to achieve this?

As an example of one theme approach: In something like Shopify's Liquid, they'd possibly be able to use inline filters.

I think the best approach would be to give themes the power to string-modify {{content}}. You could do this a few ways (e.g. provide a mechanism for themes to set up their own Handlebars helpers - probably a bad idea though) but I'd suggest either a generic string-replace (possible third party library here) or a specific flag to content which moves image src/srcset attributes to data- attributes.

I can submit an example PR for the last approach and see what you think. Any other suggestions super-welcome!

Also, the wishlist you posted appears to be down. Is it discontinued?

In the meantime, for anyone else reading this: here's a solution which goes part of the way - with some obvious drawbacks:

<div class="content" id="truncated-content">
  {{content words="100"}}
</div>

<noscript id="full-content">
  {{content}}
</noscript>

<script>
  const fullHTML = document.getElementById('full-content').textContent;
  const lazyLoadedHTML = fullHTML
        .replace(/<img(.*?) srcset="/gi, '<img$1 data-srcset="')
        .replace(/<img(.*?) src="/gi, '<img$1 data-src="');
  document.getElementById('truncated-content').innerHTML = lazyLoadedHTML;
</script>

This outputs the first paragraph or two - intentionally, so that before the script runs, the page layout happens - and drops the entire content into a <noscript> tag. Synchronously with the HTML load, the script then retrieves that content, does some regexes to move src and srcset to data- attributes, and then replaces the truncated content with the lazyloaded real content.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HenryMarshall picture HenryMarshall  路  4Comments

RadoslavGatev picture RadoslavGatev  路  3Comments

rishabhgrg picture rishabhgrg  路  3Comments

ArthurianX picture ArthurianX  路  4Comments

kirrg001 picture kirrg001  路  3Comments