Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

image performance #22329

Merged
merged 5 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 28 additions & 1 deletion files/en-us/learn/performance/multimedia/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,37 @@ The first thing to check is that your content images use `<img>` or `<picture>`

Secondly, with the adoption of Priority Hints, you can control the priority further by adding an `importance` attribute to your image tags. An example use case for priority hints on images are carousels where the first image is a higher priority than the subsequent images.

### Rendering strategy
### Rendering strategy: preventing jank when loading images

As images are loaded asynchronously and continue to load after the first paint, if their dimensions aren't defined before load, they can cause reflows to the page content. For example, when text gets pushed down the page by images loading. For this reason, it's critical that you set `width` and `height` attributes so that the browser can reserve space for them in the layout.

When the `width` and `height` attributes of an image are included on an HTML {{htmlelement("img")}} element, the aspect ratio of the image can be calculated by the browser prior to the image being loaded. This aspect ratio is used to reserve the space needed to display the image, reducing or even preventing a layout shift when the image is downloaded and painted to the screen. Reducing layout shift is a major component of good user experience and web performance.

Browsers begin rendering content as HTML is parsed, often before all assets, including images, are downloaded. Including dimensions enable browsers to reserve a correctly-sized placeholder box for each image to appear in when the images are loaded when first rendering the page.

![Two screenshots the first without an image but with space reserved, the second showing the image loaded into the reserved space.](ar-guide.jpg)

Without the `width` and `height` attributes, no placeholder space is created, creating a noticeable {{glossary('jank')}}, or layout shift, in the page when the image loads after the page is rendered. Page reflow and repaints are performance and usability issues.

In responsive designs, when a container is narrower than an image, the following CSS is generally used to keep images from breaking out of their containers:

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

While useful for responsive layouts, this causes jank when width and height information are not included, as if no height information is present when the `<img>` element is parsed but before the image has loaded, this CSS effectively has set the height to 0. When the image loads after the page has been initially rendered to the screen, the page reflows and repaints creating a layout shift as it creates space for the newly determined height.

Browsers have a mechanism for sizing images before the actual image is loaded. When an `<img>`, `<video>`, or `<input type="button">` element has `width` and `height` attributes set on it, its aspect ratio is calculated before load time, and is available to the browser, using the dimensions provided.

The aspect ratio is then used to calculate the height and therefore the correct size is applied to the `<img>` element, meaning that the aforementioned jank will not occur, or be minimal if the listed dimensions are not fully accurate, when the image loads.

The aspect ratio is used to reserve space only on the image load. Once the image has loaded, the intrinsic aspect ratio of the loaded image, rather than the aspect ratio from the attributes, is used. This ensures that it displays at the correct aspect ratio even if the attribute dimensions are not accurate.

While developer best practices from the last decade may have recommended omitting the `width` and `height` attributes of an image on an HTML {{htmlelement("img")}}, due to aspect ratio mapping, including these two attributes is considered a developer best practice.

For any background images, it's important you set a `background-color` value so any content overlaid is still readable before the image has downloaded.

## Conclusion
Expand Down
2 changes: 1 addition & 1 deletion files/en-us/web/api/svgimageelement/decoding/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ img.src = 'img/logo.svg';

## See also

