freeCodeCamp Applied Accessibility:用自定义 CSS 实现“仅屏幕阅读器可见“的 sr-only 技术
2026/9/7 17:04:41 网站建设 项目流程

freeCodeCamp Applied Accessibility:用自定义 CSS 实现"仅屏幕阅读器可见"的 sr-only 技术

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

本文以 freeCodeCamp 课程中 Applied Accessibility(可访问性实战)板块的核心挑战——"Make Elements Only Visible to a Screen Reader by Using Custom CSS"为主体,讲解如何用一小段自定义 CSS(.sr-only)把内容在视觉上移出浏览器窗口、同时保留给屏幕阅读器读取。读完后,你将掌握该 CSS 规则的完整写法与每个属性值的作用、常见"隐藏却导致读屏失效"的错误写法,并能结合一个"堆叠条形图 + 隐藏数据表格"的真实页面场景完成可复制、可运行的实现。

为什么先讲语义化,再讲 CSS

该挑战位于课程板块 Applied Accessibility 的第 15 个位置(共 21 个挑战,见 challengeOrder)。原文档特意指出:这个板块前面的挑战全部没有用到任何 CSS,这恰恰说明了重要性——在引入视觉设计之前,先建立合理的文档大纲和语义化标签

而 CSS 的"魔力"同样能提升可访问性:当你想把"仅供屏幕阅读器阅读"的内容从视觉上隐藏起来时,就需要用 CSS 把这类元素定位到浏览器窗口的可视区域之外。

典型应用场景:图表的替代数据呈现

原文档给出的核心场景是:当信息以视觉形式存在(比如一张图表)时,屏幕阅读器用户需要一种替代的呈现方式(比如表格)来获取同样的数据

这个场景在课程中前后呼应:同板块的前一个挑战 Improve Chart Accessibility with the figure Element 教你用figurefigcaption为图表提供语义化分组与文字说明,并明确提到"另一个挑战会讲解如何用 CSS 把图表数据对应的表格版本移到屏幕外(off-screen),供屏幕阅读器用户使用"——即本挑战。

挑战的练习背景是:Camper Cat 为自己的训练页面做了一个堆叠条形图(stacked bar chart),展示每周在 Stealth & Agility、Combat、Weapons 三项训练上花费的小时数,并同时为视障用户提供了完整的数据表格。该表格已经带了sr-only类名,但 CSS 规则还没填完,需要补上关键属性值。

sr-only 规则的完整写法与逐行解析

原文档给出的标准 CSS 规则如下:

.sr-only { position: absolute; left: -10000px; width: 1px; height: 1px; top: auto; overflow: hidden; }

各属性值的含义:

  • position: absolute:让元素脱离正常文档流,为后续的绝对定位(left)提供依据;
  • left: -10000px:把元素整体左移到视口左侧 10000 像素处,远远超出任何常规屏幕的可视区域;
  • width: 1px; height: 1px:把元素尺寸压到 1 像素。这里不能写成 0px(原因见下一节);
  • top: auto:纵向位置不限制,保持自动;
  • overflow: hidden:即使 1 像素的内容放不下也不产生溢出,避免产生意外的滚动条。

这样处理后的元素:人眼看不到(已移出可视区)、不影响布局(绝对定位脱离了文档流),但仍存在于 DOM 和可访问性树中,屏幕阅读器照常朗读。

两条常见的错误"隐藏"写法

原文档特别强调:以下两种 CSS 做法达不到相同效果,是开发中最容易踩的坑:

  1. display: none;visibility: hidden;—— 会把内容对所有人隐藏,包括屏幕阅读器用户。屏幕阅读器同样读不到这些元素;
  2. 把尺寸写成零值,例如width: 0px; height: 0px;—— 这会把元素从文档流中"移除"(在可访问性树上被排除),屏幕阅读器会直接忽略它。

这正是本规则必须使用1px而非0px的根本原因:1px的元素仍是可访问性树的有效成员,而零尺寸元素会被读屏软件跳过。

值得佐证的是,freeCodeCamp 网站自身的样式中也维护了一个.sr-only类,见 global.css:

/* WCAG fix */ .sr-only { color: white; background-color: black; }

从源码结构看,该仓库在基础sr-only定位规则之上追加了color: white; background-color: black的"WCAG fix"。这是一种行业常见做法:当用户开启浏览器"高对比度"模式或系统级强制颜色时,overflow: hidden之外的元素可能因颜色被系统覆盖而"闪出"可见文字(俗称 invisible text 问题);将文字与背景显式设为白底黑字之外的组合(黑底白字),可确保即使命中可见区域也是不可辨识的,从而维持"视觉上隐藏"。

完整实战:在训练页面上应用 sr-only 表格

下面是该挑战的完整起始代码(seed)。页面上已经有一个用figure/figcaption包裹的堆叠条形图占位,以及一个带sr-only类的完整数据表格,<style>中的.sr-only规则留有四个待填的空:

