一文了解Web的可访问性

作为前端开发者,我们常常沉浸在UI动效、性能优化和新技术栈的研究中,却忽视了一个直接影响25%用户的重要问题——Web 可访问性。本文将深入解析前端可访问性的核心要点及具体实现。

可访问性是什么?

Web 可访问性是指通过设计和开发技术,确保网页或应用能够被所有人无障碍地访问和使用,包括残障人士、老年用户、临时受伤者(如手部受伤)或使用特殊设备(如屏幕阅读器、语音控制工具)的人群。其核心目标是消除访问障碍,实现信息平等。

Web 可访问性的重要性:

  • 法律合规:许多国家和地区(如欧盟、美国)要求公共网站必须符合可访问性标准(如 WCAG),否则可能面临法律风险。如果你的应用用户人群是这些国家的,就需要特别关注开发中的可访问性。

  • 用户体验:提升所有用户的操作便利性,例如清晰的导航、高对比度配色对普通用户同样友好。

  • SEO 优化:可访问性实践(如语义化 HTML)通常与搜索引擎优化(SEO)兼容,提升搜索排名。

WCAG

WCAG(Web Content Accessibility Guidelines,网页内容可访问性指南)是由 W3C(万维网联盟)制定的国际标准,旨在确保网页内容对所有人均可访问和使用。

根据 Web 内容可访问性指南(WCAG),Web 可访问性可以归纳为以下四个核心原则

  • 可感知: 用户必须能够感知提供的信息。

    • 文本替代:为非文本内容(如图片、图表)提供 alt 文本或描述。

    • 多媒体可访问:为视频提供字幕,为音频提供文本转录。

    • 适配性:内容在不同设备(如屏幕阅读器、移动端)上可正常显示。

  • 可操作: 用户界面组件和导航必须是可操作的。

    • 键盘导航:所有功能可通过键盘(Tab、Enter、方向键)操作。

    • 避免闪烁内容:防止快速闪烁的动画引发光敏性癫痫。

    • 足够时间:用户有充足时间阅读或操作(如表单填写倒计时可延长)。

  • 可理解: 用户必须能够理解和使用信息和用户界面。

    • 一致性:导航、标签、按钮功能保持一致。

    • 错误提示:表单输入错误时提供明确的文字说明和修正建议。

    • 语言明确:避免使用复杂术语,页面语言通过 lang 属性声明。

  • 健壮: 内容必须兼容当前和未来的技术。

    • 语义化 HTML:使用标准标签(如 <button><nav>),避免滥用 <div> 模拟控件。

    • ARIA 支持:为动态内容补充 ARIA 属性(如 rolearia-label)。

WCAG 要求分为三个等级,从低到高依次为:

可访问性的前端实现

Web 可访问性需要贯穿开发全流程,从前端技术实现到设计协作,再到测试验证。

语义化HTML

根据内容的含义选择合适的 HTML 标签,这有助于屏幕阅读器等辅助技术理解页面结构,方便用户导航。

<!-- 错误:用 div 模拟按钮 -->
<div onclick="submit()">提交</div>

<!-- 正确:语义化按钮 -->
<button onclick="submit()">提交</button>

常见的语义化标签包括:

标签作用
<header>

定义文档或节的页眉,包含介绍性内容,如网站标志、标题、导航栏等

<nav>

专门定义导航链接部分,包含指向不同页面或同一页面不同部分的主要导航链接

<main>

规定文档的主要内容,该内容应独一无二,不包含重复出现的内容

<article>

表示文档中独立、完整且可独立分发的内容块,如博客文章、新闻报道等

<section>

对文档内容进行分块,将相似主题的内容分组,不一定能独立存在

<aside>

定义所处内容之外的内容,常表现为侧边栏或插入内容,与周围内容相关但非主要部分

<footer>

定义文档或节的页脚,包含版权信息、作者信息、联系方式等

<h1>

 - <h6>

定义不同级别的标题,构建文档大纲结构,利于搜索引擎理解及用户浏览

<ul>

创建无序列表,列表项无特定顺序,以项目符号显示

<ol>

创建有序列表,列表项按数字或字母顺序排列,适用于强调顺序的内容

<dl>

创建定义列表,包含<dt>(定义术语)和<dd>(定义描述)对,展示术语及其定义

<blockquote>

定义从其他来源引用的内容,视觉上常呈现为缩进,可搭配<cite>指定引用来源

