<title>Posts on Seirdy&#39;s Home</title>

<link>https://envs.net/~seirdy/posts.html</link>

<description>Recent content in Posts on Seirdy&#39;s Home</description>

<generator>Hugo -- gohugo.io</generator>

<language>en-us</language>

<lastBuildDate>Mon, 23 Nov 2020 12:21:35 -0800</lastBuildDate>

<atom:link href="https://envs.net/~seirdy/posts/index.xml" rel="self" type="application/rss+xml" />

<item>

  <title>An opinionated list of best practices for textual websites</title>

  <link>https://envs.net/~seirdy/2020/11/23/website-best-practices.html</link>

  <pubDate>Mon, 23 Nov 2020 12:21:35 -0800</pubDate>

  <guid>https://envs.net/~seirdy/2020/11/23/website-best-practices.html</guid>

  <description>&lt;p&gt;&lt;em&gt;The following applies to minimal websites that focus primarily on text. It does not

apply to websites that have a lot of non-textual content. It also does not apply to

websites that focus more on generating revenue or pleasing investors than being good

websites.</em></p>

<p>This is a &ldquo;living document&rdquo; that I add to as I receive feedback. See the

<a href="https://git.sr.ht/~seirdy/seirdy.one/log/master/content/posts/website-best-practices.md">changelog</a>.</p>

<p>I realize not everybody&rsquo;s going to ditch the Web and switch to Gemini or Gopher today

(that&rsquo;ll take, like, a month at the longest). Until that happens, here&rsquo;s a

non-exhaustive, highly-opinionated list of best practices for websites that focus

primarily on text:</p>

<ul>

<li>Final page weight under 50kb without images, and under 200kb with images. Page

weight should usually be much smaller; these are upper-bounds for exceptional

cases.</li>

<li>Works in Lynx, w3m, links (both graphics and text mode), Netsurf, and Dillo</li>

<li>Works with popular article-extractors (e.g. Readability) and HTML-to-Markdown

converters. This is a good way to verify that your site uses simple HTML and works

with most non-browser article readers (e.g. ebook converters, PDF exports).</li>

<li>No scripts or interactivity (preferably enforced at the CSP level)</li>

<li>No cookies</li>

<li>No animations</li>

<li>No fonts&ndash;local or remote&ndash;besides <code>sans-serif</code> and <code>monospace</code>. More on this

below.</li>

<li>No referrers</li>

<li>No requests after the page finishes loading</li>

<li>No 3rd-party resources (preferably enforced at the CSP level)</li>

<li>No lazy loading (more on this below)</li>

<li>No custom colors OR explicitly set the both foreground and background colors. More

on this below.</li>

<li>A maximum line length for readability</li>

<li>Server configured to support compression (gzip, optionally zstd as well). It&rsquo;s a

free speed boost.</li>

<li>Supports dark mode via a CSS media feature and/or works with most &ldquo;dark mode&rdquo;

browser addons. More on this below.</li>

<li>A good score on Mozilla&rsquo;s <a href="https://observatory.mozilla.org/">HTTP Observatory</a>. A

bare minimum would be 50, but it shouldn&rsquo;t be too hard to hit 100.</li>

<li>Optimized images. More on image optimization below.</li>

<li>All images labeled with alt-text. The page should make sense without images.</li>

<li>Maybe HTTP/2. There are some cases in which HTTP/2 can make things slower. Run some

tests to find out.</li>

</ul>

<p>I&rsquo;d like to re-iterate yet another time that this only applies to websites that

primarily focus on text. If graphics, interactivity, etc. are an important part of

your website, less (possibly none) of this article applies.</p>

<p>Earlier revisions of this post generated some responses I thought I should address

below. Special thanks to the IRC and <a href="https://lobste.rs/s/akcw1m">Lobsters</a> users who

gave good feedback!</p>

<h2 id="about-fonts">About fonts</h2>

<p>If you <em>really</em> want, you could use <code>serif</code> instead of <code>sans-serif</code>, but serif fonts

tend to look worse on low-res monitors. Not every screen&rsquo;s DPI has three digits.</p>

<p>To ship custom fonts is to assert that branding is more important than user choice.

That might very well be a reasonable thing to do; branding isn&rsquo;t evil! It isn&rsquo;t

<em>usually</em> the case for textual websites, though. Beyond basic layout and optionally

