TIL minimal responsive image component
POSTED ON:
Today, a image tag can look like this:
<img
src="small-image.png"
alt="A description of the image."
width="300"
height="200"
loading="lazy"
decoding="async"
srcset="small-image.png 1x, medium-image.png 2x, large-image.png 3x"
/>
My lord, look at those attributes!
So when I saw that JS frameworks made image wrapper components (like Nuxt was with <nuxt-img>
), I was blown away and wanted this power at work.
What is it?
<nuxt-img>
is a drop-in replacement for the native <img>
tag:
- Uses built-in provider to optimize local and remote images
- Converts src to provider optimized URLs
- Automatically resizes images based on width and height
- Generates responsive sizes when providing sizes option
- Supports native lazy loading as well as other
<img>
attributes
via https://image.nuxtjs.org/components/nuxt-img
A minimal, multi-framework, responsive image component #
How do we do it better?
This blog post: A minimal, multi-framework, responsive image component
This component does the following:
- using srcset to deliver multiple resolutions for different device and screen sizes
- using sizes so that the browser knows which image resolution to download
- delivering modern image formats such as AVIF and WebP if the browser supports them
- ensuring that the image resizes responsively, maintaining aspect ratio
- avoids layout shift when the images has loaded
- use native lazy-loading and async decoding for offscreen images
- use high priority fetching for critical images
- supports placeholders for lazy-loaded images
Here's the vue version:
<script setup lang="ts">
import { Image } from "@unpic/vue";
</script>
<template>
<Image
src="https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg"
layout="constrained"
width="800"
height="600"
alt="A lovely bath"
/>
</template>
That generates:
<img
alt="A lovely bath"
loading="lazy"
decoding="async"
sizes="(min-width: 800px) 800px, 100vw"
style="object-fit: cover; max-width: 800px; max-height: 600px; aspect-ratio: 1.33333 / 1; width: 100%;"
srcset="
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=1080&height=1440 1080w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=1280&height=1707 1280w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=1600&height=2133 1600w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=640&height=853 640w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=750&height=1000 750w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=800&height=1067 800w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=828&height=1104 828w,
https://cdn.shopify.com/static/sample-images/bath.jpeg?crop=center&width=960&height=1280 960w
"
src="https://cdn.shopify.com/static/sample-images/bath.jpeg?width=800&height=600&crop=center"
/>
Related TILs
Tagged: component