mirror of
https://git.sr.ht/~seirdy/seirdy.one
synced 2024-11-30 15:22:09 +00:00
ca16240b39
Some forms of containment help performance more than others. For certain levels of perf improvement, it's not worth the extra bytes.
678 lines
18 KiB
CSS
678 lines
18 KiB
CSS
/* CSS that adds the bare minimum for a simple, accessible,
|
|
* touch-friendly layout.
|
|
* Nothing here exists purely for cosmetics; everything addresses a
|
|
* specific a11y, compatibility, or critical
|
|
* usability need.
|
|
*
|
|
* Three exceptions:
|
|
* - I re-set the input styles so Safari wouldn't make them pill-shaped
|
|
* - I tweaked some margins/paddings to make some things evenly aligned
|
|
* - I made my IndieWeb profile photo align without an underline
|
|
* on the whitespace between the photo and my name.
|
|
*
|
|
* I also don't use any non-microformats classes except when styling
|
|
* depends on *content* of an element rather than structure/semantics.
|
|
* Examples include images that look better with pixelated upscaling,
|
|
* and posts on the list of entries in the "notes" section that are tall
|
|
* and need a larger contain-intrinsic-size.
|
|
* One exception: a class for narrow width body text.
|
|
*
|
|
* Some pages (e.g. post archives) are really long despite having a
|
|
* small download size. Rather than resort to pagination, I decided to
|
|
* use CSS containment and content-visibility. I test performance on
|
|
* browsers with heavy throttling and no GPU acceleration to ensure that
|
|
* they're gentle on the CPU. For instance, Lighthouse benchmarks my
|
|
* machine's CPU power at 1200-1300 and recommends 2.8-3.0x throttling;
|
|
* I throttle at 12-15x.
|
|
*
|
|
* "content-visibility: auto" implies containment; however, some
|
|
* browsers don't support "content-visibility: auto" but do support the
|
|
* "contain" property. To be consistent across all these browsers, I
|
|
* therefore use both even if it's a bit redundant. Once the latest
|
|
* Safari has supported "content-visibility: auto" for a year or so and
|
|
* it's in the latest version of the Tor Browser (which typically uses
|
|
* whatever the latest Firefox-ESR was a month or two ago), I'll
|
|
* consider removing these redundancies. I'll probably have to wait two
|
|
* years.
|
|
*
|
|
* To keep myself from caring about minute details, I limited myself to
|
|
* only defining spacing in increments of .25em. Pixels are 1px or
|
|
* multiples of 3px. This also improves compression. No more "finding
|
|
* the perfect value".
|
|
*
|
|
* I cite WCAG 2.2 success criteria with "SC". I also tried to meet
|
|
* the Google a11y requirement of 48px tap targets separated by atl
|
|
* 8px, excluding inline links. This involved increasing font size,
|
|
* padding, line-height, and margins. */
|
|
|
|
html {
|
|
/* Mobile screens benefit from greater line-spacing so links are
|
|
* further apart. Dyslexic users prefer the spacing too.
|
|
* Necessary to meet SC 1.4.8.
|
|
* <100dpi screens: sans-serif is better. Why did browsers settle
|
|
* on serif being the default?? */
|
|
font: 100%/1.5 sans-serif;
|
|
/* Nearly every page on my site is taller than the viewport.
|
|
* Paint the scrollbar ASAP to prevent layout shifts. */
|
|
overflow-y: scroll;
|
|
|
|
/* Site is already mobile optimized.
|
|
* Don't screw up landscape mode. */
|
|
-webkit-text-size-adjust: none;
|
|
text-size-adjust: none;
|
|
}
|
|
|
|
/* This should not take effect on printouts, to save paper. */
|
|
@media screen {
|
|
body {
|
|
/* Aligning to the center with space on both sides prevents accidental
|
|
* link activation on tablets, and is a common practice that users are
|
|
* more used to for articles. */
|
|
margin: auto;
|
|
|
|
/* WCAG recommends a max line width. Not everyone can resize the
|
|
* viewport. This isn't for large blocks of text yet, so we don't have
|
|
* to go by SC 1.4.8.
|
|
* 40em = lowest acceptable width for titles, nav, footers, etc */
|
|
max-width: 40em;
|
|
|
|
/* Phone cases can cover the edges. Swipe-from-edge navigations
|
|
* should not conflict with the page elements. Focus outlines for
|
|
* heavily-padded nav links should not be cut-off. All three concerns
|
|
* are addressed by adding some body padding.
|
|
* I followed Google's a11y recommendations of "at least 8px space
|
|
* between tappables" by creating margins/paddings between nav links;
|
|
* re-use that same amount of space here. 24px is what it takes to
|
|
* create atl 48px of non-interactive space on <ul> and <ol> elements
|
|
* containing lists of interactives, with 8px in between.
|
|
* Don't use relative units here; this margin shouldn't scale with
|
|
* zoom, or else text will get narrower with zoom. */
|
|
padding: 0 14px;
|
|
}
|
|
|
|
/* 45em is too wide for long body text.
|
|
* Typically meets SC 1.4.8, plus or minus a few characters. */
|
|
.e-content,
|
|
[itemprop="dataFeedElement"],
|
|
.narrow {
|
|
margin: auto;
|
|
max-width: 34em;
|
|
}
|
|
|
|
/* Enable containment, especially useful for achive pages with
|
|
* long lists of content. */
|
|
body > :not(main),
|
|
main > :not(article),
|
|
li article, /* Archive pages */
|
|
/* We increase the target size of h2/h3 links in a way that would cause
|
|
* issues with content containment */
|
|
article > :not(h2):not(h3) {
|
|
contain: inline-size layout paint;
|
|
/* Add padding on both sides so that focus outlines don't escape their
|
|
* containers. This will let us enable CSS containment without
|
|
* clipping overflowing elements. */
|
|
padding: 0 .5em;
|
|
}
|
|
|
|
/* Align titular h1 with top nav and body text. */
|
|
main > h1 {
|
|
padding-left: .25em
|
|
}
|
|
|
|
/* Breadcrumbs get a lot of padding, making the hr margin redundant
|
|
* Due to containment, the wide blurb at the top of non-article pages
|
|
* has a huge padding on the bottom. This actually works for archive
|
|
* pages but not for the main page. */
|
|
article > hr,
|
|
body > hr,
|
|
main > hr {
|
|
margin: 0 .5em;
|
|
}
|
|
|
|
/* containment has increased spacing of the first paragraph of h-feed
|
|
* entries; offset that. */
|
|
li .p-name + p,
|
|
header hr {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0 0 .25em;
|
|
}
|
|
|
|
/* Archive pages can get long. Allow them to get long without slowing
|
|
* down the browser by using content-visibility. */
|
|
dt,
|
|
footer,
|
|
h2,
|
|
h3,
|
|
li article,
|
|
summary,
|
|
[role="doc-endnotes"] {
|
|
content-visibility: auto;
|
|
contain-intrinsic-size: auto 3em;
|
|
}
|
|
|
|
dt,
|
|
h3 {
|
|
contain-intrinsic-size: 1.5em;
|
|
}
|
|
|
|
footer,
|
|
li article {
|
|
contain-intrinsic-size: auto 16em;
|
|
}
|
|
|
|
/* Notes can get a bit long. */
|
|
li article[itemtype="https://schema.org/SocialMediaPosting"] {
|
|
contain-intrinsic-size: auto 36em;
|
|
}
|
|
|
|
.tall,
|
|
[role="doc-endnotes"] {
|
|
contain-intrinsic-size: auto 50em;
|
|
}
|
|
|
|
/* Full-width elements (e.g. display: block) have known widths, so
|
|
* contain their widths. */
|
|
article,
|
|
body,
|
|
dt,
|
|
dd,
|
|
h1,
|
|
h2,
|
|
h3,
|
|
main,
|
|
pre,
|
|
summary,
|
|
[role="doc-endnotes"],
|
|
[role="doc-preface"] {
|
|
contain: inline-size layout paint;
|
|
}
|
|
|
|
figure,
|
|
:not(li) > p {
|
|
contain: inline-size layout;
|
|
}
|
|
|
|
/* Containment changed spaicng a bit; correct that. */
|
|
article > h2 {
|
|
margin: .25em 0;
|
|
padding: .25em 0;
|
|
}
|
|
|
|
/* A11y: If we have a list of disclosure widgets, we need some
|
|
* non-interactive space on the screen that's safe to tap.
|
|
* Containment does not include paint because the focus-outline
|
|
* will overflow. */
|
|
details,
|
|
fieldset,
|
|
form {
|
|
margin: .5em 0;
|
|
}
|
|
|
|
/* SC 2.5.5, Google a11y: Increase tap target size a bit
|
|
* - Summary is a tappable button
|
|
* - standalone links in lists are usually parts of collections of
|
|
* links that should be easy to fat-finger
|
|
* - links that directly follow h2 without being contained in a
|
|
* paragraph are section permalinks. */
|
|
|
|
/* stylelint-disable selector-max-compound-selectors -- simplest way to describe link-lists */
|
|
input,
|
|
summary,
|
|
aside > a, /* Used for section permalinks */
|
|
dt > a,
|
|
:not(h1) + ul > li > a,
|
|
ol > li > a,
|
|
nav li > a,
|
|
.u-comment dd > a,
|
|
[itemprop="breadcrumb"] a,
|
|
[itemprop="breadcrumb"] > span {
|
|
|
|
/* stylelint-enable selector-max-compound-selectors */
|
|
padding: .75em .25em;
|
|
}
|
|
|
|
/* Compensate for misalignment and wasted space caused by padding
|
|
* and margin adjustments in nav children made to meet SC 2.5.5
|
|
* Also prevent overlapping outlines on focus */
|
|
|
|
/* We've increased the padding for dt > a, but dt without a link
|
|
* should take up as much space. */
|
|
dt {
|
|
padding: 1em .5em;
|
|
margin: -.25em 0 -.25em -.5em;
|
|
}
|
|
|
|
/* <dt> should not be closer to the previous <dd> than the following <dd>.
|
|
* That can happen in webmentions.
|
|
* Give <dd> some padding to the right as well, so webmentions
|
|
* receiving paint containment don't get clipped. */
|
|
dd {
|
|
margin: 0;
|
|
padding: .25em .25em .5em 1.75em;
|
|
}
|
|
|
|
aside > a,
|
|
dt > a {
|
|
contain: content;
|
|
margin: -.75em -.25em;
|
|
}
|
|
|
|
h2 + aside[role="none"] {
|
|
contain: strict;
|
|
content-visibility: auto;
|
|
height: 1.75em;
|
|
margin: -1em -.5em;
|
|
padding: 1em .5em;
|
|
}
|
|
|
|
header > nav,
|
|
a[href="#h1"], /* skip link */
|
|
.u-comment dd > a ,
|
|
footer > nav,
|
|
/* List items with direct hyperlink children should only have one
|
|
* hyperlink. */
|
|
li > a,
|
|
aside > a,
|
|
nav ol a {
|
|
display: inline-block;
|
|
margin-left: -.25em;
|
|
}
|
|
|
|
h1 + ul a {
|
|
margin-left: 0;
|
|
}
|
|
|
|
/* Increase tap-target size of title links. */
|
|
|
|
h2 > a {
|
|
contain: content;
|
|
display: inline-block;
|
|
/* Mis-alignment, I have no clue why it's there. */
|
|
margin: 0 .125em;
|
|
padding: .25em;
|
|
}
|
|
|
|
h3 > a {
|
|
contain: content;
|
|
display: inline-block;
|
|
padding: .5em .25em;
|
|
}
|
|
|
|
article > h3 {
|
|
padding: .25em;
|
|
margin: 0 0 0 -.5em;
|
|
}
|
|
|
|
/* align h-feeds in sections; they typically follow articles. */
|
|
[role="doc-backlink"],
|
|
section article p {
|
|
margin-left: -.5em;
|
|
}
|
|
|
|
/* The nav has to be distant-enough from the top to make room for a
|
|
* skip-link. The breadcrumbs also can't have their focus-outlines
|
|
* overflow while CSS containment is enabled. */
|
|
header > nav,
|
|
nav[itemprop="breadcrumb"] {
|
|
padding: .75em 0 .25em;
|
|
}
|
|
|
|
/* Multiple consecutive <dt> that share a <dd> shouldn't have tap targets overlap.
|
|
* Due to containment: we need to ensure enough padding to avoid
|
|
* overflow but then un-do the padding with a margin. */
|
|
dt + dt {
|
|
padding-top: .75em;
|
|
margin-top: -.75em;
|
|
}
|
|
dt + dt > a {
|
|
padding-top: 0;
|
|
}
|
|
|
|
/* Lists of links should have some spacing so tap targets don't overlap. */
|
|
/* stylelint-disable selector-max-compound-selectors -- simplest way to describe link-lists */
|
|
:not(nav) > :not(h1) + ul li > a,
|
|
nav:not([itemprop="breadcrumb"]) li,
|
|
ol li > a {
|
|
/* stylelint-enable selector-max-compound-selectors */
|
|
margin: .25em;
|
|
}
|
|
|
|
/* Increase backlink tap target size to at least 48x48 */
|
|
[role="doc-backlink"] {
|
|
contain: content;
|
|
display: inline-block;
|
|
padding: .75em .5em;
|
|
margin-top: -1em;
|
|
}
|
|
|
|
/* skip link: make it invisible until focused, and put it on the top. */
|
|
a[href="#h1"] {
|
|
contain: content;
|
|
content-visibility: auto;
|
|
padding: 0 .25em;
|
|
position: absolute;
|
|
top: -2em;
|
|
}
|
|
|
|
a[href="#h1"]:focus {
|
|
top: 0;
|
|
}
|
|
} /* End of adjustments for screen media type */
|
|
|
|
/* Make superscripts a bit easier to tap, and prevent consecutive
|
|
* superscripts from touching. */
|
|
sup > a {
|
|
margin-left: .25em;
|
|
padding-bottom: .5em;
|
|
}
|
|
|
|
/* Make superscript font size a bit larger so they cross some APCA color
|
|
* contrast thresholds on the dark theme. Also prevent them from messing
|
|
* with line-height. */
|
|
sup {
|
|
font-size: 0.85em;
|
|
line-height: 0;
|
|
}
|
|
|
|
/* narrow screens: reduce list indentation, hyphenate nested lists
|
|
* touch screens: lists of links should be easy to tap so give them
|
|
* some spacing (partial SC 2.5.5). There should be non-interactive
|
|
* space to the left that's safe to tap.
|
|
* 1.75em is the minimum required for ol numbers to fit. */
|
|
ol,
|
|
ul,
|
|
li h2 + ul {
|
|
padding-left: 1.75em;
|
|
}
|
|
|
|
blockquote,
|
|
ol ol,
|
|
ul ul {
|
|
-webkit-hyphens: auto;
|
|
hyphens: auto;
|
|
margin: 0;
|
|
padding-left: 1.25em;
|
|
}
|
|
|
|
/* Save some space and paper by making the site nav and footer links
|
|
* single-line without bullets. The title should be visible in the fold
|
|
* on most screens so users can identify the current page. */
|
|
|
|
/* Step 1 to making the single-line nav: remove the bullet padding. */
|
|
nav ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* step 2: remove bullets and make elements inline. */
|
|
[itemprop="breadcrumb"] ol,
|
|
[itemprop="breadcrumb"] li,
|
|
[itemprop="breadcrumb"] > span,
|
|
nav ul li,
|
|
dt > a {
|
|
display: inline-block;
|
|
}
|
|
|
|
[itemprop="breadcrumb"] ol {
|
|
margin: -.25em;
|
|
padding: 0;
|
|
}
|
|
|
|
[itemprop="breadcrumb"] li:not(:last-of-type)::after {
|
|
content: "→";
|
|
}
|
|
/* narrow screens: we reduce margin for blockquotes a lot, using
|
|
* a border instead. */
|
|
blockquote {
|
|
border-left: 3px solid;
|
|
}
|
|
|
|
/* Narrow screens: allow hyphenating titles I can't add soft hyphens to
|
|
* these. Also decrease the top margin a bit; the navbar and breadcrumb
|
|
* list take up plenty of space on top. The latter is a purely
|
|
* aesthetic choice, since it was annoying me a lot. */
|
|
h1 {
|
|
-webkit-hyphens: auto;
|
|
hyphens: auto;
|
|
}
|
|
|
|
/* Very narrow screens: full hyphenation, compactness
|
|
* This is the typical width of a smart feature phone, or a browser
|
|
* sidebar. At this tiny width, users are either unlikely to be using a
|
|
* touchscreen (KaiOS-like feature phones, desktop browser sidebars) or
|
|
* they're just reading non-interactively. being compact probably takes
|
|
* precedence over being touch-friendly. */
|
|
@media (max-width: 272px) {
|
|
body {
|
|
-webkit-hyphens: auto;
|
|
hyphens: auto;
|
|
padding: 0 8px;
|
|
}
|
|
|
|
li > a,
|
|
[itemprop="breadcrumb"] a,
|
|
[itemprop="breadcrumb"] > span {
|
|
padding: .25em;
|
|
}
|
|
|
|
dd {
|
|
padding-left: 1em;
|
|
}
|
|
|
|
hr {
|
|
margin: .25em 0;
|
|
}
|
|
|
|
/* This will line-wrap and take more vertical space; strict containment
|
|
* won't work. */
|
|
h2 + aside[role="none"] {
|
|
contain: inline-size layout paint;
|
|
}
|
|
}
|
|
|
|
/* <kbd> should be distinguished from <code> and surrounding text
|
|
* in a way beyond font-face; at least two visual distinctions needed
|
|
* I set the weight here. */
|
|
kbd {
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* <ins> should not be mistaken for hyperlinks.
|
|
* "note" roles should look distinct. */
|
|
ins,
|
|
[role="note"],
|
|
[role="doc-tip"] {
|
|
contain: content;
|
|
font-style: italic;
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* narrow screens: remove unused figure margins
|
|
* figure captions shouldn't look like regular paragraphs; there should
|
|
* be some extra space.
|
|
* This does not hold true for figures in somewhat distinct sections; the
|
|
* parent section should instead get the spacing. A section that
|
|
* constitutes a separate schema.org object would qualify. */
|
|
figure,
|
|
section[itemprop="mentions"] {
|
|
margin: 1.5em 0;
|
|
}
|
|
|
|
/* image captions, on the other hand, should look more separate from
|
|
* surrounding paragraphs. */
|
|
figure[itemtype="https://schema.org/ImageObject"] {
|
|
margin: 1.5em;
|
|
}
|
|
|
|
section[itemprop="mentions"] > figure {
|
|
margin: 0;
|
|
}
|
|
|
|
/* browsers make monospace small and unreadable for some dumb legacy
|
|
* reason and this somehow fixes that without overriding the user's
|
|
* font size preferences. */
|
|
code,
|
|
kbd,
|
|
pre, /* Needed for ancient browsers */
|
|
samp {
|
|
font-family: monospace, monospace;
|
|
}
|
|
|
|
/* Some browsers don't support the hidden attr.
|
|
* I use hidden spans in backlinks to provide ARIA labels.
|
|
* Some ancient browsers don't support input[type="hidden"] */
|
|
[hidden],
|
|
[type="hidden"] {
|
|
display: none;
|
|
}
|
|
|
|
/* Remove list style from data feeds. */
|
|
.h-feed > ol {
|
|
list-style-type: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Narrow screens: long words can cause content to flow out of the
|
|
* viewport, triggering horizontal scrolling. Allow breaking words in
|
|
* content I don't control (comments, names). For content I do control,
|
|
* I just add soft hyphens to the HTML. */
|
|
.u-comment,
|
|
:not(pre) > code,
|
|
:not(pre) > samp,
|
|
span[itemtype="https://schema.org/Person"] {
|
|
overflow-wrap: break-word;
|
|
}
|
|
|
|
/* Narrow screens: allow horizontal scroll in a pre block. */
|
|
pre {
|
|
overflow: auto;
|
|
padding: .5em;
|
|
}
|
|
|
|
/* Distinguish images from the background in case their color is
|
|
* too similar to the page background color. Also put a border around
|
|
* <pre> and <code> to distinguish them in ways besides font-family.
|
|
* The tappable region of a <summary> extends across the page: we
|
|
* need to tell users that the full space is interactive.
|
|
* This is Technique C25 of SC 1.4.8 */
|
|
input,
|
|
img,
|
|
mark, /* borders provide a distinguishing factor besides color */
|
|
pre,
|
|
summary {
|
|
border: 1px solid;
|
|
}
|
|
|
|
/* A black border is too harsh; the extra visual noise is distracting
|
|
* to users with eye-tracking or ADHD. Only special items like headings
|
|
* should draw gaze. */
|
|
:not(pre) > code,
|
|
:not(pre) > samp {
|
|
border: 1px solid #999;
|
|
|
|
/* borders shouldn't touch text */
|
|
padding: 0 .25em;
|
|
}
|
|
|
|
/* center standalone images; same justification as
|
|
* for centering the body contents. Also makes images easier to see
|
|
* for people holding a device with one hand. */
|
|
.e-content img {
|
|
display: block;
|
|
height: auto;
|
|
margin: auto;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.h-card .u-photo {
|
|
height: 1em;
|
|
width: 1em;
|
|
vertical-align: -.1em;
|
|
}
|
|
|
|
.p-author a.u-uid {
|
|
text-decoration: none;
|
|
}
|
|
|
|
a .u-photo + .p-name {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Stretch out audio elements so the progress meter is easier to use. */
|
|
audio {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Some images look blurry when scaled; this makes them easier to
|
|
* read. */
|
|
.pix {
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
/* Make search box and submit button as wide as possible while keeping
|
|
* them next to each other. */
|
|
|
|
/* Use table-style layout (no, not actual tables. eww.). It's like a
|
|
* single-row flexbox that supports more browsers. Kanged this CSS from
|
|
* ww.gov.uk. Give the entire width of the row to the search box, but
|
|
* allow the minimum width for the submit button. */
|
|
legend, /* Makes the <legend> wrap text in some browsers. */
|
|
form > div {
|
|
display: table;
|
|
width: 100%
|
|
}
|
|
|
|
input {
|
|
/* Don't shrink the size of the text in forms or make it system-ui. */
|
|
font-family: sans-serif;
|
|
font-size: inherit;
|
|
}
|
|
|
|
/* A text box should take all available width */
|
|
input:not([type="submit"]) {
|
|
display: table-cell;
|
|
width: 98%;
|
|
}
|
|
|
|
/* Pseudo-table-cell containing the submit button */
|
|
form > div > div {
|
|
display: table-cell;
|
|
vertical-align: top; /* IE and some botique browsers need this */
|
|
width: 1%;
|
|
}
|
|
|
|
|
|
/* Some browser focus indicators are inaccessible; override them with
|
|
* something more visible. See WCAG 2.x SC 2.4.12. I also tried to
|
|
* match browser behavior; mainstream browsers use :focus-visible
|
|
* instead of focus but older/simpler browsers only support :focus.
|
|
* I borrowed these directives from
|
|
* https://www.tempertemper.net/blog/refining-focus-styles-with-focus-visible
|
|
* To my knowledge: <a>, <summary>, and <pre tabindex=0> are the only
|
|
* focusable elements.
|
|
* */
|
|
|
|
a:focus,
|
|
summary:focus,
|
|
[tabindex="0"]:focus,
|
|
form :focus {
|
|
outline: 3px solid;
|
|
}
|
|
|
|
/* Remove :focus styling for browsers that do support :focus-visible.
|
|
* Leave it on for elements that are supposed to show focus on click. */
|
|
@supports selector(:focus-visible) {
|
|
a:focus:not(:focus-visible),
|
|
[tabindex="0"]:focus:not(:focus-visible) {
|
|
outline: none;
|
|
}
|
|
}
|
|
|
|
/* Todo:
|
|
* - Wait till Webkit fixes its broken-ass default dark stylesheet
|
|
* then consider trimming the dark stylesheet I provide.
|
|
* */
|