supporting dark mode, authors generally shouldn&rsquo;t dictate the presentation of their

websites; that is the job of the user agent. Most websites are not important enough

to look completely different from the rest of the user&rsquo;s system.</p>

<p>A personal example: I set my preferred fonts in my computer&rsquo;s fontconfig settings.

Now every website that uses <code>sans-serif</code> will have my preferred font. Sites with

<code>sans-serif</code> blend into the users' systems instead of sticking out.</p>

<h3 id="but-most-users-dont-change-their-fonts">But most users don&rsquo;t change their fonts&hellip;</h3>

<p>The &ldquo;users don&rsquo;t know better and need us to make decisions for them&rdquo; mindset isn&rsquo;t

without merits; however, in my opinion, it&rsquo;s overused. Using system fonts doesn&rsquo;t

make your website harder to use, but it does make it smaller and stick out less to

the subset of users who care enough about fonts to change them. This argument isn&rsquo;t

about making software easier for non-technical users; it&rsquo;s about branding by

asserting a personal preference.</p>

<h3 id="cant-users-globally-override-stylesheets-instead">Can&rsquo;t users globally override stylesheets instead?</h3>

<p>It&rsquo;s not a good idea to require users to automatically override website stylesheets.

Doing so would break websites that use fonts such as Font Awesome to display vector

icons. We shouldn&rsquo;t have these users constantly battle with websites the same way

that many adblocking/script-blocking users (myself included) already do when there&rsquo;s

a better option.</p>

<p>That being said, many users <em>do</em> actually override stylesheets. We shouldn&rsquo;t

<em>require</em> them to do so, but we should keep our pages from breaking in case they do.

Pages following this article&rsquo;s advice will probably work perfectly well in these

cases without any extra effort.</p>

<h3 id="but-wouldnt-that-allow-a-website-to-fingerprint-with-fonts">But wouldn&rsquo;t that allow a website to fingerprint with fonts?</h3>

<p>I don&rsquo;t know much about fingerprinting, except that you can&rsquo;t do font enumeration

without JavaScript. Since text-based websites that follow these best-practices don&rsquo;t

send requests after the page loads and have no scripts, fingerprinting via font

enumeration is a non-issue on those sites.</p>

<p>Other websites can still fingerprint via font enumeration using JavaScript. They

don&rsquo;t need to stop at seeing what sans-serif maps to; they can see all the available

fonts on a user&rsquo;s system, the user&rsquo;s canvas fingerprint, window dimensions, etc. Some

of these can be mitigated with Firefox&rsquo;s <code>privacy.resistFingerprinting</code> setting, but

that setting also understandably overrides user font preferences.</p>

<p>Ultimately, surveillance self-defense on the web is an arms race full of trade-offs.

If you want both privacy and customizability, the web is not the place to look; try

Gemini or Gopher instead.</p>

<h2 id="about-lazy-loading">About lazy loading</h2>

<p>For users on slow connections, lazy loading is often frustrating. I think I can speak

for some of these users: mobile data near my home has a number of &ldquo;dead zones&rdquo; with

abysmal download speeds, and my home&rsquo;s Wi-Fi repeater setup occasionally results in

packet loss rates above 60% (!!).</p>

<p>Users on poor connections have better things to do than idly wait for pages to load.

They might open multiple links in background tabs to wait for them all to load at

once, or switch to another window/app and come back when loading finishes. They might

also open links while on a good connection before switching to a poor connection; I

know that I often open 10-20 links on Wi-Fi before going out for a walk in a

mobile-data dead-zone. A Reddit user reading an earlier version of this article

described a <a href="https://i.reddit.com/r/web_design/comments/k0dmpj/an_opinionated_list_of_best_practices_for_textual/gdmxy4u/">similar

experience</a>

riding the train.</p>

<p>Unfortunately, pages with lazy loading don&rsquo;t finish loading off-screen images in the

background. To load this content ahead of time, users need to switch to the loading

page and slowly scroll to the bottom to ensure that all the important content appears

on-screen and starts loading. Website owners shouldn&rsquo;t expect users to have to jump

through these ridiculous hoops.</p>

<h3 id="wouldnt-this-be-solved-by-combining-lazy-loading-with-pre-loadingpre-fetching">Wouldn&rsquo;t this be solved by combining lazy loading with pre-loading/pre-fetching?</h3>

<p>A large number of users with poor connections also have capped data, and would prefer

