跳到主要内容

无障碍✅

页面语义化与地标如何设计?

答案

核心要点

  • 语义元素:header/nav/main/aside/footer 让辅助技术快速定位结构
  • 跳转链接:提供“跳到主要内容”的 skip-link
  • landmark 命名:为导航/页脚等添加 aria-label 提升可辨识度
<!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>
    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial; line-height: 1.6; }
    .skip-link { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
    .skip-link:focus { position: static; width: auto; height: auto; }
    header, nav, main, aside, footer { padding: 8px 12px; margin: 8px 0; border: 1px dashed #bbb; }
    nav a { margin-right: 8px; }
  </style>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
  </head>
<body>
  <a href="#main" class="skip-link">跳到主要内容</a>

  <header aria-label="站点头部">
    <h1>示例站点</h1>
  </header>

  <nav aria-label="主导航">
    <a href="#">首页</a>
    <a href="#">产品</a>
    <a href="#">关于</a>
  </nav>

  <main id="main">
    <article>
      <h2>文章标题</h2>
      <p>使用 header/nav/main/footer 等语义元素有助于辅助技术快速定位页面结构。</p>
    </article>
  </main>

  <aside aria-label="侧边栏">
    <p>侧栏信息</p>
  </aside>

  <footer aria-label="页脚">
    <p>© 2025 示例</p>
  </footer>
</body>
</html>

面试官视角

  • 关注能否正确使用语义元素、跳转链接与地标命名

延伸阅读

按钮组件的可访问性该如何实现?

答案

核心要点

  • 使用 button 而非 div,天然可聚焦与键盘可触达
  • 状态宣告:结合 role="status"aria-live 提示结果
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>可访问按钮</title>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
</head>
<body>
  <h1>按钮可访问性</h1>
  <p>使用 button 元素而不是 div+click;确保可聚焦、键盘可触达、状态可感知。</p>

  <button type="button" id="btn">提交</button>
  <p id="status" role="status" aria-live="polite"></p>

  <script>
    const btn = document.getElementById('btn')
    const status = document.getElementById('status')
    btn.addEventListener('click', () => {
      status.textContent = '已提交'
      console.log('按钮被点击,并通过 role="status" 宣告')
    })
  </script>
</body>
</html>

面试官视角

  • 关注是否避免 div+click 且支持键盘和读屏状态宣告

延伸阅读

表单如何实现标签关联与错误宣告?

答案

核心要点

  • label for 绑定输入,aria-describedby 绑定错误提示
  • 错误消息使用 role="alert" 或 live region 动态宣告
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>可访问表单</title>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
</head>
<body>
  <h1>表单可访问性</h1>
  <form aria-describedby="form-desc">
    <p id="form-desc">所有输入都有 <code>label</code> 关联,错误通过 <code>aria-describedby</code> 宣告。</p>

    <label for="email">邮箱</label>
    <input id="email" name="email" type="email" required aria-describedby="email-err" />
    <small id="email-err" role="alert" aria-live="polite"></small>

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

    <button>提交</button>
  </form>

  <script>
    const form = document.querySelector('form')
    const email = document.getElementById('email')
    const emailErr = document.getElementById('email-err')
    form.addEventListener('submit', (e) => {
      e.preventDefault()
      if (!email.value.includes('@')) {
        emailErr.textContent = '请输入有效邮箱地址'
        email.focus()
        return
      }
      emailErr.textContent = ''
      console.log('表单通过基础校验')
    })
  </script>
</body>
</html>

面试官视角

  • 关注“标签-输入”可达性、错误宣告及时与聚焦管理

延伸阅读

模态对话框如何保证键盘可达和焦点管理?

答案

核心要点

  • 语义:role="dialog" + aria-modal="true" + aria-labelledby/aria-describedby
  • 焦点:开启时将焦点移入,关闭时还原;Esc 关闭
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>可访问对话框</title>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
  <style>
    .backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.5); display: none; }
    .dialog { background: #fff; margin: 10% auto; max-width: 480px; padding: 16px; outline: none; }
    .backdrop[aria-hidden="false"] { display: block; }
  </style>
</head>
<body>
  <h1>模态对话框可访问性</h1>
  <button id="open">打开对话框</button>

  <div class="backdrop" id="backdrop" aria-hidden="true">
    <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="title" aria-describedby="desc" tabindex="-1">
      <h2 id="title">删除确认</h2>
      <p id="desc">此操作不可撤销,确认继续吗?</p>
      <button id="confirm">确认</button>
      <button id="close">取消</button>
    </div>
  </div>

  <script>
    const openBtn = document.getElementById('open')
    const backdrop = document.getElementById('backdrop')
    const dialog = backdrop.querySelector('.dialog')
    const closeBtn = document.getElementById('close')
    const confirmBtn = document.getElementById('confirm')

    function open () {
      backdrop.setAttribute('aria-hidden', 'false')
      dialog.focus()
      document.addEventListener('keydown', onKeydown)
      console.log('Dialog opened')
    }
    function close () {
      backdrop.setAttribute('aria-hidden', 'true')
      openBtn.focus()
      document.removeEventListener('keydown', onKeydown)
      console.log('Dialog closed')
    }
    function onKeydown (e) {
      if (e.key === 'Escape') close()
    }
    openBtn.addEventListener('click', open)
    closeBtn.addEventListener('click', close)
    confirmBtn.addEventListener('click', close)
  </script>
</body>
</html>

面试官视角

  • 关注焦点圈定、关闭快捷键、可返回原触发点

延伸阅读

动态内容如何被读屏及时宣告?

答案

核心要点

  • 使用 aria-live 区域(polite/assertive)宣告异步状态
  • 适用于通知、加载、完成等动态反馈
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Live Region</title>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
</head>
<body>
  <h1>动态内容宣告(ARIA Live)</h1>
  <button id="add">开始任务</button>
  <div role="status" aria-live="polite" id="status"></div>

  <script>
    const status = document.getElementById('status')
    document.getElementById('add').addEventListener('click', () => {
      status.textContent = '任务已开始…'
      setTimeout(() => {
        status.textContent = '任务完成'
        console.log('通过 role="status" 宣告任务完成')
      }, 1200)
    })
  </script>
</body>
</html>

面试官视角

  • 关注宣告时机与语气等级选择是否得当

延伸阅读

图像的替代文本应如何编写?

答案

核心要点

  • 装饰性图片使用空 alt;信息性图片使用简洁的描述
  • 图表可结合 figure/figcaption 补充上下文
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>图像可访问性</title>
  <link rel="stylesheet" href="https://unpkg.com/mvp.css" />
</head>
<body>
  <h1>图像文本替代</h1>
  <p>装饰性图片用空 <code>alt</code>;信息性图片用简洁 <code>alt</code> 描述。</p>

  <img src="https://dummyimage.com/120x60/ddd/000&text=Logo" alt="示例站点 LOGO" />
  <img src="https://dummyimage.com/80x80/eee/aaa" alt="" />

  <figure>
    <img src="https://dummyimage.com/320x180/ccc/000&text=Sales+2025" alt="2025 年销售趋势折线图" />
    <figcaption>图 1:销售趋势</figcaption>
  </figure>
</body>
</html>

面试官视角

  • 关注是否能区分装饰性与信息性图片,并给出合适 alt 描述

延伸阅读