- [\<img>: The Image Embed element](/en-US/docs/Web/HTML/Element/img)
- [`<img>`: The Image Embed element](/en-US/docs/Web/HTML/Element/img)
2 changes: 2 additions & 0 deletions files/en-us/web/html/element/img/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ This element includes the [global attributes](/en-US/docs/Web/HTML/Global_attrib

- {{htmlattrdef("height")}}
- : The intrinsic height of the image, in pixels. Must be an integer without a unit.

> **Note:** Including `height` and [`width`](#attr-width) enables the aspect ratio of the image to be calculated by the browser prior to the image being loaded. This aspect ratio is used to reserve the space needed to display the image, reducing or even preventing a layout shift when the image is downloaded and painted to the screen. Reducing layout shift is a major component of good user experience and web performance.
- {{htmlattrdef("ismap")}}

- : This Boolean attribute indicates that the image is part of a [server-side map](https://en.wikipedia.org/wiki/Image_map#Server-side). If so, the coordinates where the user clicked on the image are sent to the server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,31 @@ In general, you will use mostly the same graphical assets for different layouts

[CSS media queries](/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) allow us to serve different CSS rules dependent on viewport dimensions, and you should consider using [mobile first media queries](https://www.peachpit.com/articles/article.aspx?p=1960918) where possible. This means that the default layout before any media queries are encountered in the CSS is the small screen/mobile layout, not the wide screen/desktop layout. So when the page is loaded on a mobile device, the mobile will only download the mobile assets, and not the desktop resource assets.

Making [HTML `<img>`s](/en-US/docs/Web/HTML/Element/img) responsive is not as easy, as there is currently no native mechanism to serve different HTML images depending on context. There are a number of workarounds, but none of them are perfect right now. For an overview of what's available, read [Choosing a responsive image solution](https://www.smashingmagazine.com/2013/07/choosing-a-responsive-image-solution/).
While the pixel size of an image resource doesn't change, there are a few ways to make [HTML `<img>`s](/en-US/docs/Web/HTML/Element/img)responsive. Setting `max-width: 100%` on an image allows the image to render at its normal size when space allows, without causing pixelation, while ensuring the image never exceeds the width of its parent container. Different image files can be served depending on viewport size using the [`srcset`](/en-US/docs/Web/HTML/Element/img#attr-srcset) and [`sizes`](/en-US/docs/Web/HTML/Element/img#attr-sizes) attributes. The {{HTMLElement('picture')}} element can contain multiple {{HTMLElement('source')}} elements and one `<img>` element to offer alternative versions of an image for different display/device scenarios. Always make sure your images include alternative text by including an [`alt`](/en-US/docs/Web/HTML/Element/img#attr-alt) attribute.

## Coping with different resolutions

In this section we'll review different strategies for dealing with getting images to work across devices with different resolutions. The issue here is that raster images, when rendered on high res devices, are in danger of appearing tiny because the same number of pixels is being shown in a much smaller screen space. Most hi res devices apply a default zoom factor to the whole web page so that the content is a bit more legible, but the downside of this is that the images in question start to look pixelated and ugly because they have been zoomed in.
In this section we'll review different strategies for dealing with getting images to work across devices with different screen resolutions. The issue here is that raster images, when rendered on high res devices, are in danger of appearing tiny because the same number of pixels is being shown in a much smaller screen space. Most hi res devices apply a default zoom factor to the whole web page so that the content is a bit more legible, but the downside of this is that the images in question start to look pixelated and ugly because they have been zoomed in.

- high res and low res image copies
- : One option here is to create a hi res and a low res set of images, then use [resolution media queries](/en-US/docs/Web/CSS/resolution) to serve the hi res images only to hi res devices.
- Programmatic images
- : You should also try to use programmatic/vector graphics as much as possible, as they theoretically scale infinitely so will still look crisp at high resolutions. You could use CSS properties for generating effects like [drop shadows](/en-US/docs/Web/CSS/box-shadow), [gradients](/en-US/docs/Web/CSS/CSS_Images/Using_CSS_gradients) and [rounded corners](/en-US/docs/Web/CSS/border-radius), and you could also consider using [SVG](/en-US/docs/Web/SVG) for other UI elements, instead of raster graphics formats. The downsides here are that CSS properties and SVG don't work on old browsers such as IE6-8 (although Polyfills are available, and you could build in fallbacks), and SVG isn't suitable for high detail images, such as photographs.
- : You should also try to use programmatic/vector graphics as much as possible, as they theoretically scale infinitely so will still look crisp at high resolutions. You could use CSS properties for generating effects like [drop shadows](/en-US/docs/Web/CSS/box-shadow), [gradients](/en-US/docs/Web/CSS/CSS_Images/Using_CSS_gradients) and [rounded corners](/en-US/docs/Web/CSS/border-radius), and you could also consider using [SVG](/en-US/docs/Web/SVG) for other UI elements, instead of raster graphics formats. Raster images within SVG files do have the same issues as other image types.
- Using fonts for icons
- : Another technique to consider is using [web fonts](/en-US/docs/Web/CSS/@font-face) for icons. Text is infinitely scalable on the web, and you can also use CSS text properties to style your web font icons, such as [text-shadow](/en-US/docs/Web/CSS/text-shadow) and [color](/en-US/docs/Web/Guide/CSS/Getting_started/Color). Making your own font file can be a bit fiddly, but there are a number of good icon font services available.
- : Another technique is [web fonts](/en-US/docs/Web/CSS/@font-face) for icons. Text is infinitely scalable on the web, and you can also use CSS text properties to style your web font icons, such as [`text-shadow`](/en-US/docs/Web/CSS/text-shadow) and [`color`](/en-US/docs/Web/Guide/CSS/Getting_started/Color). Unfortunately, icon fonts are not by default accessible. If the user uses their own font, such as with the Dyslexia extension, your icons may not show. Additionally, every icon needs to be nested in an element that provides it with an accessible name, such as with [`aria-label`](/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label).

## Interactive images

If your images need to feature some level of interactivity, such as links, other clickable areas, or animation, there are a number of options available.

- CSS
- : As well as adding programmatic graphical effects to links (and anywhere else you might want them), CSS also allows you to write declarative [animations](/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) and [transitions](/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions). These may not be supported in older browsers like IE6-8, but they generally degrade gracefully, are fairly easy to write, and become much more flexible and powerful when combined with JavaScript and other technologies.
- : As well as adding programmatic graphical effects to links (and anywhere else you might want them), CSS also allows you to write declarative [animations](/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) and [transitions](/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions).
- JavaScript
- : [JavaScript](/en-US/docs/Web/JavaScript) has functions that enable developers to create animations, and any other type of interactivity you want. It is very powerful when combined with other technologies, although its complexity is a barrier for non-developers.
- : [JavaScript](/en-US/docs/Web/JavaScript) has functions that enable developers to create effects based on interactions. It is very powerful when combined with other technologies, although its complexity is a barrier for non-developers.
- SVG
- : [SVG](/en-US/docs/Web/SVG), just like [HTML](/en-US/docs/Web/HTML)/[CSS](/en-US/docs/Web/CSS/), can be manipulated via JavaScript. So adding interactivity is not difficult. You can also add links directly into SVG and can create animations using [SMIL](/en-US/docs/Web/SVG/SVG_animation_with_SMIL) (Synchronized Multimedia Integration Language).
- : [SVG](/en-US/docs/Web/SVG), just like [HTML](/en-US/docs/Web/HTML)/[CSS](/en-US/docs/Web/CSS/), can be manipulated with CSS and via JavaScript. So adding interactivity is not difficult. You can also add links directly into SVG and can create animations using [SMIL](/en-US/docs/Web/SVG/SVG_animation_with_SMIL) (Synchronized Multimedia Integration Language).
- WebGL/Canvas

- : You can create a canvas to draw interactive graphics on using the HTML \<canvas> element, then use the Canvas API to create shapes, lines, import image files, create text, do compositing operations, and much more. Standard JavaScript can then be used to animate the image output, etc. You can create 2D imagery using the regular 2D canvas context, or 3D imagery using the more nascent [WebGL API](/en-US/docs/Web/API/WebGL_API).
- : You can create a canvas to draw interactive graphics on using the HTML {{HTMLElement('canvas')}} element, then use the Canvas API to create shapes, lines, import image files, create text, do compositing operations, and much more. Standard JavaScript can then be used to animate the image output, etc. You can create 2D imagery using the regular 2D canvas context, or 3D imagery using the more nascent [WebGL API](/en-US/docs/Web/API/WebGL_API).

Canvas is very powerful, but it needs to be used with caution. It is good for the visuals of games and complex data visualizations, but for standard user interface elements it is not very efficient. In addition, Canvases are just raster images, so the text created inside them is not accessible, plus they don't scale well.
Canvas is very powerful, but it needs to be used with caution. It is good for the visuals of games and complex data visualizations, but for standard user interface elements it is not very efficient and completely inaccessible to screen reader users. Canvases are just raster images, so the text created inside them is not accessible. Also, they don't scale well.