1
0
Fork 0
mirror of https://git.sr.ht/~seirdy/seirdy.one synced 2024-12-24 17:52:11 +00:00

Describe dark image variants and optimized loading

This commit is contained in:
Rohan Kumar 2022-03-17 23:31:31 -07:00
parent 35b6c2eeae
commit 9098dd5d9a
No known key found for this signature in database
GPG key ID: 1E892DB2A5F84479
2 changed files with 127 additions and 0 deletions

View file

@ -275,6 +275,26 @@ If you really want to go overboard with PNG optimization, you can try a tool lik
=> https://github.com/fhanau/Efficient-Compression-Tool Efficient Compression Tool on GitHub
### Dark image variants
A "<picture>" element allows selection of sources based on any CSS media query. When images have light backgrounds, I like to include dark variants too.
```
<source
srcset=/p/dark.png
type=image/png
media="screen and (prefers-color-scheme: dark)">
<source
srcset=/p/light.png
type=image/png>
```
Requiring the "screen" media type prevents selection of dark variants when printing. Printer paper is almost always white, so dark images could waste ink. Ink waste is a sensitive issue among many students: school printers sometimes charge students who exceed a given ink quota. Ask me how I know!
Light and dark variants of legacy formats (PNG, JPG, GIF), WebP, and AVIF can cause some of my "<picture>" imagesets to have up to six image variants. I could fully automate the process using my static site generator (Hugo) if I wanted to. Since I do want to inspect each image and compress to the minimum acceptable quality, I settled for partial automation using shell scripts and a Hugo shortcode:
=> https://git.sr.ht/~seirdy/seirdy.one/tree/master/layouts/shortcodes/picture.html My shortcode for <picture> elements
## Layout
This is possibly the most subjective item I'm including, and the item with the most exceptions. Consider it more of a weak suggestion than hard advice. Use your own judgement.
@ -376,6 +396,46 @@ I address the issue by not using any SVG images on my hidden service:
=> http://wgq3bd2kqoybhstp77i3wrzbfnsyd27wt34psaja4grqiezqircorkyd.onion/ My Tor hidden service (HTTP+HTML)
## Optimal loading
Lightweight content isn't the only factor for optimizing load times. There are ways to optimize loading without a CDN.
### Blocking content
HTML is a blocking resource: images and stylesheets will not load until the user agent loads and parses the HTML that calls them. To start loading above-the-fold images before the HTML parsing finishes, send a "link" HTTP header.
My website includes a "link" header to load an SVG that serves as my IndieWeb photo and favicon:
```
link: </favicon.072dbf7bc4323646b9ee96243fbd71b2.svg>; rel=preload; as=image
```
Reducing load time is especially useful for users with unreliable connections. For much of the world, connectivity comes in short bursts during which loading time is precious. Chances of a connection failure or packet loss increase with time.
### Inline content
In addition to HTML, CSS is also a blocking resource. You could pre-load your CSS using a "link" header. Alternatively: if your CSS is under a kilobyte, consider inlining it in the <head> using a <style> element. Simply inlining stylesheets can pose a security threat, but the "style-src" CSP directive can mitigate this if you include a hash of your inline stylesheet.
You can do the same with images by using a "data:" URI; my 32-pixel PNG site icon is under 200 bytes and inlines quite nicely. On this site's hidden service, it's often the only image on a page (recall that the hidden service replaces SVGs with PNGs). Inlining this image and the stylesheet allows my hidden service's homepage to load in a single request, which is a welcome improvement given the round-trip latency that plagues onion routing implementations.
### Layout shifts
Loading content with unknown dimensions, such as images, can create layout shifts; the WICG's Layout Instability API describes the phenomenon in detail.
=> https://wicg.github.io/layout-instability/#sec-intro Layout Instability API
Avoid layout shifts by including dimensions in HTML attributes. The simplest way to do so is by including "width" and "height" values, but the "style" attribute could work too. I recommend staying away from the "style" attribute, or at least selectively allowing its use with the "style-src-attr" CSP directive.
### Other server-side tweaks
In-depth server configuration is a bit out of scope, so I'll keep this section brief.
Compression--especially static compression--dramatically reduces download sizes. My full-text RSS feed is about a quarter of a megabyte, but the Brotli-compressed version is around 70 kilobytes. Caddy supports this with a "precompressed" directive; Nginx requires a separate module:
=> https://github.com/google/ngx_brotli The ngx_brotli module
When serving many resources at once (e.g., if a page has many images), HTTP/2 could offer a speed boost through multiplexing. HTTP/3 is unlikely to help textual websites much, so run a benchmark to see if it's worthwhile.
## Non-Browsers: Reading mode
Fully standards-compliant browsers aren't the only programs people use. They also use "reading mode" tools and services.

