image icon indicating copy to clipboard operation
image copied to clipboard

Image size detection for CSR

Open farnabaz opened this issue 4 years ago • 5 comments
trafficstars

Detecting image size has benefits on server-side rendering and prevent CLS for server-rendered pages. But it seems tricky and inefficient when it comes to client-side rendering.

  • As fetch API is a non-blocker for page rendering, fetching resolution on the client-side cannot prevent layout shifting. It highly depends on the network, and it needs to make an additional request.

  • Having a server middleware for resolution does not support full static generation. We should fallback to client-side size detection if the server is disabled

/cc @Atinux @pi0

farnabaz avatar Nov 27 '20 15:11 farnabaz

Current state:

  • The logic of auto is happening on the server-side it simply falls back to width="auto" attribute of img tag in client-side rendering
  • Since we don't use resolution on the client-side we can drop resolution middleware and use getMeta without additional HTTP request on server

farnabaz avatar Nov 29 '20 12:11 farnabaz

Is there any solution so the <img> tag includes width and height attributes?

retroriff avatar Apr 08 '21 12:04 retroriff

Would love this as well!

stuible avatar Aug 21 '21 20:08 stuible

Any updates on this feature request? This is absolutely essential for modern web development, IMO.

stuible avatar Oct 01 '21 02:10 stuible

I've come up with a interim solution for statically generated Nuxt sites. It's kind of terrible but it does work (Isn't this always the case?). I require a node library called image-size (after checking to make it's running server side and NOT client side) that reads the images dimensions and stores them in an array which Nuxt serializes and makes available to the client once generated.


async asyncData({ $content, params }) {

    const images = await $content('images').fetch();

    // generate array of image dimensions
    const dimensions = [];

    if (process.server) {
      const sizeOf = require('image-size');
      images.forEach((image) => {
        console.log(image);
        const sizeOfResult = image ? sizeOf(`static${image}`) : {};
        dimensions.push({
          ...sizeOfResult,
          slug: image,
        });
      });
    }

     return {
          images,
          dimensions
     } 
}

I can then access these dimensions in my template like so:

<nuxt-picture
       :src="image[0]"
       :width="dimensions.find(x => x.slug == image[0]).width"
       :height="dimensions.find(x => x.slug == image[0]).height"
     />

One important caveat: since the Nuxt dev server runs asyncData() on the client side when you navigate between routes, the width and height will not be populated when developing. They will however, be populated on your statically generated, production site. A fresh load of the webpage while developing will also load the correct dimensions.

stuible avatar Oct 14 '21 07:10 stuible