<q>

定义短的行内引用,浏览器自动在两端加引号

<time>

定义日期和时间,方便浏览器和搜索引擎识别,可通过datetime属性指定具体值

语义化 HTML 的好处:

  • 提高可访问性: 语义化HTML可以帮助辅助技术(如屏幕阅读器)更好地理解页面结构和内容,从而为残障用户提供更好的体验。

  • 增强SEO(搜索引擎优化): 搜索引擎爬虫依赖 HTML 标签来理解网页的内容和结构。使用语义化HTML可以使搜索引擎更准确地抓取和索引页面,有助于提高搜索排名。

  • 改善代码可读性和维护性: 语义化HTML使代码更具结构性和逻辑性,易于理解和维护。

  • 符合Web标准和最佳实践: 语义化HTML符合W3C和其他标准组织推荐的最佳实践,有助于构建高质量的Web应用。

键盘导航

键盘导航是 Web 可访问性的重要组成部分,它允许用户仅使用键盘来浏览和操作网页,这对于那些无法使用鼠标或其他指针设备的用户(如肢体残障人士、键盘快捷方式偏好者)来说至关重要。

可聚焦元素

可聚焦元素是指用户可以通过键盘的 Tab 键将焦点移动到这些元素上的元素,并且焦点顺序应符合逻辑。常见的可聚焦元素包括链接(<a>)、按钮(<button>)、输入框(<input><textarea>)、下拉框(<select>)等。

<a href="#">前端充电宝</a>
<button>点击我</button>
<input type="text"placeholder="输入内容">
<select>
<option value="1">选项1</option>
<option value="2">选项2</option>
</select>

在上述代码中,用户可以使用 Tab 键依次将焦点移动到链接、按钮、输入框和下拉框上。

焦点顺序
  • 自然顺序:键盘焦点的移动顺序应该与网页内容的逻辑和视觉顺序一致。通常,焦点会按照 HTML 文档中元素出现的先后顺序进行移动。例如,在一个表单中,焦点会从第一个输入框开始,依次移动到后续的输入框、按钮等元素。

  • 调整顺序:在某些情况下,可能需要调整焦点顺序。可以使用 tabindex 属性来实现。

    • tabindex="0":将元素添加到正常的 Tab 顺序中,即使该元素默认不可聚焦。

    • tabindex="-1":使元素可聚焦,但不包含在正常的 Tab 顺序中,可以通过 JavaScript 等方式将焦点设置到该元素上。

    • tabindex="正数":指定元素的焦点顺序,数值越小越先获得焦点,但不建议过多使用这种方式,因为可能会破坏自然的焦点顺序。

焦点可见性

当元素获得焦点时,应该有明显的视觉指示,以便用户清楚地知道当前焦点所在的位置。可以通过修改元素的样式(如改变边框颜色、添加背景色、显示下划线等)来实现。

button:focus, input:focus, a:focus{
outline:2px solid #007BFF;/* 蓝色边框 */
box-shadow:005pxrgba(0,123,255,0.5);/* 添加阴影效果 */
}

注意事项:

  • 避免移除默认的outline样式,除非提供了更好的替代方案。

  • 提供高对比度的颜色,确保视觉上有足够的可见性。

键盘操作支持
  • 常见操作:不同类型的元素应该支持相应的键盘操作。例如:

    • 链接:按下 Enter 键可以激活链接,跳转到相应的页面。

    • 按钮:按下 Enter 键或 Space 键可以触发按钮的点击事件。

    • 输入框:可以使用方向键在输入框内移动光标,按下 Enter 键在某些情况下可以提交表单。

    • 下拉框:使用方向键可以选择下拉框中的选项,按下 Enter 键可以确认选择。

  • 自定义元素的键盘操作:对于自定义的交互元素(如自定义菜单、对话框等),需要通过 JavaScript 来实现相应的键盘操作支持。例如,一个自定义菜单可以通过监听键盘事件,根据用户按下的方向键来切换菜单项的选中状态,按下 Enter 键来执行相应的操作。

跳过导航

对于一些大型网页,可能存在大量的导航链接和重复的内容,用户可能希望快速跳过这些内容,直接访问主要内容。这时可以提供 “跳过导航” 链接。

实现方法:在页面顶部添加一个隐藏的链接,当用户使用键盘将焦点移动到该链接时,链接显示出来,用户按下 Enter 键可以直接跳转到页面的主要内容区域。

