:::

Blog

Notes on frontend, design, and accessibility.

34 posts Page 1 of 4

  • Building a Video Call Waiting Room with <usermedia>: The Browser Handles Permissions, but Six Things Are Still on You

    <usermedia> hands the camera button and the permission flow to the browser: people who blocked access can recover right on the page, and screen readers can operate the permission dialog. But testing in Chrome with VoiceOver, I found that lang="zh-Hant-TW" turns the button text into Simplified Chinese, there's no state once the camera is on, and keyboard users who press too quickly get a silent failure. Using a video call waiting room as the example, this post covers the six things you still need to handle.

    Front-EndHTMLJavaScriptFront-EndAccessibilityBrowser Support
  • Make a Headline Fill the Line Exactly: Testing text-fit, and the Trap Where Zooming Makes Text Smaller

    text-fit grows text to fill its container, or shrinks it to fit, in one line of CSS instead of JavaScript. But in my tests, with plain grow, zooming the page made the text smaller, a larger default font size was cancelled out, and wrapped lines could overflow the container. This post uses a live demo to cover the syntax, where it fits and where it doesn't, and an accessible way to write it.

    Front-EndCSSFront-EndAccessibilityBrowser Support
  • Designers Could Always Draw Them, Now Developers Can Build Them: Squircles, Coupons, Step Arrows and Cut-Corner Buttons with corner-shape

    Squircle app icons, coupons with notches, checkout step arrows and game-style cut-corner buttons used to need clip-path or mask, which clipped away the focus outline and borders too. This post uses a live demo to compare the old techniques with corner-shape, includes the full commented code, and tests accessibility details such as forced colors and the clickable area.

    Front-EndCSSFront-EndAccessibilityBrowser Support
  • Writing Accessibility into CSS with if() and @function: Reduced Motion, More Contrast, Minimum Target Size

    CSS if() puts conditions inside a property value, and @function turns repeated calculations into custom functions. This post uses a live demo to write reduced motion, a higher-contrast focus outline and a 24px minimum target size as conditions and functions, and sums up the pitfalls I hit while testing: an if() without else can make the focus outline disappear entirely.

    Front-EndCSSFront-EndAccessibilityBrowser Support
  • setHTML() Is Safe, but It Stripped All My ARIA

    Element.setHTML() is a safe innerHTML that strips scripts and event attributes as it inserts HTML. In my tests, its default config also removes every aria-*, role and id, and drops button, img, input and label entirely, without any error. This post uses a live demo to compare the default config, an empty config and a custom allowlist, and sums up how to balance security and accessibility.

    Front-EndHTMLJavaScriptFront-EndAccessibilityBrowser Support
  • One Line to Change Opacity with alpha(), One Line to Roll Back with revert-rule: Testing Two Small CSS Tools

    alpha() changes the opacity of a color stored in a variable, whether it was written as hex, rgb, hsl or oklch; revert-rule rolls a property back to the value it would have "if this rule didn't exist". This post uses a live demo to compare what each color format becomes after alpha(), tests the contrast of semi-transparent colors on light and dark backgrounds, and sorts out how revert-rule differs from revert and revert-layer.

    Front-EndCSSFront-EndAccessibilityBrowser Support
  • Why Does width: 100% Overflow Its Container? Fill It Exactly with stretch

    When an element has margins, width: 100% overflows its container, and box-sizing can't fix it. width: stretch means "fill the remaining space", subtracting margins automatically, and it's the standard name for -webkit-fill-available. This post compares 100%, calc() and stretch with a live demo, covers how it behaves on buttons, inputs, flex and grid, and checks this site at 400% zoom width.

    Front-EndCSSFront-EndAccessibilityBrowser Support
  • Phones Downloading 1920px Images? Fixing My Portfolio with sizes="auto"

    The sizes attribute for responsive images is hard to get right, and when it's wrong the browser picks an image that's too big. sizes="auto" lets the browser pick by the image's actual width. This post first answers whether it helps when you only have one image, then tests its rules and traps with a live demo, and finally applies it to my own portfolio: image data on the project list dropped by about 60% on phones.

    Front-EndHTMLFront-EndPerformanceBrowser Support
  • An Outside label Can Finally Reach the input Inside Shadow DOM: shadowrootreferencetarget

    A long-standing accessibility problem with Web Components: an outside <label for>, aria-labelledby or aria-describedby can't point to anything inside Shadow DOM. shadowrootreferencetarget lets a component say "when something points at me, it really means this element inside". This post tests what it can and can't do with live demos, where testing tools report false errors, and how it could help my own UI Kit.

    Front-EndHTMLWeb ComponentsFront-EndAccessibilityBrowser Support
  • Let ARIA Be the Single Source of Truth: Reading aria-valuenow with CSS attr()

    CSS attr() used to work only in content; now it takes a type and works in any property. This post tests it from an accessibility angle: progress bars, ratings and tree indentation that read ARIA attributes directly, so what people see and what screen readers get come from one source and can't drift apart. It also covers the traps I hit while testing, such as children not seeing a parent's attributes and an input's live value.

    Front-EndCSSFront-EndAccessibilityBrowser Support