that pages don&rsquo;t decide to predictively load content ahead-of-time for them. Some go

so far as to disable this behavior to avoid data overages. Savvy privacy-conscious

users also generally disable pre-loading because they don&rsquo;t have reason to trust that

linked content doesn&rsquo;t practice dark patterns like tracking without consent.</p>

<p>Users who click a link <em>choose</em> to load a full page. Loading pages that a user hasn&rsquo;t

clicked on is making a choice for that user.</p>

<h3 id="cant-users-on-poor-connections-disable-images">Can&rsquo;t users on poor connections disable images?</h3>

<p>I have two responses:</p>

<ol>

<li>If an image isn&rsquo;t essential, you shouldn&rsquo;t include it inline.</li>

<li>Yes, users could disable images. That&rsquo;s <em>their</em> choice. If your page uses lazy

loading, you&rsquo;ve effectively (and probably unintentionally) made that choice for a

large number of users.</li>

</ol>

<h2 id="about-custom-colors">About custom colors</h2>

<p>Some users' browsers set default page colors that aren&rsquo;t black-on-white. For

instance, Linux users who enable GTK style overrides might default to having white

text on a dark background. Websites that explicitly set foreground colors but leave

the default background color (or vice-versa) end up being difficult to read. Here&rsquo;s

an example:</p>

<picture>

<source srcset="https://seirdy.one/misc/website_colors.webp" type="image/webp">

<img src="https://seirdy.one/misc/website_colors.png" alt="This page with a grey background, a header with unreadable black/grey text, and unreadable white-on-white code snippets">

</picture>

<p>If you do explicitly set colors, please also include a dark theme using a media

query: <code>@media (prefers-color-scheme: dark)</code>. For more info, read the relevant docs

<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">on

MDN</a></p>

<h2 id="image-optimization">Image optimization</h2>

<p>Some image optimization tools I use:</p>

<ul>

<li><a href="http://pngquant.org">pngquant</a> (lossy)</li>

<li><a href="https://github.com/shssoichiro/oxipng">Oxipng</a> (lossless)</li>

<li><a href="https://github.com/tjko/jpegoptim">jpegoptim</a> (lossless or lossy)</li>

<li><a href="https://developers.google.com/speed/webp/docs/cwebp">cwebp</a> (lossless or lossy)</li>

</ul>

<p>I put together a <a href="https://git.sr.ht/~seirdy/dotfiles/tree/3b722a843f3945a1bdf98672e09786f0213ec6f6/Executables/shell-scripts/bin/optimize-image">quick

script</a>

to losslessly optimize images using these programs in my dotfile repo.</p>

<p>You also might want to use the HTML <code>&lt;picture&gt;</code> element, using JPEG/PNG as a fallback

for more efficient formats such as WebP or AVIF. More info in the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture">MDN

docs</a></p>

<p>Most of my images will probably be screenshots that start as PNGs. My typical flow:</p>

<ol>

<li>Lossy compression with <code>pngquant</code></li>

<li>Losslessly optimize the result with <code>oxipng</code> and its Zopfli backend (slow)</li>

<li>Also create a lossless WebP from the lossy PNG, using <code>cwebp</code></li>

<li>Include the resulting WebP in the page, with a fallback to the PNG using a

<code>&lt;picture&gt;</code> element.</li>

</ol>

<p>It might seem odd to create a lossless WebP from a lossy PNG, but I&rsquo;ve found that

it&rsquo;s the best way to get the smallest possible image at the minimum acceptable

quality for screenshots with solid backgrounds.</p>

<h2 id="other-places-to-check-out">Other places to check out</h2>

<p>The <a href="https://250kb.club/">250kb club</a> gathers websites at or under 250kb, and also

rewards websites that have a high ratio of content size to total size.</p>

<p>Also see <a href="https://motherfuckingwebsite.com/">Motherfucking Website</a>. Motherfucking

Website inspired several unofficial sequels that tried to gently improve upon it. My

favorite is <a href="https://bestmotherfucking.website/">Best Motherfucking Website</a>.</p>

<p>The <a href="https://www.webbloatscore.com/">WebBS calculator</a> compares a page&rsquo;s size with

the size of a PNG screenshot of the full page content, encouraging site owners to

minimize the ratio of the two.</p>

</item>