<a href="#main-content" class="skip-nav">跳过导航</a>
<header>
    <nav>
        <ul>
            <li><a href="#">首页</a></li>
            <li><a href="#">产品</a></li>
            <li><a href="#">关于我们</a></li>
        </ul>
    </nav>
</header>
<main id="main-content">
    <h1>主要内容标题</h1>
    <p>主要内容文本...</p>
</main>
.skip-nav{
position: absolute;
top:-40px;
left:0;
background:#fff;
padding:8px;
border:1px solid #ccc;
transition: top 0.3s ease;
}

.skip-nav:focus{
top:0;
}

这样,当用户使用键盘将焦点移动到该链接时,链接会显示出来,按下 Enter 键可以直接跳转到页面的主要内容区域。

测试验证
  • 手动测试: 使用键盘在网页上进行导航,检查焦点顺序是否正确、焦点可见性是否明显、元素的键盘操作是否正常等。

    • Tab键测试:通过Tab键逐个测试页面上的交互元素,确保每个元素都可以被聚焦并操作。

    • Shift + Tab:测试反向导航,确保焦点顺序正确。

    • Enter和Space 键:测试按钮、链接等交互元素是否可以通过Enter或Space键激活。

    • Esc键:测试模态对话框、下拉菜单等是否可以通过Esc键关闭。

  • 自动化测试:使用 axe-core 工具库进行检查。

ARIA 属性

ARIA(Accessible Rich Internet Applications)属性是 HTML5 规范的一部分,旨在帮助开发者增强网页的可访问性,特别是在处理动态内容和复杂用户界面时。通过使用ARIA属性,可以为屏幕阅读器和其他辅助技术提供更多的信息,从而提升用户体验。

ARIA 属性主要分为三类:角色、状态、属性。

角色

角色定义了元素在页面中的功能或用途,常见的角色包括buttonmenudialog等。

  • role="button":将一个普通的 <div> 元素定义为按钮,使其具有按钮的语义。

<div role="button"tabindex="0">前端充电宝</div>
  • role="menu" 和 role="menuitem":用于创建自定义菜单,明确菜单和菜单项的角色。

<ul role="menu">
<li role="menuitem"><a href="#">选项1</a></li>
<li role="menuitem"><a href="#">选项2</a></li>
</ul>
  • role="dialog":用于定义一个对话框。

<div id="dialog"role="dialog"aria-modal="true">
<h2>标题</h2>
<p>内容</p>
<button id="closeDialog">关闭</button>
</div>

注意事项:

  • 尽量使用原生HTML元素(如<button><nav>等),它们自带语义化角色。

  • 只有在必要时才使用role属性来增强自定义组件的可访问性。

状态

状态表示元素当前的状态,如是否选中、是否展开等。常见的状态包括aria-checkedaria-expanded等。

  • aria-checked:用于复选框和单选框,指示其选中状态。

<input type="checkbox"id="check-box"aria-checked="false">
<label for="check-box">选择</label>
  • aria - expanded:用于可展开 / 折叠的元素,如菜单、手风琴组件等,指示其展开状态。

<button aria-controls="content"aria-expanded="false">展开内容</button>
<div id="content"hidden>具体内容</div>
属性

属性提供了额外的信息,如标签、描述等。常见的属性包括aria-labelaria-labelledbyaria-describedby等。

  • aria-label:为元素提供一个明确的标签,用于替代元素内部的文本,特别是当元素没有可见文本时,适用于简单的替代文本。

<input type="search"aria-label="搜索框">
<button aria-label="关闭菜单">X</button>
  • aria-labelledby:引用其他元素的ID作为标签来源,适用于引用现有文本作为标签的情况。

<h1 id="page-title">网站</h1>
<nav aria-labelledby="page-title">
<ul>
<li><a href="#home">首页</a></li>
<li><a href="#about">关于我们</a></li>
</ul>
</nav>
  • aria-describedby用于为元素提供额外的描述信息,通常与表单验证错误消息一起使用。

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"aria-invalid="true"aria-describedby="email-error">
<span id="email-error"class="error">请输入有效的邮箱地址</span>

多媒体内容

确保多媒体内容对所有用户都是可访问的,包括视力障碍者、听力障碍者以及其他有特殊需求的用户,是创建包容性网站的重要部分。

