/* 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 { /* Default font sizes are one-size-fits-all; they're optimized for a * wide variety of complex pages. For single-column websites like * mine, it's ideal to bump it up ever so slightly. This also makes * , , , etc. large enough to have decent contrast * with minimal adjustment, and makes tap-targets larger. * Only do this on screen, since printouts already improve legibility * and cost paper + ink. * 109.375% is the minimum required to get text to 17.5 CSS pixels and * superscripts past 14.75 px with most default stylesheets. At that * size, my dark color palette has sufficient contrast.*/ font-size: 109.375%; /* 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
    and
      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-backlink"], [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, html, main, pre, summary, dl > div, :not(nav) > ol, [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. */ details, form { contain: inline-size layout; 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; } /*
      should not be closer to the previous
      than the following
      . * That can happen in webmentions. * Give
      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; contain: inline-size layout paint; } 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 > li > 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 { padding: .75em 0 .25em; } /* Multiple consecutive
      that share a
      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 { font-size: 100%; -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; } } /* should be distinguished from and surrounding text * in a way beyond font-face; at least two visual distinctions needed * I set the weight here. */ kbd { font-weight: bold; } /* 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 * 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; } 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 *
       and  to distinguish them in ways besides font-family.
       * The tappable region of a  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  wrap text in some browsers. */
      form > div {
      	display: table;
      	width: 100%
      }
      
      input {
      	/* Browsers like Safari make the submit button pill-shaped which
      	 * clashes with the input box. One of the only purely-cosmetic changes
      	 * on this site. */
      	appearance: none;
      
      	/* 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: , , and 
       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.
       * */