<item>

  <title>Resilient Git, Part 1: Hydra Hosting</title>

  <link>https://envs.net/~seirdy/2020/11/18/git-workflow-1.html</link>

  <pubDate>Wed, 18 Nov 2020 18:31:15 -0800</pubDate>

  <guid>https://envs.net/~seirdy/2020/11/18/git-workflow-1.html</guid>

  <description>&lt;p&gt;This is Part 1 of a series called &lt;a href=&#34;../../../2020/11/17/git-workflow-0.html&#34;&gt;Resilient

Git</a>.</p>

<p>The most important part of a project is its code. Resilient projects should have

their code in multiple places of equal weight so that work continues normally if a

single remote goes down.</p>

<p>Many projects already do something similar: they have one &ldquo;primary&rdquo; remote and

several mirrors. I&rsquo;m suggesting something different. Treating a remote as a &ldquo;mirror&rdquo;

implies that the remote is a second-class citizen. Mirrors are often out of date and

aren&rsquo;t usually the preferred place to fetch code. Instead of setting up a primary

remote and mirrors, I propose <strong>hydra hosting:</strong> setting up multiple primary remotes

of equal status and pushing to/fetching from them in parallel.</p>

<p>Having multiple primary remotes of equal status might sound like a bad idea. If there

are multiple remotes, how do people know which one to use? Where do they file bug

reports, get code, or send patches? Do maintainers need to check multiple places?</p>

<p>No. Of course not. A good distributed system should automatically keep its nodes in

sync to avoid the hassle of checking multiple places for updates.</p>

<h2 id="adding-remotes">Adding remotes</h2>

<p>This process should pretty straightforward. You can run <code>git remote add</code> (see

<code>git-remote(1)</code>) or edit your repo&rsquo;s <code>.git/config</code> directly:</p>

<pre><code class="language-gitconfig" data-lang="gitconfig">[remote &quot;origin&quot;]

url = git@git.sr.ht:~seirdy/seirdy.one