图片可访问性
  • 替代文本: 为图像提供替代文本(alt属性),以便屏幕阅读器能够描述图像的内容。需要注意:

    • 提供有意义的alt属性,避免使用空字符串(除非图像是纯粹装饰性的)。

    • 对于装饰性图像,可以使用alt=""来告诉屏幕阅读器忽略该图像。

<img src="logo.png"alt="公司Logo">
  • 长描述: 对于复杂的图像或图表,简单的alt属性可能不足以描述其全部内容,此时可以使用 <figcaption> 标签结合 <figure> 标签为图像添加说明。

<figure>
<img src="complex_graph.png"alt="一张复杂的销售数据折线图">
<figcaption>该折线图展示了过去一年中不同季度的产品销售数据变化趋势。</figcaption>
</figure>
视频可访问性
  • 字幕: 为视频添加字幕,帮助听力障碍者理解视频内容,也有助于在嘈杂环境或用户选择静音时理解视频内容。可以在 <video> 标签中使用 <track> 标签添加字幕文件,kind 属性设置为 captions

<video controls>
<source src="example.mp4"type="video/mp4">
<track kind="captions"src="captions.vtt"srclang="zh"label="中文字幕">
</video>
  • 音频描述: 音频描述是对视频中视觉内容的口头描述,帮助视力障碍者理解视频中的重要视觉元素。同样使用 <track> 标签来实现,kind 属性设置为 descriptions

<video controls>
<source src="video.mp4"type="video/mp4">
<track kind="descriptions"src="descriptions.vtt"srclang="zh"label="视频描述">
</video>
  • 控制和交互: 提供易于使用的视频控制功能,让所有用户都能方便地播放、暂停、调整音量、快进等。可以在 <video> 标签中添加 controls 属性,显示默认的视频控制条。也可以通过 JavaScript 自定义控制界面,但要确保其可通过键盘操作。

<video id="myVideo"controls>
<source src="example.mp4"type="video/mp4">
</video>

<script>
const video =document.getElementById('myVideo');

// 添加键盘事件监听器
document.addEventListener('keydown',(e)=>{
if(e.key =' '){// 空格键播放/暂停
      e.preventDefault();
if(video.paused){
        video.play();
}else{
        video.pause();
}
}elseif(e.key ='ArrowLeft'){// 左箭头后退5秒
      video.currentTime -=5;
}elseif(e.key ==='ArrowRight'){// 右箭头前进5秒
      video.currentTime +=5;
}
});
</script>
音频可访问性
  • 音频转录: 为听障用户或在无法播放音频的情况下提供音频内容的文字版本。

<audio controls>
<source src="audio.mp3"type="audio/mpeg">
</audio>
<p>点击 <a href="audio_transcription.txt">这里</a> 查看音频转录文本。</p>
  • 音频控制: 确保音频播放器的控制按钮可以通过键盘操作,并且对屏幕阅读器友好。

<audio id="myAudio"controls>
<source src="example.mp3"type="audio/mpeg">
</audio>

<script>
const audio =document.getElementById('myAudio');

// 添加键盘事件监听器
document.addEventListener('keydown',(e)=>{
if(e.key =' '){// 空格键播放/暂停
      e.preventDefault();
if(audio.paused){
        audio.play();
}else{
        audio.pause();
}
}elseif(e.key ='ArrowLeft'){// 左箭头后退5秒
      audio.currentTime -=5;
}elseif(e.key ==='ArrowRight'){// 右箭头前进5秒
      audio.currentTime +=5;
}
});
</script>
整体策略
  • 自动播放限制: 避免自动播放多媒体内容,特别是带有声音的视频或音频,以免干扰用户的体验。可以使用preload="none"preload="metadata"来延迟加载视频,直到用户明确请求播放。

<video controlspreload="none">
<source src="example.mp4"type="video/mp4">
</video>
  • 焦点管理: 确保当多媒体内容加载或动态更新时,焦点正确管理,不会导致用户失去当前的操作上下文。

表单设计

设计一个易于理解和使用的表单是提升用户体验和可访问性的关键。

结构与布局
  • 清晰的层次结构: 确保表单有一个清晰的层次结构,使用户能够轻松理解每个部分的目的和内容。可以使用<fieldset><legend>来分组相关的表单元素,并且确保每个表单部分都有明确的标题或说明。

