From cc59c9abf01c3d1e7af7129fc3b0f024e69f8d39 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Fri, 29 Apr 2022 17:42:23 -0700 Subject: [PATCH] More about APCA, RCWN, allow-same-origin, typos --- content/posts/website-best-practices.gmi | 30 +++++++++++++++-------- content/posts/website-best-practices.md | 31 +++++++++++++++--------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/content/posts/website-best-practices.gmi b/content/posts/website-best-practices.gmi index 541548c..3d956c7 100644 --- a/content/posts/website-best-practices.gmi +++ b/content/posts/website-best-practices.gmi @@ -6,7 +6,7 @@ This is a "living document" that I add to as I receive feedback. This is also a somewhat long read; for a summary, skip everything between the table of contents and the conclusion. -I realize not everybody's going to ditch the Web and switch to Gemini or Gopher today (that'll take, like, a month at the longest). Until that happens, here's a non-exhaustive, highly-opinionated list of best practices for websites that focus primarily on text. I don't expect anybody to fully agree with the list; nonetheless, the article should have *some* useful information for any web content author or front-end web developer. +I realize not everybody's going to ditch the Web and switch to Gemini or Gopher today (that'll take, like, a month at the longest). Until that happens, here's a non-exhaustive, highly-opinionated list of best practices for websites that focus primarily on text. I don't expect anybody to fully agree with the list; nonetheless, the article should have at least some useful information for any web content author or front-end web developer. My primary focus is inclusive design: @@ -78,7 +78,7 @@ sandbox allow-same-origin => https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox "sandbox" CSP directive on MDN -While "script-src" restricts script loading, "sandbox" can also restrict script execution with stronger defenses against script injection (e.g. by a browser add-on).¹ I added the "allow-same-origin" parameter so that these add-ons will still be able to function.² +While "script-src" restricts script loading, "sandbox" can also restrict script execution with stronger defenses against script injection (e.g. by a browser add-on).¹ I added the "allow-same-origin" parameter so that signed scripts (e.g. from add-ons) will still be able to function.² If you're able to control your HTTP headers, then use headers instead of a tag. In addition to not supporting certain directives, a CSP in a tag might let some items slip through: @@ -102,7 +102,7 @@ Finally, consider using your CSP to restrict script loading. If you must use inl Third-party content will complicate the CSP, allow more actors to track users, possibly slow page loading, and create more points of failure. Some privacy-conscious users actually block third-party content: while doing so is fingerprintable, it can reduce the amount of data collected about an already-identified user. -Some web developers deliver resources using a third-party content delivery network (CDN), such as jsDelivr or Unpkg. Traditional wisdom held that doing so would allow different websites to re-use cached resources; however, all mainstream browsers engines now partition their caches to prevent this behavior: +Some web developers deliver resources using a third-party content delivery network (CDN), such as jsDelivr or Unpkg. Traditional wisdom held that doing so would allow different websites to re-use cached resources; however, all mainstream browser engines now partition their caches to prevent this behavior: => https://privacycg.github.io/storage-partitioning/ @@ -146,7 +146,9 @@ Furthermore: a high number of cached resources can decrease performance of the c => https://simonhearne.com/2020/network-faster-than-cache When Network is Faster than Cache -The effect is especially pronounced on low-end phones and mechanical hard drives. +The effect is especially pronounced on low-end phones and mechanical hard drives. Firefox calls this feature "Race Cache With Network": + +=> https://bugzilla.mozilla.org/show_bug.cgi?id=1358038 Bug 1358038: Add "Race Cache With Network" status to netmonitor One way to help browsers decide which disk-cached resources to prioritize is to use immutable assets. Include the `immutable` directive in your cache-control headers, and cache-bust modified assets by changing their URLs. You can also keep your asset counts low by combining textual assets (e.g. CSS) and inlining small resources. @@ -348,7 +350,7 @@ Using containment for content at the end of the page is relatively safe. Using i In-page search (e.g., using "Ctrl + f") has been a basic feature in document readers well before browsers, and continues to be an essential feature today. -Searchability is a good reason to reason to prefer conveying information textually, when possible: video (especially without accurate captions), pictures of text, etc. aren't so easily searchable. +Searchability is a good reason to prefer conveying information textually, when possible: video (especially without accurate captions), pictures of text, etc. aren't so easily searchable. Web pages that hide content behind "show content" widgets are difficult to search through: users need to toggle "show content" for each item they wish to search. Often, in-page search highlights are hidden; Reddit's atrocious redesign is a serious offender. If you need to hide some content for performance reasons, I described a less hostile way to do so in the "other ways to defer content" section. @@ -582,7 +584,7 @@ The Web version of this page is an example application of Technique C25 and the The Web version of this page only uses non-default colors when a user agent requests a dark color scheme (using the "prefers-color-scheme" CSS media query; see the next subsection) and for lightening borders. Any image with a solid background may match the page background; to ensure that their dimensions are clear, I surrounded them with borders. I also set a custom color for the borders and ensure that the image backgrounds don't match the border colors. I included borders to break up some sections, since heading-based delineation is either unavailable or insufficient for them. When overriding color schemes or disabling CSS altogether, the page layout remains clear. -Color overrides go well beyond simple foreground and background color changes. Windows' High Contrast Mode (WHCM) is perhaps the best example. WHCM makes advanced modifications to color palettes: it colors elements with a user-specified palette, all according to semantic markup while ignoring ARIA overrides. Since WHCM sets colors independent of explicitly-defined ARIA roles, it's a good way to test adherence to the First Rule of ARIA (see the "Split elements and posessive hyperlinks" sub-section of the "Screenreader improvements" section). +Color overrides go well beyond simple foreground and background color changes. Windows' High Contrast Mode (WHCM) is perhaps the best example. WHCM makes advanced modifications to color palettes: it colors elements with a user-specified palette, all according to semantic markup while ignoring ARIA overrides. Since WHCM sets colors independently of explicitly-defined ARIA roles, it's a good way to test adherence to the First Rule of ARIA (see the "Split elements and posessive hyperlinks" sub-section of the "Screenreader improvements" section). > Win HCM is a collection of user defined color themes that overwrite your definitions in CSS. > It’s not about design but readability. @@ -649,13 +651,19 @@ If you use JavaScript: avoid setting colors, especially dark-mode colors, using ### Contrast is complex -When setting colors, especially for a dark background, I recommend checking your page's contrast using Advanced Perceptual Contrast Algorithm (APCA) values. You can do so in an online checker or Chromium's developer tools (you might have to enable them in a menu for experimental preferences. +When setting colors, especially for a dark background, I recommend checking your page's contrast using Accessible Perceptual Contrast Algorithm (APCA) values. You can do so in an online checker or Chromium's developer tools (you might have to enable them in a menu for experimental preferences. I recommend using the web app. -=> https://www.myndex.com/APCA/simple Online ACPA Contrast Calculator +=> https://www.myndex.com/APCA/ Online ACPA Contrast Calculator + +The APCA takes several factors into account: + +* The human retina has few blue-sensitive cone cells, so blue appears "darker" than green and red. Yellow appears brightest. +* Small, thin fonts are difficult to see and require greater contrast. +* It's possible to have too much contrast, especially for large/bold text (note that the APCA version built into Chromium does not yet take this into account). Blue and purple links on a black background have much worse perceptual contrast than yellow or green links. -Note that the APCA isn't fully mature as of early 2022. Until version 3.0 of the WCAG is ready, pages should also conform to the contrast ratios described in the WCAG 2.2's success criteria 1.4.3 (Contrast: Minimum, level AA) or 1.4.6 (Contrast: Enhanced, level AAA). This site's dark-mode stylesheet is an example of a palette that conforms to both the WCAG 2.2 AAA contrast requirements and APCA recommendations. +Note that the APCA isn't fully mature as of early 2022. Until version 3.0 of the WCAG is ready, pages that need to comply with the WCAG should also conform to the contrast ratios described in the WCAG 2.2's success criteria 1.4.3 (Contrast: Minimum, level AA) or 1.4.6 (Contrast: Enhanced, level AAA). This site's dark-mode stylesheet is an example of a palette that conforms to both the WCAG 2.2 AAA contrast requirements and APCA recommendations. => https://yatil.net/blog/wcag-3-is-not-ready-yet WCAG 3 is not ready yet @@ -726,7 +734,7 @@ For lossy compression, I typically use GNU Parallel to mass-generate images usin => https://squoosh.app Squoosh -You also might want to use the HTML element, using JPEG/PNG as a fallback for more efficient formats such as WebP or AVIF, but only if the size savings are more significant than a couple hundred bytes. +You also might want to use the HTML element, using JPEG/PNG as a fallback for more efficient formats such as WebP or AVIF, but only if the size savings (or quality improvements at a similar size) are significant. => https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture docs on MDN @@ -981,6 +989,8 @@ I already covered the first option in the prior subsection. If you expect viewer The best compromise is to ensure that the image isn't too wide, and can support large text on a narrow viewport. Lines of text in images should contain as few characters as possible. For a good exmple, see the "In defense of link underlines" section. +If the text needs to be readable, check its contrast; see the prior "contrast is complex" section. At large sizes, the contrast shouldn't be too high; at small sizes, it shouldn't be too low. + ### Indented elements Most browser default stylesheets were not optimized for narrow viewports, so narrow-viewport optimization is one of few good reasons to override the defaults. The best example of widescreen bias in browser stylesheets is indentation. diff --git a/content/posts/website-best-practices.md b/content/posts/website-best-practices.md index 927d6e8..79f9a20 100644 --- a/content/posts/website-best-practices.md +++ b/content/posts/website-best-practices.md @@ -34,7 +34,7 @@ This is a "living document" that I add to as I receive feedback. See the updated Intro­duction {#introduction} ----------------- -I realize not everybody's going to ditch the Web and switch to Gemini or Gopher today (that'll take, like, a month at the longest). Until that happens, here's a non-exhaustive, highly-opinionated list of best practices for websites that focus primarily on text. I don't expect anybody to fully agree with the list; nonetheless, the article should have _some_ useful information for any web content author or front-end web developer. +I realize not everybody's going to ditch the Web and switch to Gemini or Gopher today (that'll take, like, a month at the longest). Until that happens, here's a non-exhaustive, highly-opinionated list of best practices for websites that focus primarily on text. I don't expect anybody to fully agree with the list; nonetheless, the article should have at least some useful information for any web content author or front-end web developer. My primary focus is [inclusive design](https://100daysofa11y.com/2019/12/03/accommodation-versus-inclusive-design/). Specifically, I focus on supporting _under­represented ways to read a page_. Not all users load a page in a common web-browser and navigate effortlessly with their eyes and hands. Authors often neglect people who read through accessibility tools, tiny viewports, machine translators, "reading mode" implemen­tations, the Tor network, printouts, hostile networks, and uncommon browsers, to name a few. I list more niches in [the conclusion](#conclusion). Compatibility with so many niches sounds far more daunting than it really is: if you only selectively override browser defaults and use plain-old, semantic HTML (POSH), you've done half of the work already. @@ -73,7 +73,6 @@ JavaScript and WebAssembly are responsible for the bulk of modern web exploits. default-src 'none'; img-src 'self' data:; style-src 'sha256-HASH'; -style-src-attr 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'; @@ -84,7 +83,7 @@ sandbox allow-same-origin {{}} -`default-src: 'none'` implies `script-src: 'none'`, causing a compliant browser to forbid the loading of scripts. Furthermore, the `sandbox` CSP directive forbids a [wide variety of risky actions](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox). While `script-src` restricts script loading, `sandbox` can also restrict script execution with stronger defenses against script injection (e.g. by a browser add-on).[^1] I added the `allow-same-origin` parameter so that these add-ons will still be able to function.[^2] +`default-src: 'none'` implies `script-src: 'none'`, causing a compliant browser to forbid the loading of scripts. Furthermore, the `sandbox` CSP directive forbids a [wide variety of risky actions](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox). While `script-src` restricts script loading, `sandbox` can also restrict script execution with stronger defenses against script injection (e.g. by a browser add-on).[^1] I added the `allow-same-origin` parameter so that signed scripts (e.g. from add-ons) will still be able to function.[^2] If you're able to control your HTTP headers, then use headers instead of a `` tag. In addition to not supporting certain directives, a CSP in a `` tag might let some items slip through. @@ -118,7 +117,7 @@ Finally, consider using your CSP to restrict script loading. If you must use inl Third-party content will complicate the CSP, allow more actors to track users, possibly slow page loading, and create more points of failure. Some privacy-conscious users actually block third-party content: while doing so is fingerprintable, it can reduce the amount of data collected about an already-identified user. Avoid third-party content, if at all possible. -Some web developers deliver resources using a third-party content delivery network (CDN), such as jsDelivr or Unpkg. Traditional wisdom held that doing so would allow different websites to re-use cached resources; however, all mainstream browsers engines now [partition their caches](https://privacycg.github.io/storage-partitioning/) to prevent this behavior. +Some web developers deliver resources using a third-party content delivery network (CDN), such as jsDelivr or Unpkg. Traditional wisdom held that doing so would allow different websites to re-use cached resources; however, all mainstream browser engines now [partition their caches](https://privacycg.github.io/storage-partitioning/) to prevent this behavior. If you must use third-party content, use [subresource integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) (check the [SRI specification](https://www.w3.org/TR/SRI/)). This prevents alteration without your consent. If you wish to be extra careful, you could use SRI for first-party resources too. @@ -153,7 +152,7 @@ The browser cache is a valuable tool to save bandwidth and improve page speed, b Out of privacy concerns, most browsers no longer re-use cached content across sites; refer back to the [section on third-party content](#third-party-content) for more details. Privacy-conscious users (including all users using "private" or "incognito" sessions) will likely have their caches wiped between sessions. -Requesting a high number of cached resources can decrease performance of the cache, causing browsers to [bypass the cache](https://simonhearne.com/2020/network-faster-than-cache/). The effect is especially pronounced on low-end phones and mechanical hard drives. +Requesting a high number of cached resources can decrease performance of the cache, causing browsers to [bypass the cache](https://simonhearne.com/2020/network-faster-than-cache/). The effect is especially pronounced on low-end phones and mechanical hard drives. Firefox calls this feature "Race Cache With Network", documented in [Bug 1358038](https://bugzilla.mozilla.org/show_bug.cgi?id=1358038). One way to help browsers decide which disk-cached resources to prioritize is to use immutable assets. Include the `immutable` directive in your `cache-control` headers, and cache-bust modified assets by changing their URLs. You can also keep your asset counts low by combining textual assets (e.g. CSS) and inlining small resources. @@ -382,7 +381,7 @@ In-page search In-page search (e.g., using Ctrl + f) has been a basic feature in document readers well before browsers, and continues to be an essential feature today. -Searchability is a good reason to reason to prefer conveying information textually, when possible: video (especially without accurate captions), pictures of text, etc. aren't so easily searchable. +Searchability is a good reason to prefer conveying information textually, when possible: video (especially without accurate captions), pictures of text, etc. aren't so easily searchable. Web pages that hide content behind "show content" widgets are difficult to search through: users need to toggle "show content" for each item they wish to search. Often, in-page search highlights are hidden; [Reddit's atrocious redesign](#reddit-redesign) is a serious offender. If you need to hide some content for performance reasons, I described a less hostile way to do so in [the "other ways to defer content" section](#other-ways-to-defer-content). @@ -613,7 +612,7 @@ Chris also describes the importance of visited link colors in [VisitedLink
-This is an unreadable screenshot of a [website promoting browser style overrides](http://bettermotherfuckingwebsite.com/) (specifically, the "A little less contrast" section). I had set my browser foreground and background colors to white and dark gray, respectively. The website overrode the foreground colors while assuming that everyone browses with a white background. +This is an unreadable screenshot of a [website promoting browser style overrides](http://bettermotherfuckingwebsite.com/). I had set my browser foreground and background colors to white and dark gray, respectively. The website overrode the foreground colors while assuming that everyone browses with a white background.
{{< /transcribed-image-figure >}} @@ -688,9 +687,15 @@ I personally like a foreground and background of `#eee` and `#0e0e0e`, respectiv Color is a nuanced topic that deserves more attention than current guidelines give. -When setting colors, especially for a dark background, I recommend checking your page's contrast using Advanced Perceptual Contrast Algorithm (APCA) values. You can do so in an [online checker](https://www.myndex.com/APCA/) (requires JavaScript) or Chromium's developer tools (you might have to enable them in a menu for experimental preferences). Blue and purple links on a black background have much worse perceptual contrast than yellow or green links. +When setting colors, especially for a dark background, I recommend checking your page's contrast using Accessible Perceptual Contrast Algorithm (APCA) values. You can do so in an [online checker](https://www.myndex.com/APCA/) (requires JavaScript) or Chromium's developer tools (you might have to enable them in a menu for experimental preferences). I recommend using the web app. -Note that [the APCA isn't fully mature](https://yatil.net/blog/wcag-3-is-not-ready-yet) as of early 2022. Until version 3.0 of the WCAG is ready, pages should also conform to the contrast ratios described in the WCAG 2.2's success criteria 1.4.3 (Contrast: Minimum, level AA) or 1.4.6 (Contrast: Enhanced, level AAA). This site's dark-mode stylesheet is an example of a palette that conforms to both the WCAG 2.2 AAA contrast requirements and APCA recommen­dations. +The APCA takes several factors into account: + +* The human retina has few blue-sensitive cone cells, so blue appears "darker" than green and red. Yellow appears brightest. +* Small, thin fonts are difficult to see and require greater contrast. +* It's possible to have too much contrast, especially for large/bold text (note that the APCA version built into Chromium does not yet take this into account). + +Note that [the APCA isn't fully mature](https://yatil.net/blog/wcag-3-is-not-ready-yet) as of early 2022. Until version 3.0 of the WCAG is ready, pages that need to comply with the WCAG should also conform to the contrast ratios described in the WCAG 2.2's success criteria 1.4.3 (Contrast: Minimum, level AA) or 1.4.6 (Contrast: Enhanced, level AAA). This site's dark-mode stylesheet is an example of a palette that conforms to both the WCAG 2.2 AAA contrast requirements and APCA recommen­dations. Yellow may have great contrast on dark backgrounds, but yellow and red can cause problems among [people who deal with overstimulation](https://www.tpgi.com/beyond-wcag-losing-spoons-online/); this includes [autistic people](https://www.experia.co.uk/blog/ultimate-guide-to-autism-friendly-colours/). @@ -758,7 +763,7 @@ Some image optimization tools I use: I put together [a quick script](https://git.sr.ht/~seirdy/dotfiles/tree/3b722a843f3945a1bdf98672e09786f0213ec6f6/Executables/shell-scripts/bin/optimize-image) to losslessly optimize images using these programs. For lossy compression, I typically use [GNU Parallel](https://www.gnu.org/software/parallel/) to mass-generate images using different options before selecting the smallest image at the minimum acceptable quality. Users who'd rather avoid the command line while performing lossy compression can instead check out [Squoosh](https://squoosh.app/), a JavaScript app that bundles Web­Assembly-compiled encoders; I've heard good things about it. -You also might want to use the HTML `` element, using JPEG/PNG as a fallback for more efficient formats such as WebP or AVIF, but only if the size savings are more significant than a couple hundred bytes. More info in the [MDN `` docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) +You also might want to use the HTML `` element, using JPEG/PNG as a fallback for more efficient formats such as WebP or AVIF, but only if the size savings (or quality improvements at a similar size) are significant. More info is in the [MDN `` docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) Most of my images will probably be screenshots that start as PNGs. My typical flow: @@ -984,6 +989,8 @@ I already covered the first option in the prior subsection. If you expect viewer The best compromise is to ensure that the image isn't too wide, and can support large text on a narrow viewport. Lines of text in images should contain as few characters as possible. For a good example, see the "[In defense of link underlines](#in-defense-of-link-underlines)" section. +If the text needs to be readable, [check its contrast](#contrast-is-complex). At large sizes, the contrast shouldn't be too high; at small sizes, it shouldn't be too low. + ### Indented elements Most browser default stylesheets were not optimized for narrow viewports, so narrow-viewport optimization is one of few good reasons to override the defaults. The best example of widescreen bias in browser stylesheets is indentation. @@ -1453,9 +1460,9 @@ A special thanks goes out to GothAlice for the questions she answered in # [^9]: Decoration is more than cosmetic. The [color overrides and accessibility](#color-overrides-and-accessibility) sub-section describes how some decorations, like borders, improve access­ibility. -[^10]: [WebAIM](https://wave.webaim.org/api/docs?format=html) and the [University of Illinois](https://fae.disability.illinois.edu/rulesets/IMAGE_4_EN/) recommends 100 characters; [Tangaru](https://www.tanaguru.com/en/) recommends an even smaller limit of 80 characters. +[^10]: [WebAIM](https://wave.webaim.org/api/docs?format=html) and the [University of Illinois](https://fae.disability.illinois.edu/rulesets/IMAGE_4_EN/) recommend 100 characters; [Tangaru](https://www.tanaguru.com/en/) recommends an even smaller limit of 80 characters. -[^11]: Since WHCM sets colors independent of explicitly-defined ARIA roles, it's a good way to test adherence to [the First Rule of ARIA](#first-rule-of-aria). +[^11]: Since WHCM sets colors independently of explicitly-defined ARIA roles, it's a good way to test adherence to [the First Rule of ARIA](#first-rule-of-aria). [^12]: {{}} only renders invisible text without JavaScript. You can use a textual browser, screen reader, copy-paste the page contents elsewhere, use a reader-mode implemen­tation, or "view source" to read it without enabling scripts. All of these options will ironically override the carefully-crafted typography of this website about typography.