Skip to content

12.1 可访问性基础

学习目标

  • 理解Web可访问性的基本概念和重要性
  • 掌握WCAG 2.1指南的核心原则
  • 学会使用语义化HTML实现基础可访问性
  • 了解常见的可访问性问题和解决方案

1. 可访问性概述

1.1 什么是Web可访问性

Web可访问性是指设计和开发网站时,确保残疾人士能够感知、理解、导航和与网站交互的能力。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>可访问性基础演示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        .accessibility-demo {
            background: white;
            border-radius: 8px;
            padding: 30px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }
        
        h1 {
            color: #2c3e50;
            margin-bottom: 20px;
            font-size: 2em;
        }
        
        h2 {
            color: #34495e;
            margin: 30px 0 15px 0;
            font-size: 1.5em;
        }
        
        .guidelines-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin: 30px 0;
        }
        
        .guideline-card {
            background: #ecf0f1;
            border-radius: 8px;
            padding: 20px;
            border-left: 4px solid #3498db;
            transition: transform 0.3s ease;
        }
        
        .guideline-card:hover {
            transform: translateY(-5px);
        }
        
        .guideline-title {
            font-size: 1.2em;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .guideline-description {
            color: #7f8c8d;
            font-size: 0.9em;
        }
        
        .principles-section {
            margin: 30px 0;
        }
        
        .principle-item {
            background: #fff;
            border: 1px solid #ddd;
            border-radius: 6px;
            padding: 20px;
            margin-bottom: 15px;
            transition: all 0.3s ease;
        }
        
        .principle-item:hover {
            background: #f8f9fa;
            border-color: #3498db;
        }
        
        .principle-title {
            font-size: 1.1em;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .good-example {
            background: #d4edda;
            border: 1px solid #c3e6cb;
            border-radius: 6px;
            padding: 15px;
            margin: 15px 0;
        }
        
        .bad-example {
            background: #f8d7da;
            border: 1px solid #f5c6cb;
            border-radius: 6px;
            padding: 15px;
            margin: 15px 0;
        }
        
        .example-title {
            font-weight: bold;
            margin-bottom: 10px;
        }
        
        .good-example .example-title {
            color: #155724;
        }
        
        .bad-example .example-title {
            color: #721c24;
        }
        
        .code-block {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 4px;
            padding: 15px;
            margin: 15px 0;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            overflow-x: auto;
        }
        
        .interactive-demo {
            background: #e8f4f8;
            border: 1px solid #b8e6f0;
            border-radius: 8px;
            padding: 20px;
            margin: 30px 0;
        }
        
        .demo-controls {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }
        
        .demo-button {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            background: #3498db;
            color: white;
            cursor: pointer;
            transition: background 0.3s ease;
        }
        
        .demo-button:hover {
            background: #2980b9;
        }
        
        .demo-button:focus {
            outline: 2px solid #f39c12;
            outline-offset: 2px;
        }
        
        .demo-result {
            background: white;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 15px;
            min-height: 100px;
        }
        
        .accessibility-checker {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
        }
        
        .checker-title {
            font-weight: bold;
            color: #856404;
            margin-bottom: 15px;
        }
        
        .checker-item {
            padding: 10px;
            margin: 5px 0;
            border-radius: 4px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .checker-pass {
            background: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }
        
        .checker-fail {
            background: #f8d7da;
            border: 1px solid #f5c6cb;
            color: #721c24;
        }
        
        .status-icon {
            font-size: 1.2em;
            font-weight: bold;
        }
        
        .faq-section {
            background: #f8f9fa;
            border-radius: 8px;
            padding: 25px;
            margin: 30px 0;
        }
        
        .faq-title {
            color: #2c3e50;
            font-size: 1.3em;
            margin-bottom: 20px;
            border-bottom: 2px solid #3498db;
            padding-bottom: 10px;
        }
        
        .faq-item {
            margin-bottom: 20px;
        }
        
        .faq-question {
            font-weight: bold;
            color: #34495e;
            margin-bottom: 8px;
        }
        
        .faq-answer {
            color: #7f8c8d;
            line-height: 1.6;
        }
        
        @media (max-width: 768px) {
            .guidelines-grid {
                grid-template-columns: 1fr;
            }
            
            .demo-controls {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="accessibility-demo">
            <h1>HTML5可访问性基础知识</h1>
            
            <section class="principles-section">
                <h2>WCAG 2.1 四大原则</h2>
                <div class="principle-item">
                    <div class="principle-title">1. 可感知性 (Perceivable)</div>
                    <p>信息和用户界面组件必须以用户能够感知的方式呈现。</p>
                    <ul>
                        <li>为非文本内容提供文本替代方案</li>
                        <li>为多媒体提供字幕或其他替代方案</li>
                        <li>确保足够的颜色对比度</li>
                    </ul>
                </div>
                
                <div class="principle-item">
                    <div class="principle-title">2. 可操作性 (Operable)</div>
                    <p>用户界面组件和导航必须是可操作的。</p>
                    <ul>
                        <li>所有功能都可以通过键盘访问</li>
                        <li>用户有足够的时间阅读和使用内容</li>
                        <li>内容不会引起癫痫发作</li>
                    </ul>
                </div>
                
                <div class="principle-item">
                    <div class="principle-title">3. 可理解性 (Understandable)</div>
                    <p>信息和用户界面的操作必须是可理解的。</p>
                    <ul>
                        <li>文本是可读和可理解的</li>
                        <li>网页以可预测的方式显示和操作</li>
                        <li>帮助用户避免和纠正错误</li>
                    </ul>
                </div>
                
                <div class="principle-item">
                    <div class="principle-title">4. 健壮性 (Robust)</div>
                    <p>内容必须足够健壮,能够被各种用户代理解释。</p>
                    <ul>
                        <li>与辅助技术兼容</li>
                        <li>使用有效的标记语言</li>
                        <li>确保向后兼容性</li>
                    </ul>
                </div>
            </section>
            
            <section>
                <h2>语义化HTML示例</h2>
                
                <div class="good-example">
                    <div class="example-title">✅ 良好的可访问性实践</div>
                    <div class="code-block">
&lt;article&gt;
    &lt;header&gt;
        &lt;h1&gt;文章标题&lt;/h1&gt;
        &lt;p&gt;发布时间:&lt;time datetime="2024-01-01"&gt;2024年1月1日&lt;/time&gt;&lt;/p&gt;
    &lt;/header&gt;
    &lt;main&gt;
        &lt;p&gt;文章内容...&lt;/p&gt;
        &lt;figure&gt;
            &lt;img src="example.jpg" alt="描述性文本"&gt;
            &lt;figcaption&gt;图片说明&lt;/figcaption&gt;
        &lt;/figure&gt;
    &lt;/main&gt;
&lt;/article&gt;
                    </div>
                </div>
                
                <div class="bad-example">
                    <div class="example-title">❌ 不良的可访问性实践</div>
                    <div class="code-block">
&lt;div&gt;
    &lt;div&gt;
        &lt;span style="font-size: 24px; font-weight: bold;"&gt;标题&lt;/span&gt;
        &lt;span&gt;2024年1月1日&lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;p&gt;内容...&lt;/p&gt;
        &lt;img src="example.jpg"&gt;
    &lt;/div&gt;
&lt;/div&gt;
                    </div>
                </div>
            </section>
            
            <section class="interactive-demo">
                <h2>交互式可访问性演示</h2>
                <div class="demo-controls">
                    <button class="demo-button" onclick="checkAccessibility()">检查可访问性</button>
                    <button class="demo-button" onclick="toggleHighContrast()">切换高对比度</button>
                    <button class="demo-button" onclick="testKeyboardNav()">测试键盘导航</button>
                    <button class="demo-button" onclick="simulateScreenReader()">模拟屏幕阅读器</button>
                </div>
                <div class="demo-result" id="demoResult">
                    <p>点击上方按钮开始测试...</p>
                </div>
            </section>
            
            <section class="accessibility-checker">
                <div class="checker-title">🔍 页面可访问性检查结果</div>
                <div class="checker-item checker-pass">
                    <span class="status-icon">✓</span>
                    <span>页面具有有效的语言属性</span>
                </div>
                <div class="checker-item checker-pass">
                    <span class="status-icon">✓</span>
                    <span>所有图像都有替代文本</span>
                </div>
                <div class="checker-item checker-pass">
                    <span class="status-icon">✓</span>
                    <span>标题层级结构正确</span>
                </div>
                <div class="checker-item checker-fail">
                    <span class="status-icon">✗</span>
                    <span>某些链接缺少描述性文本</span>
                </div>
            </section>
            
            <section class="faq-section">
                <div class="faq-title">常见问题解答</div>
                
                <div class="faq-item">
                    <div class="faq-question">Q: 为什么网站需要考虑可访问性?</div>
                    <div class="faq-answer">A: 可访问性确保所有用户,包括残疾人士,都能使用网站。这不仅是道德责任,在许多国家也是法律要求。</div>
                </div>
                
                <div class="faq-item">
                    <div class="faq-question">Q: WCAG 2.1有哪些等级?</div>
                    <div class="faq-answer">A: WCAG 2.1有三个符合等级:A(最低)、AA(标准)、AAA(最高)。大多数网站应该至少符合AA级别。</div>
                </div>
                
                <div class="faq-item">
                    <div class="faq-question">Q: 如何测试网站的可访问性?</div>
                    <div class="faq-answer">A: 可以使用自动化工具(如WAVE、axe)进行初步检查,但最重要的是进行手动测试,包括使用屏幕阅读器和键盘导航。</div>
                </div>
                
                <div class="faq-item">
                    <div class="faq-question">Q: 什么是替代文本(alt text)?</div>
                    <div class="faq-answer">A: 替代文本是对图像内容的文字描述,当图像无法显示时,或者屏幕阅读器用户访问时,会读取这些文本。</div>
                </div>
                
                <div class="faq-item">
                    <div class="faq-question">Q: 颜色对比度要求是什么?</div>
                    <div class="faq-answer">A: WCAG 2.1 AA级别要求正常文本的对比度至少为4.5:1,大文本至少为3:1。</div>
                </div>
            </section>
        </div>
    </div>
    
    <script>
        // 可访问性检查功能
        function checkAccessibility() {
            const result = document.getElementById('demoResult');
            const checks = [
                { name: '页面标题', pass: !!document.title },
                { name: '语言属性', pass: !!document.documentElement.lang },
                { name: '标题层级', pass: checkHeadingStructure() },
                { name: '图像替代文本', pass: checkImageAlt() },
                { name: '链接描述', pass: checkLinkText() }
            ];
            
            let html = '<h3>可访问性检查结果:</h3>';
            checks.forEach(check => {
                const status = check.pass ? '✅' : '❌';
                const color = check.pass ? 'green' : 'red';
                html += `<div style="color: ${color};">${status} ${check.name}</div>`;
            });
            
            result.innerHTML = html;
        }
        
        // 检查标题层级结构
        function checkHeadingStructure() {
            const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
            if (headings.length === 0) return false;
            
            let currentLevel = 0;
            for (let heading of headings) {
                const level = parseInt(heading.tagName.charAt(1));
                if (currentLevel === 0) {
                    currentLevel = level;
                } else if (level > currentLevel + 1) {
                    return false;
                }
                currentLevel = level;
            }
            return true;
        }
        
        // 检查图像替代文本
        function checkImageAlt() {
            const images = document.querySelectorAll('img');
            return Array.from(images).every(img => img.alt !== undefined);
        }
        
        // 检查链接文本
        function checkLinkText() {
            const links = document.querySelectorAll('a');
            return Array.from(links).every(link => {
                const text = link.textContent.trim();
                return text.length > 0 && !['点击这里', '更多', '链接'].includes(text);
            });
        }
        
        // 切换高对比度模式
        function toggleHighContrast() {
            const body = document.body;
            if (body.style.filter === 'contrast(150%)') {
                body.style.filter = '';
                body.style.background = '';
            } else {
                body.style.filter = 'contrast(150%)';
                body.style.background = '#000';
            }
            
            const result = document.getElementById('demoResult');
            result.innerHTML = '<p>高对比度模式已切换。这有助于视力障碍用户更好地阅读内容。</p>';
        }
        
        // 测试键盘导航
        function testKeyboardNav() {
            const result = document.getElementById('demoResult');
            result.innerHTML = `
                <h3>键盘导航测试</h3>
                <p>请尝试使用以下键盘操作:</p>
                <ul>
                    <li><strong>Tab</strong> - 移动到下一个可聚焦元素</li>
                    <li><strong>Shift + Tab</strong> - 移动到上一个可聚焦元素</li>
                    <li><strong>Enter/空格</strong> - 激活按钮或链接</li>
                    <li><strong>方向键</strong> - 在某些组件中导航</li>
                </ul>
                <p>当前焦点元素将显示清晰的轮廓。</p>
            `;
        }
        
        // 模拟屏幕阅读器
        function simulateScreenReader() {
            const result = document.getElementById('demoResult');
            
            // 获取页面主要内容的文本描述
            const pageStructure = analyzePageStructure();
            
            result.innerHTML = `
                <h3>屏幕阅读器视角</h3>
                <div style="background: #f0f0f0; padding: 15px; border-radius: 4px; font-family: monospace;">
                    ${pageStructure}
                </div>
                <p><small>这是屏幕阅读器可能读取的内容结构。</small></p>
            `;
        }
        
        // 分析页面结构
        function analyzePageStructure() {
            let structure = '';
            
            // 分析标题
            const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
            if (headings.length > 0) {
                structure += '<strong>页面标题结构:</strong><br>';
                headings.forEach(heading => {
                    const level = heading.tagName.charAt(1);
                    const indent = ' '.repeat(level - 1);
                    structure += `${indent}${heading.tagName}: ${heading.textContent}<br>`;
                });
            }
            
            // 分析主要区域
            const landmarks = document.querySelectorAll('main, nav, aside, footer, header');
            if (landmarks.length > 0) {
                structure += '<br><strong>页面区域:</strong><br>';
                landmarks.forEach(landmark => {
                    structure += `${landmark.tagName.toLowerCase()} 区域<br>`;
                });
            }
            
            // 分析交互元素
            const interactive = document.querySelectorAll('button, a, input, select, textarea');
            if (interactive.length > 0) {
                structure += `<br><strong>交互元素:</strong>${interactive.length} 个<br>`;
            }
            
            return structure;
        }
        
        // 页面加载完成后的初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 为所有按钮添加键盘事件监听
            const buttons = document.querySelectorAll('button');
            buttons.forEach(button => {
                button.addEventListener('keydown', function(e) {
                    if (e.key === 'Enter' || e.key === ' ') {
                        e.preventDefault();
                        button.click();
                    }
                });
            });
            
            // 增强焦点可见性
            const focusableElements = document.querySelectorAll('button, a, input, select, textarea');
            focusableElements.forEach(element => {
                element.addEventListener('focus', function() {
                    this.style.outline = '2px solid #f39c12';
                    this.style.outlineOffset = '2px';
                });
                
                element.addEventListener('blur', function() {
                    this.style.outline = '';
                    this.style.outlineOffset = '';
                });
            });
        });
    </script>
</body>
</html>

2. 可访问性的重要性

2.1 用户群体

  • 视觉障碍用户:盲人、低视力用户
  • 听觉障碍用户:聋人、听力障碍用户
  • 运动障碍用户:无法使用鼠标的用户
  • 认知障碍用户:学习困难、记忆障碍用户
  • 临时性障碍用户:手臂受伤、在强光下使用设备等

2.2 法律和商业考量

  • 法律要求:许多国家有相关的可访问性法律
  • 商业利益:扩大用户群体,提高用户满意度
  • SEO优势:语义化HTML有利于搜索引擎优化
  • 品牌价值:展现企业社会责任

3. 基本可访问性原则

3.1 语义化HTML

使用正确的HTML元素来传达内容的含义:

html
<!-- 好的示例 -->
<button>提交</button>
<nav>导航内容</nav>
<main>主要内容</main>

<!-- 避免的示例 -->
<div onclick="submit()">提交</div>
<div>导航内容</div>
<div>主要内容</div>

3.2 替代文本

为所有有意义的图像提供替代文本:

html
<!-- 描述性图像 -->
<img src="chart.png" alt="2024年销售数据显示增长了15%">

<!-- 装饰性图像 -->
<img src="decoration.png" alt="" role="presentation">

3.3 颜色和对比度

  • 不要仅依赖颜色传达信息
  • 确保足够的颜色对比度
  • 提供多种信息传达方式

4. 要点回顾

  1. WCAG 2.1四大原则:可感知、可操作、可理解、健壮
  2. 语义化HTML:使用正确的HTML元素表达内容含义
  3. 替代文本:为图像和媒体内容提供文字描述
  4. 颜色对比度:确保文本与背景有足够的对比度
  5. 键盘导航:确保所有功能都可以通过键盘访问

5. 下一步学习

在下一节中,我们将深入学习ARIA属性,了解如何使用ARIA增强HTML的可访问性。


本节完成! 你已经掌握了HTML5可访问性的基础知识。