Skip to main content

Tagged “images”

Testing the 11ty Image plugin

I’m testing out the Eleventy Image plugin. Here’s a post with an image which, if all goes well, will be converted by the plugin from source jpeg into lightweight avif and webp formats and the underlying code transformed from a basic img element into comprehensive modern HTML image syntax.

A photo of the sign at the entrance to La Petite Garoupe restaurant, Antibes. The letters are in neon and the sign is surrounded by flowers.
Entrance sign at La Petite Garoupe restaurant, Antibes

My new syntax for modern, responsive blog images

I’ve started trialling different HTML and technologies for the “simple” responsive images (i.e. not art-directed per breakpoint) used in blog articles on this site. I’m continuing to lean on Cloudinary as my free image host, CDN and format-conversion service. But at the HTML level I’ve moved from a complicated <img srcset> based approach that includes many resized versions of the same image. I now use a simpler <picture> and <source> based pattern that keeps the number of images and breakpoints low and instead – by using the source element’s type attribute – takes advantage of the performance gains offered by the new avif and webp image formats.

My new approach is based on advice in Jake Archibald’s brilliant article Halve the size of images by optimising for high density displays. Jake explains that the majority of your traffic likely consists of users with high density screens so when we can combine optimising for that and making performance gains in a progressively enhanced way, we should!

Jake offers a “lazy but generally good enough” approach:

Here's the technique I use for most images on this blog: I take the maximum size the image can be displayed in CSS pixels, and I multiply that by two, and I encode it at a lower quality, as it'll always be displayed at a 2x density or greater. Yep. That's it. For 'large' images in blog posts like this, they're at their biggest when the viewport is 799px wide, where they take up the full viewport width. So I encode the image 1,598 pixels wide.

<picture>
  <source type="image/avif" srcset="red-panda.avif" />
  <source type="image/webp" srcset="red-panda.webp" />
  <img src="red-panda.jpg" width="1598" height="1026" alt="A red panda" />
</picture>

So, if you want your images to be as sharp as possible, you need to target images at the user's device pixels, rather than their CSS pixels. To encode a 2x image, I throw it into Squoosh.app, and zoom it out until it's the size it'll be displayed on a page. Then I just drag the quality slider as low as it'll go before it starts looking bad.

Taking Jake’s guidance and tweaking it for my Cloudinary-based context, my recent post April 2022 mixtape included its image like so:

<figure>
  <picture>
    <source type="image/avif" srcset="https://res.cloudinary.com/…/f_avif,q_auto,w_1292/v1654433393/mato_1500_squooshed_mozjpg_xjrkhl.jpg" />
    <source type="image/webp" srcset="https://res.cloudinary.com/…/f_webp,q_auto,w_1292/v1654433393/mato_1500_squooshed_mozjpg_xjrkhl.jpg" />
      <img class="u-full-parent-width" src="https://res.cloudinary.com/…/f_jpg,q_auto,w_1292/v1654433393/mato_1500_squooshed_mozjpg_xjrkhl.jpg" width="1292" height="1292" alt="Side A of the 7-inch vinyl release of Mato’s “Summer Madness" loading="lazy" decoding="async" />
  </picture>
  <figcaption>Mato’s “Summer Madness”, as featured on the mix</figcaption>
</figure>

And my process was as follows:

  1. Take a photo (for me, that’ll be on my phone). Without doing anything special it’ll already be wide enough.
  2. Apple use the HEIC format. To get around that, do: Share, Copy, open Files > HEIC to JPG, paste and it’ll save as JPG.
  3. Drop it into Squoosh and do the following:
  • rotate it if necessary
  • resize it to 1300 wide (in my current layout 1292 is twice as wide (2 × 646) as the image would need to go, and I just round up to 1300)
  • reduce its quality a bit (stopping before it gets noticeably bad)
  1. Encode that as a mozjpg which gave the best size reduction and as far as I can tell, is a safe approach to use.
  2. Upload to my Cloudinary account then copy its new Cloudinary URL.
  3. Prepare the image HTML per the above snippet. The first source tells Cloudinary to use format avif, while for the second source it’s webp, and for the fallback img it’s jpg.
  4. Check the rendered image in a browser to confirm that the modern formats are being used.

I’ll DRY-up that HTML into an 11ty shortcode in due course.