View file

@ -240,6 +240,31 @@ If you want to include a profile photo (e.g., if your website is part of the Ind
If you really want to go overboard with PNG optimization, you can try a tool like [Efficient Compression Tool](https://github.com/fhanau/Efficient-Compression-Tool).
### Dark image variants
A `<picture>` element allows selection of sources based on any CSS media query. When images have light backgrounds, I like to include dark variants too.
<figure>
<figcaption>
A minimal example of what this could look like:
</figcaption>
```
<source
srcset=/p/dark.png
type=image/png
media="screen and (prefers-color-scheme: dark)">
<source
srcset=/p/light.png
type=image/png>
```
</figure>
Requiring the `screen` media type prevents selection of dark variants when printing. Printer paper is almost always white, so dark images could waste ink. Ink waste is a sensitive issue among many students: school printers sometimes charge students who exceed a given ink quota. Ask me how I know!
Light and dark variants of legacy formats (PNG, JPG, GIF), WebP, and AVIF can cause some of my `<picture>` imagesets to have up to six image variants. I could fully automate the process using my static site generator (Hugo) if I wanted to. Since I do want to inspect each image and compress to the minimum acceptable quality, I settled for partial automation using shell scripts and [a Hugo shortcode](https://git.sr.ht/~seirdy/seirdy.one/tree/master/layouts/shortcodes/picture.html).
Layout
------
@ -329,6 +354,48 @@ The Tor browser will download whichever format Firefox would, rather than whiche
I address the issue by not using any SVG images on [my hidden service](http://wgq3bd2kqoybhstp77i3wrzbfnsyd27wt34psaja4grqiezqircorkyd.onion/).
Optimal loading
---------------
Lightweight content isn't the only factor for optimizing load times. There are ways to optimize loading without a <abbr title="Content Delivery Network">CDN</abbr>.
### Blocking resources
HTML is a blocking resource: images and stylesheets will not load until the user agent loads and parses the HTML that calls them. To start loading above-the-fold images before the HTML parsing finishes, send a `link` HTTP header.
<figure>
<figcaption>
My website includes a `link` header to load an SVG that serves as my IndieWeb photo and favicon:
</figcaption>
```
link: </favicon.072dbf7bc4323646b9ee96243fbd71b2.svg>; rel=preload; as=image
```
</figure>
Reducing load time is especially useful for users with unreliable connections. For much of the world, connectivity comes in short bursts during which loading time is precious. Chances of a connection failure or packet loss increase with time.
### Inline content
In addition to HTML, CSS is also a blocking resource. You could pre-load your CSS using a `link` header. Alternatively: if your CSS is under a kilobyte, consider inlining it in the `<head>` using a `<style>` element. Simply inlining stylesheets can pose a security threat, but the `style-src` <abbr title="Content Security Policy">CSP</abbr> directive can mitigate this if you include a hash of your inline stylesheet.
You can do the same with images by using a `data:` URI; my 32-pixel PNG site icon is under 200 bytes and inlines quite nicely. On this site's hidden service, it's often the only image on a page (recall that the hidden service replaces SVGs with PNGs). Inlining this image and the stylesheet allows my hidden service's homepage to load in a single request, which is a welcome improvement given the round-trip latency that plagues onion routing implementations.
### Layout shifts
Loading content with unknown dimensions, such as images, can create layout shifts; the <abbr title="Web Incubator Community Group">WICG</abbr>'s <cite>[Layout Instability API](https://wicg.github.io/layout-instability/#sec-intro)</cite> describes the phenomenon in detail. Avoid layout shifts by including dimensions in HTML attributes. The simplest way to do so is by including `width` and `height` values, but the `style` attribute could work too. I recommend staying away from the `style` attribute, or at least selectively allowing its use with the `style-src-attr` CSP directive.
### Other server-side tweaks
In-depth server configuration is a bit out of scope, so I'll keep this section brief.
Compression--especially static compression--dramatically reduces download sizes. My full-text RSS feed is about a quarter of a megabyte, but the Brotli-compressed version is around 70 kilobytes. Caddy supports this with a `precompressed` directive; Nginx requires a [separate module](https://github.com/google/ngx_brotli).
When serving many resources at once (e.g., if a page has many images), HTTP/2 could offer a speed boost through multiplexing. HTTP/3 is unlikely to help textual websites much, so run a benchmark to see if it's worthwhile.
Non-Browsers: Reading mode
--------------------------