<head> <style> .sr-only { position: ; left: ; width: ; height: ; top: auto; overflow: hidden; } </style> </head> <body> <header> <h1>Training</h1> <nav> <ul> <li><a href="#stealth">Stealth &amp; Agility</a></li> <li><a href="#combat">Combat</a></li> <li><a href="#weapons">Weapons</a></li> </ul> </nav> </header> <section> <h2>Master Camper Cat's Beginner Three Week Training Program</h2> <figure> <!-- Stacked bar chart of weekly training --> <p>[Stacked bar chart]</p> <br /> <figcaption>Breakdown per week of time to spend training in stealth, combat, and weapons.</figcaption> </figure> <table class="sr-only"> <caption>Hours of Weekly Training in Stealth, Combat, and Weapons</caption> <thead> <tr> <th></th> <th scope="col">Stealth &amp; Agility</th> <th scope="col">Combat</th> <th scope="col">Weapons</th> <th scope="col">Total</th> </tr> </thead> <tbody> <tr> <th scope="row">Week One</th> <td>3</td> <td>5</td> <td>2</td> <td>10</td> </tr> <tr> <th scope="row">Week Two</th> <td>4</td> <td>5</td> <td>3</td> <td>12</td> </tr> <tr> <th scope="row">Week Three</th> <td>4</td> <td>6</td> <td>3</td> <td>13</td> </tr> </tbody> </table> </section> <section id="stealth"> <h2>Stealth &amp; Agility Training</h2> <article><h3>Climb foliage quickly using a minimum spanning tree approach</h3></article> <article><h3>No training is NP-complete without parkour</h3></article> </section> <section id="combat"> <h2>Combat Training</h2> <article><h3>Dispatch multiple enemies with multithreaded tactics</h3></article> <article><h3>Goodbye, world: 5 proven ways to knock out an opponent</h3></article> </section> <section id="weapons"> <h2>Weapons Training</h2> <article><h3>Swords: the best tool to literally divide and conquer</h3></article> <article><h3>Breadth-first or depth-first in multi-weapon training?</h3></article> </section> <footer>&copy; 2018 Camper Cat</footer> </body>

注意这张表格本身也体现了可访问性细节:<caption>提供了表格标题,表头使用scope="col",行头使用scope="row",让屏幕阅读器在逐行朗读时能正确报出"这是哪一列/哪一行"的上下文。这正是sr-only隐藏方式的价值——表格虽然人眼不可见,但其完整的可访问性语义被完整保留。

参考答案

只需用absolute-10000px1px1px四个值补全 CSS 规则:

<style> .sr-only { position: absolute; left: -10000px; width: 1px; height: 1px; top: auto; overflow: hidden; } </style>

其余 HTML 结构保持不变。完成后的完整解法见 挑战文件中的 --solutions 段。

测试如何验证你的 CSS

该挑战的测试套件(hints 段,完整内容见 挑战原文)从两个维度验证实现:

维度一:计算样式(浏览器实际生效的值)。测试直接读取 DOM 中.sr-only元素的计算样式并断言:

const srOnly = document.querySelector('.sr-only'); const position = window.getComputedStyle(srOnly).position; assert.equal(position, 'absolute'); const left = window.getComputedStyle(srOnly).left; assert.equal(left, '-10000px');

getComputedStyle返回的是浏览器解析后的最终值,因此left必须是计算后的-10000px——这解释了为什么填left: -10000px有效,而填其他负值(如left: -9999px)会失败。

维度二:源码匹配。对widthheight采用正则直接匹配你的代码文本:

assert.match(code, /width:\s*?1px/gi); assert.match(code, /height:\s*?1px/gi);

这类"计算样式 + 源码正则"的双重校验,正是 freeCodeCamp 经典编辑器(classic editor)挑战的标准测试模式:源码中的--hints--段落被转成测试用例,由挑战框架在沙箱环境中执行(执行环境可参考 frame.ts,测试运行组件见 test-suite.tsx)。

小结:sr-only 的正确使用边界

  • 适用:需要"视觉隐藏、读屏可读"的内容——图表的替代数据表格、跳转链接的辅助文本、仅辅助读屏的上下文说明等;
  • 不适用:真正对所有人都不需要展示的内容,那应该直接删除或用语义手段处理;
  • 禁用display: nonevisibility: hidden0px尺寸——它们会让屏幕阅读器一并失去这些内容;
  • 实现要点position: absolute+ 大负值left+1px宽高 +overflow: hidden,缺一不可。

掌握这一技术后,你可以把它与前面讲过的figure/figcaption图表语义化组合使用:figure负责让图表对读屏用户"可解释",sr-only表格负责让图表的原始数据对读屏用户"可获取",两者共同构成数据可视化可访问性的完整方案。

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询