I’ve no doubt that I’ll be getting some of this wrong – this stuff gets pretty complicated! For example I note my image file size is still quite large so I wonder if I should be manually creating the avif and webp versions in Squoosh myself to ensure getting the savings that make this approach worthwhile, rather than handing the conversion off to Cloudinary. (However this would mean having to host more images…)

In the meantime however, I’m happy that this approach has simplified the mental overhead of handling modern, responsive blog images, and optimising it can be a work in progress.

Additional references

Avoiding img layout shifts: aspect-ratio vs width & height attributes (on Jake Archibald's blog)

Recently I’ve noticed some developers recommending using the CSS aspect-ratio property directly on images. My understanding of aspect-ratio was that it’s not so much intended for elements like img which already have an intrinsic aspect ratio, but rather for the likes of div which do not. Furthermore, when the goal is to prevent the layout shift that can occur after an image loads we should supply our images with width and height HTML attributes rather than using CSS.

In this timely post, Jake helpfully explains how width and height attributes are used by CSS as presentation hints to automatically set an aspect-ratio that will also, in cases where the attributes were set wrongly, fall back to the image’s intrinsic aspect ratio. Therefore, concentrating on HTML alone is ideal for our content images. My previous approach seems sound but I now know a little more about why.

If I'm adding an image to an article on my blog, that's content. I want the reserved space to be the aspect ratio of the content. If I get the width and height attributes wrong, I'd rather the correct values were used from the content image. Therefore, width and height attributes feel like the best fit. This means I can just author content, I don't need to dip into inline styles.

If it's a design requirement that the layout of an image is a particular aspect ratio, enforcing that with aspect-ratio in CSS can be appropriate. For example, a hero image that must be 16 / 9 – if the image isn't quite 16 / 9 I don't want it messing up my design, I want the design to take priority. Although, if the image isn't actually that aspect ratio, it'll either end up stretched (object-fit: fill), letter-boxed (object-fit: contain), or cropped (object-fit: cover). None of which are ideal.

Improving alternative text for images

Some colleagues at work have recently been asking interesting questions about “good/appropriate alternative text for images”. I definitely reckon it’s a topic worth revisiting because it feels like the landscape has changed a bit on this front over the years.

I think the web design industry has traditionally been:

  1. lacking knowledge of how to write good alternative text.
  2. too quick to decide which images are “purely decorative”, or accurately described by a matter-of-fact short label when maybe they actually should convey their inherent tone and emotion to all users rather than only those with no visual impairments.

But as inclusion-centric practioners we can probably do better. In his blog post Writing great alt text Jake Archibald breaks down the considerations. I reckon it’d be useful for us to dissect this post and try to boil it down to some practical rules-of-thumb for our teams.

But also, I’ve just noticed a couple of interesting developments at the big players. Firstly, Twitter have upped their image alt game and are encouraging their users to try doing so, too.

And hot on the heels of Twitter’s announcement, I now see in Slack an Edit file details option for adding image descriptions. It’s great that Twitter and Slack are doing this… and also serves as a reminder that tools such as Slack and Twitter are consumed on the web and so accessible best practices apply when you’re writing content on them, too!

Learn Responsive Design (on web.dev)

Jeremy Keith’s new course for Google’s web.dev learning platform is fantastic and covers a variety of aspects of responsive design including layout (macro and micro), images, icons and typography.

Images on the Web: The Big Picture, Part 1

In modern web development there are a myriad ways to present an image on a web page and it can often feel pretty baffling. In this series I step through the options, moving from basic to flexible images; then from modern responsive images to the new CSS for fitting different sized images into a common shape. By the end I’ll arrive at a flexible, modern boilerplate for images.

Scope

This article is primarily about the HTML img element (and related markup). I might mention CSS background images at some point, but by and large I’m focusing on images as content rather than decoration.

Similarly I probably won’t mention icons at all. I see them as a separate concern and recommend you use inline SVG rather than any image-based approach.

Terminology

Replaced element

The image element is a replaced element which means that the element is replaced by the resource (file) referenced in its src attribute.

Aspect Ratio

You get an image’s aspect ratio by dividing its width by its height.

A 160px wide × 90px tall image can be represented as 16:9, or 1.777.

Aspect Ratio is an intrinsic characteristic of an image—i.e. it is “part of the image”—therefore outside of our control as developers. We can apply extrinsic settings which change the dimensions of the rendered image on our web page, however its aspect ratio was determined when the image was originally created and cropped.

Assumptions

CSS-wise, assume that we’ll start with nothing more complex than the following boilerplate:

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

img {
  border-style: none;
  display: block;
}

A basic image

Let’s start by going back to basics. I can include an image on a web page like so:

<img src="/img/250x377.jpg" alt="A Visit… by Jennifer Egan" />

Note that our markup contains no width or height attributes, just an alt for accessibility. With no size-related attributes (and in the absence of any CSS acting on its width or height) the image simply displays at its intrinsic dimensions i.e. the dimensions at which the file was saved, in this case 250 × 377 pixels. The image is output as follows:

“A Visit from the Goon Squad“ by Jennifer Egan

Now I know that narrow and static images like this feel pretty old-school. Since the Responsive Web Design movement we’re more accustomed to seeing full-column-width media and complex markup for intelligently selecting one file from many options.

However I still occasionally encounter use cases for displaying a relatively narrow image as-is.

Sticking with the book image example, given its aspect ratio you probably wouldn’t want it to be full-column-width on anything other than the narrowest screens simply because of how tall it could become at the expense of the reading experience. You might also be loading your images from a third party bookshop with which you have an affiliate scheme, and therefore have little control over file size and other factors influencing performance and responsive behaviour. As such you might do well to keep things simple and just load a sensibly-sized thumbnail.

See also this figure illustrating a simple database schema on the Ruby on Rails Tutorial website. On wide viewports, the author’s preference is to simply display the image at its natural, small size and centre it rather than blowing it up unnecessarily.

In summary, there remain times when you might need a narrow, fixed-size image so I want to keep that option open.

Include size attributes

When we know the dimensions of our image in advance, we can improve upon our previous markup by explicitly adding the width and height attributes.

<img src="/img/250x377.jpg" width="250" height="377" alt="" />

Don’t expect fireworks; this renders the image exactly as before.

“A Visit from the Goon Squad“ by Jennifer Egan

However, this addition allows the browser to reserve the appropriate space in the page for the image before it has loaded. If we don’t do this, we risk a situation where text immediately after our image renders higher up the page than it should while the image is loading, only to shift jarringly after the image loads.

We’re not overriding width or height with CSS (remember CSS rules would trump HTML attributes because attributes have no specificity) so the browser will render the image at whatever size attribute values we provide, regardless of the image’s intrinsic dimensions. As such, to avoid squashing and distortion we would ensure that our size attribute values matched the image’s real dimensions.

Flexible Images

At the dawn of the mobile web, many authors sought to handle mobile devices by creating a separate, dedicated mobile website. However this meant duplication of cost, code, content and maintenance. Responsive Web Design provided a counterpoint with a “create once, publish everywhere” philosophy which embraced the fluidity of the web and suggested we could serve desktop and mobile devices alike from a single codebase.

RWD proposed making layout and content adaptable. This included the idea of flexible images—that for any given image you need just a single, wide version plus some clever CSS to enable it to work not only on desktop but also to adapt its size for narrower contexts and still look good.

By default when a wide image is rendered within a narrower container it will overflow that container, breaking the layout. The key to avoiding this is to set a tolerance for how wide the image is permitted to go. Generally, we’ll tolerate the image being 100% as wide as its container but no wider. We can achieve this using max-width.

<img src="/img/wide.png" alt="" />
img {
  max-width: 100%;
}

The eagle-eyed will have noticed that the above snippet once again excludes the HTML width and height attributes. That’s because when we began working responsively many of us stopped adding those size attributes, feeling that for flexible images the practice was redundant. The image’s dimensions were now a moving target so the space needing reserved by the browser while the image loaded was variable rather than fixed. And we were right: for a long time, browsers were not capable of reserving space for a moving target, so including the size attributes served no real purpose.

Regardless, some content management systems (most notably Wordpress) continued to output images with HTML width and height attributes as standard. This introduced a challenge. Without the attributes we could rely on the browser to take our simple max-width:100% declaration and also implicitly apply height:auto thereby always preserving the image‘s aspect ratio when scaling it down. To achieve the same goal when the HTML height attribute is present, we needed the following revised CSS:

img {
  max-width: 100%;
  height: auto;
}

Here’s an example of a flexible image. It’s 2000 pixels wide, but shrinks to fit inside its narrower parent. Magic!

Jank-free responsive images

There’s been a recent development wherein modern browsers can now reserve appropriate space for flexible images while they are loading (rather than only for fixed images).

This means that adding the width and height attributes is once again a good idea.

If you know the image’s aspect ratio in advance, you can now use any combination of width and height attribute values which represent that ratio, and the browser will dynamically calculate and reserve the appropriate required space in the layout while the image loads, once again avoiding those jarring layout shifts I mentioned before.

However this presents a couple of challenges.

Firstly, having the height HTML attribute once again means that for any image we want flexibly scaled and safely constrained by CSS max-width, we’ll also need to override that explicit height attribute value with CSS.

Secondly, having the width attribute can be problematic when the image is one which we explicitly want to be full-container-width, such as the featured image in a blog post. The problem arises when the width attribute value is less than the containing element’s current width. If the only CSS you have on your image is max-width:100% then the image will adopt the value from its width attribute and consequently be narrower than its parent, ruining the effect. One approach might be to always use a sufficiently high width value but that feels a tad brittle; I’d rather employ a solution that is more explicit and decisive.

To solve both of the above challenges, we can apply some additional CSS.

  /*
  Ensure correct aspect ratio is preserved when
  max-width: 100% is triggered and image
  has the HTML height attribute set,
  while doing no harm otherwise.
  */
img[height] {
  height: auto;
}

  /*
  Optional class to make an image 100% container-width.
  Overrides the 'width' attribute, avoiding the risk of the image
  being too narrow because its width value is narrower than the container.
  When using this try to ensure your image’s intrinsic width is at least as
  wide as its container’s maximum width because otherwise on wide
  viewports the image would stretch and the results might not be great.
  */
.u-full-parent-width {
  width: 100%;
}

Pros and cons of the “one large image” approach

I’d like to quickly take stock.

Let’s say we have a source image which is 1200px wide. Let’s also say that it’s the featured image for a blog post and therefore will be placed in our main content column, and that this column is never wider than 600px.

If we make the image flexible using max-width:100%, it’ll work on wide viewports and narrow viewports (such as a mobile phone) alike.

On the plus-side, we only need to create one image for our blog post and we’re done.

Another positive is that on devices with retina screens—capable of displaying a comparatively greater density of pixel information in the same physical space—our oversized image will appear at higher quality and look great.

On the downside, we are delivering a much larger image and therefore file size than is required for, say, a 320px wide context. This has performance implications since bigger files mean longer download times, and this is exacerbated when the device is not connected to high-speed wifi (as is often the case with a mobile phone).

Another issue which is perhaps less obvious is that your content may not be read on your website with your CSS operating on it. For example if your website has an RSS feed (like mine does) then someone may well be reading your article in another environment (such as a feed reader application or website) and who is to say how that oversized image will look there?

Dealing with these challenges using modern Responsive Images will be the subject of Part #2.

References

A First Look at aspect-ratio (on CSS-Tricks)

Chris Coyier takes the new CSS aspect-ratio property for a spin and tests how it works in different scenarios.

Note that he’s applying it here to elements which do not have an intrinsic aspect-ratio. So, think a container element (div or whatever is appropriate) rather than an img. This is line with a Jen’s Simmons’ recent replies to me when I asked her whether or not we should apply aspect-ratio to an img after she announced support for aspect-ratio in Safari Technical Preview 118.

A couple of interesting points I took from Chris’s article:

  • this simple new means of declaring aspect-ratio should soon hopefully supersede all the previous DIY techniques;
  • if you apply a CSS aspect-ratio to an element which has no explicit width set, we still get the effect because the element’s auto (rendered) width is used, then by combining that with the CSS aspect-ratio the browser can calculate the required height, then apply that height;
  • if the content would break out of the target aspect-ratio box, then the element will expand to accommodate the content (which is nice). If you ever need to override this you can by applying min-height: 0;
  • if the element has either a height or a width set, the other of the two is calculated from the aspect ratio;
  • if the element has both a height and width set, aspect-ratio is ignored.

Regarding browser support: at the time of writing aspect-ratio is supported in Chrome and Edge (but not IE), is coming in Firefox and Safari, but as yet there’s no word regarding mobile. So I’d want to use it as a progressive enhancement rather than for something mission critical.

Breaking Out With CSS Grid Layout (on cloudfour.com)

While bookmarking the mastery.games article yesterday, I started getting the feeling that something was awfully familiar. It was! I’ve seen this layout before – from Tyler Sticka back in 2017 to be precise – but failed to bookmark it at the time.

Here, then, is the original and still the best CSS Grid “article with breakout images” layout!

I particularly love the way that, by naming the lines and appending -start and -end as appropriate you can then target the area between those lines using its short name.

.Prose {
  display: grid;
  grid-template-columns: 
    [full-start] minmax(1em, 1fr) 
    [main-start] minmax(0, 40em) [main-end]
    minmax(1em, 1fr) [full-end];
}

.Prose > * {
  grid-column: main;
}

.Prose-splash {
  grid-column: full;
}

Bustle

Here’s a beautiful, magazine style website design for digital publication Bustle. The typography, use of whitespace, responsive layout, menu pattern, colour palette and imagery are all on point!

Modern CSS Solutions

Modern CSS Solutions for Old CSS Problems

Stephanie Eckles with a beautifully presented series of articles on how to use modern CSS to tackle some of the enduring challenges of web development including dropdown navigation, centring and styling buttons.

Jank-free Responsive Images

Here’s how to improve performance and prevent layout jank when browsers load responsive images.

Since the advent of the Responsive Web Design era many of us, in our rush to make images flexible and adaptive, stopped applying the HTML width and height attributes to our images. Instead we’ve let CSS handle the image, setting a width or max-width of 100% so that our images can grow and shrink but not extend beyond the width of their parent container.

However there was a side-effect in that browsers load text first and images later, and if an image’s dimensions are not specified in the HTML then the browser can’t assign appropriate space to it before it loads. Then, when the image finally loads, this bumps the layout – affecting surrounding elements in a nasty, janky way.

CSS-tricks have written about this several times however I’d never found a solid conclusion.

Chrome’s Performance Warning

The other day I was testing this here website in Chrome and noticed that if you don’t provide images with inline width and height attributes, Chrome will show a console warning that this is negatively affecting performance.

Based on that, I made the following updates:

  1. I added width and height HTML attributes to all images; and
  2. I changed my CSS from img { max-width: 100%; } to img { width: 100%; height: auto; }.

NB the reason behind #2 was that I found that that CSS works better with an image with inline dimensions than max-width does.

Which dimensions should we use?

Since an image’s actual rendered dimensions will depend on the viewport size and we can’t anticipate that viewport size, I plumped for a width of 320 (a narrow mobile width) × height of 240, which fits with this site’s standard image aspect ratio of 4:3.

I wasn’t sure if this was a good approach. Perhaps I should have picked values which represented the dimensions of the image on desktop.

Jen Simmons to the rescue

Jen Simmons of Mozilla has just posted a video which not only confirmed that my above approach was sound, but also provided lots of other useful context.

Essentially, we should start re-applying HTML width and height attributes to our images, because in soon-to-drop Firefox and Chrome updates the browser will use these dimensions to calculate the image’s aspect ratio and thereby be able to allocate the exact required space.

The actual dimensions we provide don’t matter too much so long as they represent the correct aspect ratio.

Also, if we use the modern srcset and sizes syntax to offer the browser different image options (like I do on this site), so long as the different images are the same aspect ratio then this solution will continue to work well.

There’s no solution at present for the Art Direction use case – where we want to provide different aspect ratios dependent on viewport size – but hopefully that will come along next.

I just tested this new feature in Firefox Nightly 72, using the Inspector’s Network tab to set “throttling” to 2G to simulate a slow-loading connection, and it worked really well!

Lazy Loading

One thing I’m keen to test is that my newly-added inline width and height attributes play well with loading="lazy". I don’t see why they shouldn’t and in fact they should in theory all support each other well. In tests so far everything seems good, however since loading="lazy" is currently only implemented in Chrome I should re-test images in Chrome once it adds support for the new image aspect ratio calculating feature, around the end of 2019.

Native lazy-loading for the web

Now that we have the HTML attribute loading we can set loading="lazy" on our website’s media, and the loading of non-critical, below-the-fold media will be deferred until the user scrolls to them.

This can really improve performance so I’ve implemented it on images and iframes (youtube video embeds etc) throughout this site.

This is currently only supported in Chrome, but that still makes it well worth doing.

Cloudinary

Cloudinary is a very handy tool for image and video upload, storage, optimisation and CDN.

Store, transform, optimize, and deliver all your media assets with easy-to-use APIs, widgets, or user interface.

This was brought to my attention by Jason Grigsby at An Event Apart. We were discussing his article series on Responsive Images and I asked if he could recommend a tool which auto-generated all of the images you needed for your responsive image code, if you provide a single source image.

I’ve been trying Cloudinary out and so far, so good.

(via @grigs)

See all tags.

External Link Bookmark Note Entry Search