---
title: "Blog - Neil's portfolio"
description: "Neil's blog: notes on frontend, design, and accessibility"
canonical_url: "https://neillin.com/en/blog/"
meta:
  author: Neil
  keywords: "Accessibility, Design Management, Data Visualization, UI, UX, Layout"
  "og:description": "Neil's blog: notes on frontend, design, and accessibility"
  "og:image": "https://neillin.com/_og/s/o_968acc07fd28a720.png"
  "og:image:height": "600"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "Blog - Neil's portfolio"
  "twitter:image": "https://neillin.com/_og/s/o_968acc07fd28a720.png"
---

> Index of every page on this site: [llms.txt](https://neillin.com/llms.txt)

:::

# 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](https://neillin.com/en/blog/html-usermedia "Go to  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.31 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")HTMLJavaScriptFront-EndAccessibilityBrowser Support
- ## [Make a Headline Fill the Line Exactly: Testing text-fit, and the Trap Where Zooming Makes Text Smaller](https://neillin.com/en/blog/css-text-fit "Go to  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.25 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support
- ## [Designers Could Always Draw Them, Now Developers Can Build Them: Squircles, Coupons, Step Arrows and Cut-Corner Buttons with corner-shape](https://neillin.com/en/blog/css-corner-shape "Go to  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.16 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support
- ## [Writing Accessibility into CSS with if() and @function: Reduced Motion, More Contrast, Minimum Target Size](https://neillin.com/en/blog/css-if-function "Go to  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.16 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support
- ## [setHTML() Is Safe, but It Stripped All My ARIA](https://neillin.com/en/blog/html-sethtml "Go to  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.16 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")HTMLJavaScriptFront-EndAccessibilityBrowser Support
- ## [One Line to Change Opacity with alpha(), One Line to Roll Back with revert-rule: Testing Two Small CSS Tools](https://neillin.com/en/blog/css-alpha-revert-rule "Go to  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.15 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support
- ## [Why Does width: 100% Overflow Its Container? Fill It Exactly with stretch](https://neillin.com/en/blog/css-stretch "Go to  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.14 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support
- ## [Phones Downloading 1920px Images? Fixing My Portfolio with sizes="auto"](https://neillin.com/en/blog/html-sizes-auto "Go to  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.14 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")HTMLFront-EndPerformanceBrowser Support
- ## [An Outside label Can Finally Reach the input Inside Shadow DOM: shadowrootreferencetarget](https://neillin.com/en/blog/shadow-dom-reference-target "Go to  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.14 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")HTMLWeb ComponentsFront-EndAccessibilityBrowser Support
- ## [Let ARIA Be the Single Source of Truth: Reading aria-valuenow with CSS attr()](https://neillin.com/en/blog/css-attr "Go to  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.13 Oct 2026 [Front-End](https://neillin.com/en/blog?category=frontend "See all posts in Front-End")CSSFront-EndAccessibilityBrowser Support

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://neillin.com/en/#website","@type":"WebSite","inLanguage":"en-US","name":"Neil's portfolio","url":"https://neillin.com/en/","translationOfWork":{"@id":"https://neillin.com/#website"}},{"@id":"https://neillin.com/en/blog#webpage","@type":"CollectionPage","description":"Neil's blog: notes on frontend, design, and accessibility","inLanguage":"en","name":"Blog","url":"https://neillin.com/en/blog/","isPartOf":{"@id":"https://neillin.com/en/#website"},"mainEntity":{"@id":"https://neillin.com/en/blog#blog"},"potentialAction":[{"@type":"ReadAction","target":["https://neillin.com/en/blog/"]}]},{"@id":"https://neillin.com/en/#person","@type":"Person","jobTitle":"UI/UX Designer","name":"Neil Lin","url":"https://neillin.com/en/","sameAs":["https://github.com/Neil-Lin"]},{"@id":"https://neillin.com/en/blog#blog","@type":"Blog","inLanguage":"en","name":"Blog","url":"https://neillin.com/en/blog/","blogPost":[{"@type":"BlogPosting","headline":"Building a Video Call Waiting Room with \u003Cusermedia>: The Browser Handles Permissions, but Six Things Are Still on You","description":"\u003Cusermedia> 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.","url":"https://neillin.com/en/blog/html-usermedia/","datePublished":"2026-10-31","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Make a Headline Fill the Line Exactly: Testing text-fit, and the Trap Where Zooming Makes Text Smaller","description":"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.","url":"https://neillin.com/en/blog/css-text-fit/","datePublished":"2026-10-25","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Designers Could Always Draw Them, Now Developers Can Build Them: Squircles, Coupons, Step Arrows and Cut-Corner Buttons with corner-shape","description":"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.","url":"https://neillin.com/en/blog/css-corner-shape/","datePublished":"2026-10-16","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Writing Accessibility into CSS with if() and @function: Reduced Motion, More Contrast, Minimum Target Size","description":"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.","url":"https://neillin.com/en/blog/css-if-function/","datePublished":"2026-10-16","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"setHTML() Is Safe, but It Stripped All My ARIA","description":"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.","url":"https://neillin.com/en/blog/html-sethtml/","datePublished":"2026-10-16","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"One Line to Change Opacity with alpha(), One Line to Roll Back with revert-rule: Testing Two Small CSS Tools","description":"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.","url":"https://neillin.com/en/blog/css-alpha-revert-rule/","datePublished":"2026-10-15","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Why Does width: 100% Overflow Its Container? Fill It Exactly with stretch","description":"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.","url":"https://neillin.com/en/blog/css-stretch/","datePublished":"2026-10-14","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Phones Downloading 1920px Images? Fixing My Portfolio with sizes=\"auto\"","description":"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.","url":"https://neillin.com/en/blog/html-sizes-auto/","datePublished":"2026-10-14","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"An Outside label Can Finally Reach the input Inside Shadow DOM: shadowrootreferencetarget","description":"A long-standing accessibility problem with Web Components: an outside \u003Clabel 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.","url":"https://neillin.com/en/blog/shadow-dom-reference-target/","datePublished":"2026-10-14","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Let ARIA Be the Single Source of Truth: Reading aria-valuenow with CSS attr()","description":"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.","url":"https://neillin.com/en/blog/css-attr/","datePublished":"2026-10-13","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Zoomed In and the Top of Your Centered Content Is Gone? Make It Reachable with safe center","description":"align-items: center is one of the most common lines of CSS, but when the content is bigger than its container it overflows on both sides, and the part that goes off the top and left can't be scrolled to. It happens easily when people zoom to 400%, and keyboard users who Tab there can't see focus. This post tests safe center with live demos, lists which centering methods break and which are safe by default, and checks this site too.","url":"https://neillin.com/en/blog/css-safe-alignment/","datePublished":"2026-10-13","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"h1 Inside a section No Longer Shrinks: and I Fixed My Site's h1 Too","description":"Browsers changed their built-in styles: an h1 inside section, article, aside or nav no longer shrinks level by level. This post compares the old and new styles with a live demo, explains why they used to shrink and why screen readers never followed along, and whether the change affects your site. I also checked my own site and changed every page's h1 from the site name to the page title.","url":"https://neillin.com/en/blog/html-nested-h1/","datePublished":"2026-10-13","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"No More Hand-Rolled Roving tabindex: Arrow-Key Navigation with focusgroup","description":"Toolbars, tabs and menus are supposed to take a single Tab stop and move with the arrow keys inside, which used to mean writing a roving tabindex by hand. focusgroup makes it one HTML attribute. Tested in Chromium 153, this post covers the six behavior types, modifiers, the roles it adds for you, two traps (the tab entry point, and a bare focusgroup doing nothing), and a fallback for browsers without support.","url":"https://neillin.com/en/blog/focusgroup/","datePublished":"2026-10-10","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Make Screen Readers Speak: Replacing aria-live with ariaNotify()","description":"Announcing \"Added to cart\" to screen readers used to mean hiding an aria-live region and stuffing text into it, which often went unspoken. ariaNotify() lets you ask the screen reader to speak directly. Starting from an aria-live problem on my own site, this post covers how to use it, the element version and language, the limits of priority, and a fallback to live regions for browsers without it.","url":"https://neillin.com/en/blog/aria-notify/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Is a CSS-Only Carousel Accessible Enough? Compared Against My UI Kit","description":"::scroll-marker and ::scroll-button() let CSS build a carousel's dots and previous/next buttons with no JavaScript. But carousels have always been an accessibility trouble spot, so is the native version good enough? With identical content, this post puts a native CSS carousel next to the \u003Cau-carousel> I built for Accesserty UI Kit and tests the accessibility tree and keyboard behavior.","url":"https://neillin.com/en/blog/css-carousel-a11y/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Why Do Web Components Flash? Fixing It with Declarative Shadow DOM","description":"A web component's Shadow DOM can't appear until JavaScript runs, so it flashes during SSR and vanishes entirely if JavaScript fails. Declarative Shadow DOM lets you write the shadow root straight into HTML. Using demos with JavaScript switched off, this post covers the syntax, how components should take over an existing root, the limits of dynamic insertion, and the traps I hit in Vue/Nuxt and how to get around them.","url":"https://neillin.com/en/blog/declarative-shadow-dom/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"How to Write a Dialog Today: From showModal() to command and closedby","description":"You don't need to hand-roll modals out of divs anymore. This post rounds up how to write \u003Cdialog> in 2026: show() vs showModal(), opening and closing with zero JavaScript via Invoker Commands, choosing who can close it with closedby, catching unsaved changes with request-close, getting results out with form method=\"dialog\", plus accessibility and animation details. Every section has a demo you can try.","url":"https://neillin.com/en/blog/dialog-modern-guide/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Why Can't Ctrl+F Find Collapsed Content? A Look at hidden=\"until-found\"","description":"Content collapsed with hidden, like FAQs and accordions, can't be found by in-page search. hidden=\"until-found\" keeps content collapsed but findable by search and deep links, and expands it when found. This post compares four ways to collapse content with live demos, plus three traps I ran into while testing.","url":"https://neillin.com/en/blog/hidden-until-found/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Popover auto, manual and hint: What's Actually the Difference? I Built Demos to Find Out","description":"One popover attribute, three values: auto, manual and hint decide whether a popover closes when you click outside and whether opening it closes others. This post compares them with demos you can play with, plus the accessibility details you still have to add yourself when building tooltips with hint, and what happens in browsers that don't support it.","url":"https://neillin.com/en/blog/popover-auto-manual-hint/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Tooltip Getting Cut Off? Let the Browser Find a Spot with @position-try","description":"Tooltips and menus get cut off near the edge of the screen, and flipping them used to take JavaScript. position-try-fallbacks and @position-try let CSS handle it: when there isn't room, try another position. With a demo where you can drag the anchor around, this post covers the three ways to write it, how margins flip too, how the browser remembers the position, position-try-order, and what happens when nothing fits.","url":"https://neillin.com/en/blog/position-try/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Page Jumps While You Read? A Look at Scroll Anchoring and overflow-anchor","description":"You're halfway through an article when an image or ad above finally loads, and the whole page jumps down. Browsers have a built-in fix called scroll anchoring. With a hands-on demo, this post tests when it works and when it can't help, shares two real examples from my own site, and covers the smooth-scrolling issue I fixed along the way.","url":"https://neillin.com/en/blog/scroll-anchoring/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Spaces Between Chinese and English? Let text-autospace Add Them for You","description":"Whether to put spaces between Chinese characters and English words or numbers has been argued about for years. text-autospace lets the browser add a little space automatically, so you don't have to type it. With side-by-side demos, I tested how wide the gap is, whether it stacks with typed spaces, whether copied text changes, and what to watch for in code blocks. Then I turned it on for this site.","url":"https://neillin.com/en/blog/text-autospace/","datePublished":"2026-10-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"AI Is Great at Research — But Is It a Reliable Researcher? So I Just Asked It","description":"AI 2027's core assumption is that AI can do its own research and improve itself. But after using AI for product research every day, my feeling is: the real bottleneck isn't 'can't find the data' — it's that AI doesn't know when it shouldn't trust what it found, and sometimes doesn't even know the question itself was wrong. So I asked it directly.","url":"https://neillin.com/en/blog/ai-reliable-researcher/","datePublished":"2026-08-30","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Who Forces Websites to Be Accessible? (Part 2): Eight More Jurisdictions, and the Gray Zone Between 'Organizing' and 'Certifying'","description":"The previous article surveyed 16 jurisdictions and I meant to go straight into a deep comparison of certification marks — but while collecting data on Hong Kong and Qatar, I found that many 'government marks' I'd assumed were official are actually run by private bodies, with the government merely co-organizing. So I widened the map to 24 jurisdictions to finish the institutional groundwork first.","url":"https://neillin.com/en/blog/a11y-world-rules-part2/","datePublished":"2026-07-17","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Modern CSS & HTML Cheat Sheet: 115 Features, Support & What to Try Next","description":"A scannable checklist of modern CSS and HTML features—grouped by layout, selectors, color, typography, animation and more, plus declarative HTML additions like `\u003Cgeolocation>`, `focusgroup` and Invoker Commands—each with its purpose, an example, and browser support.","url":"https://neillin.com/en/blog/css-techniques-checklist/","datePublished":"2026-07-06","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Who Forces Websites to Be Accessible? A Comparison of Web Accessibility Regimes Across 16 Jurisdictions","description":"What started as a simple effort to collect each country’s marks, regulations, and testing criteria turned into something bigger — halfway through, I realized I first needed to understand each country’s policy.","url":"https://neillin.com/en/blog/a11y-world-rules/","datePublished":"2026-06-09","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Accessibility Testing Should Not Be Confined by Professional Silos","description":"In the past, accessibility was often synonymous with regulatory compliance, formal audits, or a checklist dusted off only at the very end of a project. But things have changed.","url":"https://neillin.com/en/blog/accessibility-testing/","datePublished":"2026-05-30","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Forbes Accessibility 200","description":"A few days ago, I came across the Forbes Accessibility 200 list.","url":"https://neillin.com/en/blog/2026-forbes-accessibility/","datePublished":"2026-05-28","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Are the Users of Web Accessibility Changing?","description":"Not long ago, Anthropic engineer Thariq mentioned that, under the assumption that “humans no longer manually edit code,” HTML is more suitable than Markdown for interacting with AI.","url":"https://neillin.com/en/blog/a11y-tree-for-who/","datePublished":"2026-05-13","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Accessibility Web Services Coated in AI Sugar?","description":"When AI promises to fix web accessibility at runtime, but ends up repeating the same old widget problem.","url":"https://neillin.com/en/blog/ai-sugar/","datePublished":"2026-05-08","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Reflections on Digital Accessibility (April 2026)","description":"Some thoughts on Digital Accessibility and AI.","url":"https://neillin.com/en/blog/2026-04-a11y-opinion/","datePublished":"2026-04-30","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Accesserty DevCheck — Simulate and Detect Accessibility Challenges Before You Ship","description":"Stop waiting for complaints. Start feeling what your users feel — directly inside your dev workflow.","url":"https://neillin.com/en/blog/a11y-dev-tool/","datePublished":"2025-05-31","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"The Invisible Experience Gap  —  Why It’s So Hard to Find Truly Usable Websites","description":"Why I decided to display accessibility signals in search results.","url":"https://neillin.com/en/blog/search-good-website/","datePublished":"2025-05-29","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}},{"@type":"BlogPosting","headline":"Building Accesserty — An Accessibility Experience from Search to Development","description":"A small product ecosystem I built in about a month, aimed at improving the accessible web experience.","url":"https://neillin.com/en/blog/building-accesserty-an-accessibility-experience-from-search-to-development/","datePublished":"2025-05-23","author":{"@id":"https://neillin.com/en/#person"},"publisher":{"@id":"https://neillin.com/en/#person"}}],"publisher":{"@id":"https://neillin.com/en/#person"}},{"@id":"https://neillin.com/en/blog/#/schema/breadcrumb-list/1","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"home page","item":"https://neillin.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://neillin.com/en/blog/"}]}]}
```

## Sitemap

See the full [sitemap](https://neillin.com/sitemap.md) for all pages.