<form id="registrationForm">
<fieldset>
<legend>注册信息</legend>
<label for="username">用户名:</label>
<input type="text"id="username"name="username"required>

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"required>

<label for="password">密码:</label>
<input type="password"id="password"name="password"required>
</fieldset>

<fieldset>
<legend>联系方式</legend>
<label for="phone">电话号码:</label>
<input type="tel"id="phone"name="phone">

<label for="address">地址:</label>
<textarea id="address"name="address"></textarea>
</fieldset>

<button type="submit">提交</button>
</form>
  • 逻辑顺序: 按照用户的自然填写顺序排列表单字段,避免跳跃式布局。

<label for="firstName">名字:</label>
<input type="text"id="firstName"name="firstName"required>

<label for="lastName">姓氏:</label>
<input type="text"id="lastName"name="lastName"required>

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"required>
标签
  • 使用<label>标签: 为每个表单控件提供明确的标签,以便屏幕阅读器能够正确读取,可以使用for属性将标签与相应的输入字段关联起来。

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"required>
  • 隐藏标签: 对于某些装饰性或视觉上不必要的标签,可以使用CSS将其隐藏,但仍然对屏幕阅读器可见。

<label for="search"class="sr-only">搜索:</label>
<input type="search"id="search"name="search"placeholder="搜索...">
.sr-only{
position: absolute;
width:1px;
height:1px;
padding:0;
margin:-1px;
overflow: hidden;
clip:rect(0,0,0,0);
border:0;
}
输入字段
  • 类型提示: 使用HTML5的输入类型提示(如emailteldate等),帮助浏览器提供更好的输入体验(如自动完成、键盘布局等)。

<input type="email"id="email"name="email"required>
<input type="tel"id="phone"name="phone">
<input type="date"id="birthday"name="birthday">
  • 占位符: 占位符文本可以帮助用户了解应该输入的内容,但不应替代标签。

<input type="email"id="email"name="email"placeholder="example@example.com"required>
表单验证
  • 客户端验证: 在用户提交表单之前进行客户端验证,以防止无效数据提交,可以使用 HTML5 内置的验证属性(如requiredpattern等)。

<form id="registrationForm">
<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"requiredaria-invalid="false"aria-describedby="email-error">
<span id="email-error"class="error"></span>

<button type="submit">提交</button>
</form>

<script>
const form =document.getElementById('registrationForm');
const emailInput =document.getElementById('email');
const emailError =document.getElementById('email-error');

  form.addEventListener('submit',(e)=>{
if(!emailInput.validity.valid){
      e.preventDefault();
      emailInput.setAttribute('aria-invalid','true');
      emailError.textContent ='请输入有效的邮箱地址';
      emailInput.focus();
}
});
</script>
  • 服务器端验证: 即使有客户端验证,仍需在服务器端进行验证,以确保数据的安全性和完整性。

即时反馈
  • 实时验证: 在用户输入过程中提供即时反馈,帮助他们在提交表单前纠正错误,可以使用aria-invalid属性指示输入的有效性状态。

<form id="registrationForm">
<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"requiredaria-invalid="false"aria-describedby="email-error">
<span id="email-error"class="error"></span>

<button type="submit">提交</button>
</form>

<script>
const emailInput =document.getElementById('email');
const emailError =document.getElementById('email-error');

  emailInput.addEventListener('input',()=>{
if(!emailInput.validity.valid){
      emailInput.setAttribute('aria-invalid','true');
      emailError.textContent ='请输入有效的邮箱地址';
}else{
      emailInput.setAttribute('aria-invalid','false');
      emailError.textContent ='';
}
});
</script>
  • 成功反馈: 在用户成功提交表单后,提供明确的成功确认信息。

辅助功能
  • ARIA属性: 使用ARIA属性增强表单的可访问性,特别是在复杂交互中。

    • 使用aria-required指示必填字段。

    • 使用aria-describedby提供额外描述信息(如错误消息)。

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"requiredaria-required="true"aria-describedby="email-error">
<span id="email-error"class="error"></span>
  • 键盘导航: 确保表单可以通过键盘操作,并且焦点管理合理。

<form id="registrationForm">
<label for="username">用户名:</label>
<input type="text"id="username"name="username"required>

<label for="email">邮箱地址:</label>
<input type="email"id="email"name="email"required>

<button type="submit">提交</button>
</form>

