303 private links
- choose fonts wisely
- optimize the font display:
body { text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } - golden ratio for line-height
- keep the amount of characters per line to 90
- prefer SVG and WEBP formats
A guide to display: grid-lanes
instead of letting the call stack implicitly control what happens next (as recursion does), store the pending work in an explicit data structure such as a stack, queue, or heap. This turns control flow into ordinary data that can be inspected, paused, modified, or resumed.
Explicit stacks makes interruptions, limits, cancellation or interleaving work easier to work with. It's more adaptable to real-world constraints and test.
A stack (LIFO) produces depth-first search behavior.
A queue (FIFO) produces breadth-first search behavior.
- giving every integer a shared helper method: define a trait with two required methods and one default method,
- Making class AnimatedServo still count as a Servo: require a trait in another trait
- adding a method to a type you don't own: implement a new trait for the primitive type
- giving a tiny Enum a full set of standard behaviors: the standard traits already exist and
derive - making a wrapper feel like the thing inside it: the wrapper can implement the thing and implement
DerefandDerefMut - adding union to any collection of range sets: mock a wrapper around a BTreeSet for example
- treating fifteen integer-link types the same way: to avoid writing the same method bodies 15 times, write a
macro_rules - Giving Only OutputArray<8> (8 bits) a Byte-Oriented Method: implement a general methods in the general impl block. It's named Constraint-Gated Methods.
- How would you make some methods available only when the method’s type parameter has the required capabilities? Use
serdeandpostcardwith aHashMapstanding in for flash memory.
I learned the content property has an alt (similar to images) if needed.
The snippet:
[href^="http"]:not(.btn, :has(svg)):not([href^="https://gomakethings.com"], [href^="http://localhost"])::after {
background-color: currentColor;
content: "" / "(external link)";
display: inline-block;
mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z"/></svg>');
mask-size: cover;
}There is an @page to set the property of a page. There is also rules to break the page at desired.
The navigation can be hidden.
Links and <abbr> content must be placed in the view with content: attr(href).
Check the forms.
It can be worth checking for a black and white version while printing it.
safe-area-insert is useful to provide some padding to avoid cameras and virtual buttons. This is not needed because the browser handles it for you already.
It's still needed for elements with position: absolute or position: fixed
Browsers by default will prevent your site from being obscured by the notch or home indicator, so your content will be safe without any special handling.
Ideally we want the content to stretch edge-to-edge, but we want to make sure they're not obscured by system UI. To get that, you need to opt in to the full viewport and handle safe areas yourself.
Maybe useful for later, but I see some advantages.
wcag2(aa) seems to be a good and self explanatory function.
It has limitations though:
- it doesn't guarantee perceptual or AAA compliance
- transition snaps because
contrast-colorreturns a discrete value and - tie goes to white
- gradients and images are out
- transparent colors are composited first
- windows high contrast mode takes over. It is defined in https://www.w3.org/TR/css-color-adjust-1/#forced-colors-mode
The generated colors can be combined with other color functions.
I am still concerned more and more computation will be put on simple webpages.
You might think that the JS version is slower [than CSS, but it's not for the right reason]
But there’s one significant difference: the JavaScript version runs on the main thread, along with everything else happening in our application. CSS transitions and keyframe animations run on a separate thread, so they aren’t disrupted when stuff happens in JavaScript.
Motion can create more smooth APIs but GSAP is more powerful.
These are definitely the rules I follow. I still not reach for <menu> yet.
in HTML5 they realized it was kinda annoying that the spec didn’t allow us to clump the terms and definitions together. So now a
is permitted as a non-semantic wrapper to help us clump those terms and definitions together:Action list should be put inside
<menu>. Thenavelement is a sectioning element whereas the`menuelement is a list element.
The client is not a thin view requesting permission to show data. The client is a node in a distributed system with its own database.
It’s overkill for simple CRUD apps with no offline or collaboration needs.
But here’s where it shines: note-taking, document editing, collaborative design tools, project management, field apps with unreliable connectivity, basically anything where data privacy is a selling point, as well as anything with real-time collaboration.
One more thing I wish someone had told me earlier: you don’t have to go all-in. I’ve had the best results using local-first for specific features within otherwise traditional apps. Offline drafts in a blog editor. Real-time collaborative notes inside a project management tool that’s otherwise standard REST.
To do so: SQLite in the browser via WebAssembly; persisted to the Origin Private File System (OPFS). The author describes the method used.
To avoid conflicts: CRDT. Yjs exists. There is also Automerge and the newer Loro.
To grasp the data: replicate rows via database replication.
PowerSync does this well from Postgres to SQLite.
Triplit is a full-stack database with sync built-in.
LiveStore use an event-based approach.
TinyBase for prototyping or small apps.
PGLite (Postgres compiled to WASM) but it has a significant bundle size and memory footprint for mobile browsers.
Often the last-write-wins (LWW) is the best strategy at the field level.
For a document body, CRDT should be used.
To book a meeting, one must verify there is no other meeting booked by someone else. " The approach I’ve landed on (after getting it wrong twice) is: validate on the server during the write-back phase, but flag violations rather than silently rejecting them. When the client pushes mutations to the server during sync, the server runs them through a constraint validation layer before applying them to Postgres". See the example.
The conflict should then be resolved by the user.
For something like inventory management where two people “buy” the last item, that window is unacceptable, and that’s exactly why I said earlier that local-first is wrong for systems requiring strong transactional consistency.
Conflict resolution works well for texts with CRDT.
See such app architecture: https://www.smashingmagazine.com/2026/05/architecture-local-first-web-development/#building-a-real-app-architecture-auth-and-migrations
Example of E2E (local, on device) encryption for https://anytype.io/
One thing to consider is migrations: Design your migrations to be additive. New columns with defaults. New tables. Don’t rename or drop columns unless you absolutely must, because users running old app versions will still be syncing data, and your server needs to handle the mismatch. I learned this the hard way when I dropped a column that an older client was still writing to, which caused silent sync failures for about 200 users over a weekend.
Performance are awesome (< 10ms for read or writes). The initial sync is where the cost occurs.
The architecture can be tested with Playwright and context.setOffline(true).
I’m excited about where this is going. PGlite (full Postgres in the browser) feels like a glimpse of a future where the client/server data layer distinction just dissolves. You write SQL, it runs everywhere, sync is a runtime concern rather than an architectural decision. We’re not there yet, but you can see it from here.
There is also no standard for a sync engine. Migrating away a sync engine is not trivial. I’m also worried about the complexity budget. Local-first adds real architectural complexity: sync engines, conflict resolution, client-side migrations, partial replication, and auth at the sync boundary.
Adding query string for a referral (with ?via for example)
- can broke the URL such as
https://int10h.org/oldschool-pc-fonts/fontlist/?foo. Altering a URL gives you a new URL. The new URL could point to a completely different resource, or to no resource at all, even if the alteration is as small as adding a seemingly harmless query string. - There is already the HTTP Referrer header for that. It's governed by the Referrer-Policy
Another post describe this problem: https://chrismorgan.info/no-query-strings
There are a number of serialization libraries that outperform JSON in NodeJS.
It's important to avoid generating extraneous garbage when doing these kinds of benchmarks.
It's important to provide an appropriately sized buffer when performing serialization.
If you care about serialization performance, consider using a different programming language with better tradeoffs.
With 3 columns and CSS grid.