Accessibility
A11y 101: 2.5.3 Label in Name
We all navigate the internet and computers in different ways. Some use screen readers, others keyboard, and some people by voice. Success Criterion 2.5.3 was created to support these diverse methods. While it helps all users, it was created to address using voice control because typing is a struggle for the user.
The rule is simple, but the impact is profound:
If a user interface component has a visible text label, that exact text (or a string that contains it) must be present in the component’s accessible name.
Is aria-label allowed on static elements?
There is a commonly held belief that the aria-label attribute “cannot” be used on static (or non-interactive) elements.
While the ARIA and HTML specifications do not forbid aria-label purely on the basis of an element being ‘static’, they do prohibit its use when an element’s implicit or explicit role does not support ‘name from author’ (see ARIA in HTML, section 5.2.8).
As you will see below, there are legitimate cases where static elements use aria-label, either because they have a native role or because an appropriate ARIA role is applied.
In this article, we examine how aria-label behaves on static elements in practice, across browsers and platforms, and why real-world behaviour is often more nuanced than common assumptions suggest.
The examples include clearly flagged bad-practice patterns alongside legitimate use cases, to show what is exposed at the accessibility API level — and why exposure alone does not imply recommendation.
A11y 101: 3.1.1 Language of Page
The requirement is simple but powerful: The default human language of each web page must be programmatically determinable.
In code terms, this means slapping a lang attribute on your <html> element:
<html lang="en">
That’s it. One attribute. Two little characters. But those two characters tell browsers, screen readers, and translation tools exactly what language they’re dealing with. It’s like handing your assistive technology a dictionary before it starts reading aloud.
CSS
Hand-Drawn Underline using border-shape
Use the new border-shape property and transform the classic underline into hand-drawn lines. It works with a simple code, and you can easily generate the wavy shape using my online generator.
Multi-stroke text effect in CSS
I used to see that retro multi-stroke text effect quite often and tried to replicate it using the CSS text-stroke property, but the results never quite matched. Because text-stroke accepts a single value, stacking elements was the only workaround I could think of, though it didn't seem to work.
One evening late last year, I was eager to give it another shot. I kept stacking several elements and accidentally varied the text-stroke-width for each layer. To my suprise, the result was getting closer this time.
Scroll-Driven Variable Fonts
font-variation-settings is a CSS property like any other, which means animation-timeline can drive font weight, tracking, and optical size directly from scroll position. No JavaScript.
font-family Doesn’t Fall Back the Way You Think
There is a small but surprisingly important nuance in the way font-family works that seems to catch a lot of people out. In my continuing series on web performance for design systems, today we’ll look at font stacks and how, when improperly configured, they can cause unsightly flashes of inappropriate or unexpected fallback text, and in more extreme cases, layout shifts.
CSS you didn’t know you could style
Most developers think of CSS as the tool for styling layout, spacing, and colors, but modern CSS can do much more than that.
CSS can even style some native elements in your browser that you probably never even thought about styling.
The end of responsive images
I’ve been waiting for fourteen years to write this article. Fourteen years to tell you about one relatively new addition to the way images work on the web. For you, just a handful of characters will mean improvements to the fundamental ergonomics of working with images. For users, it will mean invisible, seamless, and potentially massive improvements to front-end performance, forever stitched into the fabric of the web.
Six levels of dark mode
Breaks dark mode implementation into a progression of six levels, from simplest to most advanced:
- Barebone – Add a
<meta name="color-scheme">tag so the browser automatically adapts to the user’s OS preference. - Basic – Use the CSS
color-schemeproperty for similar behavior, optionally scoped to parts of the page. - Benign – Use the
light-dark()CSS function to switch specific colors between light and dark modes. - Bold – Use
@media (prefers-color-scheme)for full control over styles in each mode. - Bisectional – Split light and dark styles into separate stylesheets for larger customizations.
- Ballistic – Use JavaScript (
matchMedia) to detect and react to color scheme dynamically.
The key idea: dark mode isn’t one technique—it’s a spectrum, and developers can mix these approaches depending on how much control and complexity they need.
Details That Make Interfaces Feel Better
Great interfaces rarely come from a single thing. It's usually a collection of small things that compound into a great experience. Below are a few small details I use to make my interfaces feel better.
JavaScript
JavaScript Promise.all() and Promise.allSettled() in Practice
If you're await-ing async calls one after another instead of using Promise.all(), you're probably wasting time. Literally.
Say you need to hit three APIs and each takes 300ms. Await them sequentially and you're looking at approximately 900ms. Run them with Promise.all() and you're done in 300ms, which is the time of the slowest call.
Why I don't chain everything in JavaScript anymore
The issue isn’t .map() or .filter(). It’s what happens when you stack them. You stop writing steps and start writing pipelines.
Pipelines look clean, but you still have to walk through them in your head: filter → map → sort → slice.
That’s fine once or twice. Do it all over a file and it starts to wear on you.
Short chains are fine. I still write them. Once I hit three or four steps, I pause. Chaining is great when you’re writing code quickly. Breaking things into steps is better when that code has to be read later.
What's actually new in JavaScript (and what's coming next)
ES2025 is out, ES2026 is close. Here is the new feature of Javascript we can use today, what is coming next and how we can get our AI friends to use these new features.
Geoviz - a JavaScript library for designing thematic maps
The library provides a set of d3 compatible functions that you can mix with the usual d3 syntax. The library is designed to be intuitive and concise. It allow to manage different geographic layers (points, lines, polygons) and marks (circles, labels, scale bar, title, north arrow, etc.) to design pretty maps.
Backend-for-Frontend: The most secure architecture for browser-based apps
Learn why Backend-for-Frontend (BFF) is the only auth architecture that survives npm supply chain attacks. Part 1 of 3 in our architecture-driven auth series.
If you still store tokens where JavaScript can access them, consider migrating to a BFF architecture as soon as possible. Now more than ever, the security benefits are too significant to ignore.
Although BFF isn't necessary for every application, it's strongly recommended if you:
- Handle sensitive data (PII, financial, healthcare).
- Build business-critical applications.
- Are subject to compliance requirements.
- Control the backend.
Miscellaneous
ai-quit-job - An open-source employment attorney + career coach. 14 markdown files. No retainer
Most people quit their jobs emotionally. They give notice on a Tuesday, feel a brief rush of freedom, then spend the next six months piecing together what they left on the table. Conservative estimates put the average foregone value at $20,000–$80,000 — in uncollected severance, unvested equity, unpaid wages, or a legitimate legal claim that was never pursued because they never knew to look.
This repo is the systematic alternative. It combines the perspective of a career coach, a senior HR negotiator, and an employment attorney into a set of production-quality system prompts. You supply the situation. The agents provide the framework, the diagnostic questions, and the structured output.
The differentiator: the legal screener agents. Most career advice stops at resignation letters and LinkedIn posts. This repo asks the uncomfortable question first — does your employer owe you something? — before helping you craft a graceful exit. Most employers are counting on you never asking.
HyperFrames — Edit Videos By Vibe-Coding
HyperFrames lets AI agents compose videos by writing HTML, CSS & JS.
GPT Image Generation Models Prompting Guide
In this notebook, we demonstrate how to use gpt-image generation models to build high-quality, controllable image generation and editing workflows that hold up in real production settings. The cookbook emphasizes prompt structure, explicit constraints, and small iterative changes as the primary tools for controlling realism, layout, text accuracy, and identity preservation. We cover both generation and editing patterns, ranging from infographics, photorealism, UI mockups, and logos to translation, style transfer, virtual try-on, compositing, and lighting changes. Throughout the examples, the cookbook reinforces the importance of clearly separating what should change from what must remain invariant, and of restating those invariants on every iteration to prevent drift. We also highlight how quality and input-fidelity settings enable deliberate tradeoffs between latency and visual precision depending on the use case. Together, these examples form a practical, repeatable playbook for applying gpt-image generation models in production image workflows.