<script>
document.addEventListener('keydown',(e)=>{
if(e.key ==='Enter'){
const focusedElement =document.activeElement;
if(focusedElement.tagName.toLowerCase()==='button'){
        focusedElement.click();
}
}
});
</script>

模态框

模态框是一种常见的UI组件,用于显示临时信息或要求用户进行特定操作。

HTML结构

模态框的基本结构应包含一个对话框容器和关闭按钮,并且使用适当的ARIA属性来定义其角色和状态。

  • 使用role="dialog"来标识模态框。

  • 使用aria-modal="true"来告知屏幕阅读器这是一个模态对话框,阻止背景内容的交互。

  • 提供明确的标题(aria-labelledby)和描述(aria-describedby),帮助用户理解对话框的内容。

<div id="myModal"role="dialog"aria-modal="true"aria-labelledby="modalTitle"aria-describedby="modalDescription"style="display: none;">
<h2 id="modalTitle">模态标题</h2>
<p id="modalDescription">这是模态内容。</p>
<button id="closeModal">关闭</button>
</div>
焦点管理
  • 初始焦点: 当模态框打开时,应将焦点移动到模态框内的第一个可聚焦元素上。如果模态框有多个可聚焦元素,选择最相关的元素作为初始焦点。

functionopenModal(){
const modal =document.getElementById('myModal');
  modal.style.display ='block';

// 将焦点移到关闭按钮上
document.getElementById('closeModal').focus();
}
  • 模态框内焦点循环:在模态框打开时,焦点应限制在模态框内部,防止用户通过 Tab 键将焦点移出模态框,与页面其他部分交互。可以通过第三方库如 react-focus-lock来实现,也可以通过监听keydown事件,处理Tab键导航,确保焦点始终停留在模态框内。

functiontrapFocus(event){
const modal =document.getElementById('myModal');
const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length -1];

if(event.shiftKey &&document.activeElement = firstFocusableElement){
// Shift + Tab 从第一个元素移出
    lastFocusableElement.focus();
    event.preventDefault();
}elseif(!event.shiftKey &&document.activeElement = lastFocusableElement){
// Tab 从最后一个元素移出
    firstFocusableElement.focus();
    event.preventDefault();
}
}

document.addEventListener('keydown', trapFocus);
  • 关闭模态框时恢复焦点:当模态框关闭时,应将焦点恢复到打开模态框的触发元素上,以便用户可以继续之前的操作。

const closeModalButton =document.getElementById('close-modal');
closeModalButton.addEventListener('click',()=>{
    modal.hidden =true;
    openModalButton.focus();
});
样式与视觉提示
  • 视觉焦点指示: 为可聚焦元素提供清晰的视觉焦点指示,帮助视力障碍者识别当前聚焦的位置。

button:focus, input:focus, select:focus, textarea:focus{
outline:2px solid #007bff;
outline-offset:2px;
}
  • 背景遮罩: 使用背景遮罩来模糊或隐藏背景内容,使模态框更加突出,背景遮罩应覆盖整个视口,并具有一定的透明度。

<div id="overlay"style="display: none;"></div>
<div id="myModal"role="dialog"aria-modal="true"aria-labelledby="modalTitle"aria-describedby="modalDescription"style="display: none;">
<!-- 模态框内容 -->
</div>

<style>
#overlay{
position: fixed;
top:0;
left:0;
width:100%;
height:100%;
background-color:rgba(0,0,0,0.5);
z-index:9998;
}

#myModal{
position: fixed;
top:50%;
left:50%;
transform:translate(-50%,-50%);
background-color: white;
padding:20px;
z-index:9999;
}
</style>

<script>
functionopenModal(){
const overlay =document.getElementById('overlay');
const modal =document.getElementById('myModal');

    overlay.style.display ='block';
    modal.style.display ='block';

// 将焦点移到关闭按钮上
document.getElementById('closeModal').focus();
}

functioncloseModal(){
const overlay =document.getElementById('overlay');
const modal =document.getElementById('myModal');

    overlay.style.display ='none';
    modal.style.display ='none';

// 恢复之前的焦点
if(previousActiveElement){
      previousActiveElement.focus();
}
}
</script>

小结:可访问性不是功能,而是责任。通过实现这些技术细节,我们不仅满足 WCAG 标准,更是为所有用户构建真正的包容性网络。从下一个功能需求开始,将可访问性刻进你的开发 DNA。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值