hello hello Lee Cattarin... on the internet! 2026-02-19T21:09:51Z https://leecat.art/ Lee Cattarin lee.cattarin@gmail.com screen reader optimizations 2026-02-19T21:09:51Z https://leecat.art/screen-reader-optimizations/ <h2 id="context">context</h2> <p>recently, I've been working on a <a href="https://inherentlee.codeberg.page/spoonfairies/" target="_blank" rel="external">website for a project called spoonfairies</a>. On the providers page, we list a series of names along with their pronouns, location, and services offered. Visually, it looks like this:</p> <p><img src="https://leecat.art/img/spoonfairies-provider.png" alt="A provider listing from spoonfairies. On the top row of text, it shows the provider's name in large purple text, then their pronouns in slightly opaque white and slightly smaller font, then aligned on the right, a map pin emoji and their general location in standard size white text. On the second row of text, it lists a few services the provider offers, comma separated." loading="lazy" decoding="async" width="1000" height="147"></p> <h2 id="pronouns">pronouns</h2> <p>at first, all three pieces of information in the top row had no extra styling - it was just a line of text with the same color and size throughout. The location bit also didn't exist yet, so we're going to briefly ignore it. Screenreader testing (with NVDA, specifically) informed me that, when reading through a long list of providers, parentheses become <em>very</em> irritating. Imagine hearing the following:</p> <blockquote> <p>Lorem Ipsum left parentheses she slash her right parentheses web accessiblity webdev. Dolor Sit left parentheses they slash them right parentheses housecleaning. Amet Consectetur left parentheses he slash him right parentheses webdev spreadsheets software.</p> </blockquote> <p>...ad nauseam. Kinda irritating.</p> <h3 id="the-fix">the fix</h3> <p>put the pronouns in a span that provides special styling, and use <code>::before</code> and <code>::after</code> to apply parentheses.</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/providers/lorem-ipsum<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Lorem Ipsum <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pronouns<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>she/her<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre> <pre class="language-css"><code class="language-css"><span class="token selector">.pronouns::before</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"("</span> / <span class="token string">""</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.pronouns::after</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">")"</span> / <span class="token string">""</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre> <p><strong>the slash is the magic there.</strong> The string before the slash indicates the visual content, and the string after the slash is the alternative text content. I went happily on my way.</p> <p>plus, this is neat - now I can style the pronouns separately. Let's make them the standard text color rather than the link color, and a bit smaller, and a smidge opaque... nice.</p> <h2 id="location">location</h2> <p>ooh, time to implement locations! I did my same ol' trick.</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/providers/lorem-ipsum<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Lorem Ipsum <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pronouns<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>she/her<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>location<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Tacoma<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre> <pre class="language-css"><code class="language-css"><span class="token selector">.location::before</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"📍"</span> / <span class="token string">"is based out of"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre> <p>I even added actual alternative text rather than an empty string to provide some context. Pronouns, I figured, could exist without much context, as it's pretty common for them to follow directly after names in introductions, but location isn't as much of a given.</p> <p>again, style em up nice, more of a standard text look, right-aligned. Cool.</p> <h2 id="a-bigger-problem-than-parentheses">a bigger problem than parentheses</h2> <p>...then I did some screen reader testing. Which I should have done directly after the pronouns bit. Turns out, I wasn't thrilled with what the <code>&lt;span&gt;</code>s did.</p> <p>at least with fairly default settings in NVDA, the <code>&lt;span&gt;</code>s broke up the way the link was read out. Suddenly, I was getting:</p> <blockquote> <p>visited link Lorem Ipsum visited link she slash her visited link Tacoma</p> </blockquote> <p>this is all one link, mind you. The <code>&lt;a&gt;</code> tag isn't broken into three links. But the <code>&lt;span&gt;</code>s apparently break up the screen reader output anyway (in NVDA, that's a continual caveat).</p> <p>ooookay... what next?</p> <h3 id="total-overhaul">total overhaul</h3> <p>I moved away from my <code>content</code> approach entirely (well, I kept it around as a failsafe, but it's not running the show now). Instead, I switched over to an <code>aria-label</code> for the whole link.</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/providers/lorem-ipsum<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Lorem Ipsum she/her is based out of Tacoma<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Lorem Ipsum <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pronouns<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>she/her<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>location<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Tacoma<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre> <p>(technically, all this is templated to hell and back. I would hope that's obvious given I'm talking about <em>lists</em> of these entries.)</p> <p>now, after more screen reader testing, it reads out smoothly. The <code>aria-label</code> precludes the actual link text and cleanly says what needs to be said, with nothing breaking up the text and the whole thing easily recognized as one link. <em>And</em> I've got my fancy styling. Sweet.</p> crow 2026-02-09T00:00:00Z https://leecat.art/crow/ charlie the alpaca handspun 2026-02-05T00:00:00Z https://leecat.art/charlie-the-alpaca-handspun/ <p>Fiber from Circle R Ranch. 100% alpaca, from Charlie the alpaca.</p> ruby the alpaca handspun 2026-01-27T00:00:00Z https://leecat.art/ruby-the-alpaca-handspun/ <p>Fiber from Circle R Ranch. 100% alpaca, from Ruby the alpaca.</p> hand-dyed gold handspun 2026-01-24T00:00:00Z https://leecat.art/hand-dyed-gold-handspun/ <p>Fiber from <a href="https://paradisefibers.com" target="_blank" rel="external">Paradise Fibers</a>. 70% merino/30% nylon. Hand-dyed by me.</p> spinner's dream handspun 2026-01-18T00:00:00Z https://leecat.art/spinners-dream-handspun/ <p>Fiber from <a href="https://paradisefibers.com" target="_blank" rel="external">Paradise Fibers</a>. 40% merino/20% alpaca/20% camel/20% mulberry silk. Scrumptiously soft.</p> rambouillet handspun 2026-01-18T00:00:00Z https://leecat.art/rambouillet-handspun/ <p>Fiber from <a href="https://woolgatherings.com" target="_blank" rel="external">Woolgatherings</a>. 100% rambouillet. Hand-dyed!</p> fire & ice handspun 2026-01-18T00:00:00Z https://leecat.art/fire-and-ice-handspun/ <p>Fiber from <a href="https://www.etsy.com/shop/JakiraFarms" target="_blank" rel="external">Jakira Farms</a> in Fire &amp; Ice colorway. 100% merino.</p> dyeing fiber 2026-01-18T00:00:00Z https://leecat.art/dyeing-fiber/ <p>hand-dyed with acid dyes</p> coral reef handspun 2026-01-18T00:00:00Z https://leecat.art/coral-reef-handspun/ <p>Fiber from <a href="https://www.etsy.com/shop/JakiraFarms" target="_blank" rel="external">Jakira Farms</a> in Coral Reef colorway. 100% merino.</p>