fetch = +refs/heads/*:refs/remotes/origin/*

[remote &quot;gl_upstream&quot;]

url = git@gitlab.com:seirdy/seirdy.one.git

fetch = +refs/heads/*:refs/remotes/gl_upstream/*

[remote &quot;gh_upstream&quot;]

url = git@github.com:seirdy/seirdy.one.git

fetch = +refs/heads/*:refs/remotes/gh_upstream/*

</code></pre><p>If that&rsquo;s too much work&ndash;a perfectly understandable complaint&ndash;automating the process

is trivial. Here&rsquo;s <a href="https://git.sr.ht/~seirdy/dotfiles/tree/master/Executables/shell-scripts/bin/git-remote-setup">an example from my

dotfiles</a>.</p>

<h2 id="seamless-pushing-and-pulling">Seamless pushing and pulling</h2>

<p>Having multiple remotes is fine, but pushing to and fetching from all of them can be

slow. Two simple git aliases fix that:</p>

<pre><code class="language-gitconfig" data-lang="gitconfig">[alias]

pushall = !git remote | grep -E &#39;origin|upstream&#39; | xargs -L1 -P 0 git push --all --follow-tags

fetchall = !git remote | grep -E &#39;origin|upstream&#39; | xargs -L1 -P 0 git fetch

</code></pre><p>Now, <code>git pushall</code> and <code>git fetchall</code> will push to and fetch from all remotes in

parallel, respectively. Only one remote needs to be online for project members to

keep working.</p>

<h2 id="advertising-remotes">Advertising remotes</h2>

<p>I&rsquo;d recommend advertising at least three remotes in your README: your personal

favorite and two determined by popularity. Tell users to run <code>git remote set-url</code> to

switch remote locations if one goes down.</p>

<h2 id="before-you-ask">Before you ask&hellip;</h2>

<p>Q: Why not use a cloud service to automate mirroring?</p>

<p>A: Such a setup depends upon the cloud service and a primary repo for that service to

watch, defeating the purpose (resiliency). Hydra hosting automates this without

introducing new tools, dependencies, or closed platforms to the mix.</p>

<p>Q: What about issues, patches, etc.?</p>

<p>A: Stay tuned for Parts 2 and 3, coming soon to a weblog/gemlog near you™.</p>

<p>Q: Why did you call this &ldquo;hydra hosting&rdquo;?</p>

<p>A: It&rsquo;s a reference to the Hydra of Lerna from Greek Mythology, famous for keeping

its brain in a nested RAID array to protect against disk failures and beheading. It

could also be a reference to a fictional organization of the same name from Marvel

Comics named after the Greek monster for <a href="https://www.youtube.com/watch?v=assccoyvntI&amp;t=37">similar

reasons</a> (<a href="https://seirdy.one/misc/hail_hydra.webm">direct

webm</a>).</p>

</item>

<item>

  <title>Resilient Git, Part 0: Introduction</title>

  <link>https://envs.net/~seirdy/2020/11/17/git-workflow-0.html</link>

  <pubDate>Tue, 17 Nov 2020 13:13:03 -0800</pubDate>

  <guid>https://envs.net/~seirdy/2020/11/17/git-workflow-0.html</guid>

  <description>&lt;p&gt;Recently, GitHub re-instated the &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;youtube-dl git

repository</a> after following a takedown

request by the RIAA under the DMCA. Shortly after the takedown, many members of the

community showed great interest in &ldquo;decentralizing git&rdquo; and setting up a more

resilient forge. What many of these people fail to understand is that the Git-based

project setup is designed to support decentralization by being fully distributed.</p>

<p>Following the drama, I&rsquo;m putting together a multi-part guide on how to leverage the

decentralized, distributed nature of git and its ecosystem. I made every effort to

include all parts of a typical project.</p>

<p>I&rsquo;ll update this post as I add articles to the series. At the moment, I&rsquo;ve planned to

write the following articles:</p>

<ol>

<li><a href="../../../2020/11/18/git-workflow-1.html">Hydra Hosting</a>: repository hosting.</li>

<li>Community feedback (issues, support, etc.)</li>

<li>Community contributions (patches)</li>

<li>CI/CD</li>

<li>Distribution</li>

</ol>

<p>The result of the workflows this series covers will be minimal dependence on outside

parties; all members of the community will easily be able to get a copy of the

software, its code, development history, issues, and patches offline on their

machines with implementation-neutral open standards. Following open standards is the

killer feature: nothing in this workflow depends on a specific platform (GitHub,

GitLab, Gitea, Bitbucket, Docker, Nix, Jenkins, etc.), almost eliminating your

project&rsquo;s &ldquo;bus factor&rdquo;.</p>

<p>Providing a way to get everything offline, in a format that won&rsquo;t go obsolete if a

project dies, is the key to a resilient git workflow.</p>

<h2 id="before-we-start-faq">Before we start: FAQ</h2>

<p>Q: What level of experience does this series expect?</p>

<p>A: Basic knowledge of git, and a very basic understanding of email. If you have a few

repos and can use a third-party email client, you&rsquo;re good.</p>

<p>Q: Do you think you can get hundreds and thousands of people to drop Git{Hub,Lab,tea}

and use a different workflow?</p>

<p>A: No, but that would be nice. If only five people who read this series give this

workflow a spin and two of them like it and keep using it, I&rsquo;d be happy.</p>

<p>Q: Is this workflow more difficult than my current one?</p>

<p>A: &ldquo;Difficult&rdquo; is subjective. I recommend TRYING this before jumping to conclusions

(or worse, sharing those conclusions with others before they have a chance to try

it).</p>

<p>Q: I&rsquo;m not interested in trying anything new, no matter what the benefits are.</p>

<p>A: First of all, that wasn&rsquo;t a question. Second, this series isn&rsquo;t for you. You

should not read this. I recommend doing literally anything else.</p>

<p>Next: Resilient Git, Part 1: <a href="../../../2020/11/18/git-workflow-1.html">Hydra Hosting</a></p>

</item>

<item>

  <title>Hello World</title>

  <link>https://envs.net/~seirdy/2020/11/02/hello-world.html</link>

  <pubDate>Mon, 02 Nov 2020 11:06:56 -0800</pubDate>

  <guid>https://envs.net/~seirdy/2020/11/02/hello-world.html</guid>

  <description>&lt;p&gt;Hello, world! This is my first post.&lt;/p&gt;

<p>It looks like I managed to somehow get this site working. You can look forward to a

few more posts in the coming weeks.</p>

</item>

Proxy Information
Original URL
gemini://envs.net/~seirdy/posts/index.xml
Status Code
Success (20)
Meta
application/xml
Capsule Response Time
148.469679 milliseconds
Gemini-to-HTML Time
11.677531 milliseconds

This content has been proxied by September (3851b).