You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

轮播组件无障碍优化:屏蔽屏幕阅读器读隐藏内容且保留总项数提示

轮播组件无障碍优化:屏蔽隐藏内容同时保留总项数提示

核心问题拆解

你遇到的矛盾点在于:直接给隐藏项加aria-hidden="true"会让屏幕阅读器把列表计数从总项数改成当前可见项数,而不加的话又会读取隐藏内容。解决方案的关键是用ARIA属性明确声明列表的总项数,同时单独控制隐藏项的可读性。

具体实现方案

  1. 给列表容器声明总项数:通过aria-setsize属性告诉屏幕阅读器整个轮播的总项目数量,不管当前显示多少项,这个值始终是总条数。
  2. 给可见项标记位置:用aria-posinset给每个可见项标注它在总列表中的序号,帮助用户理解当前看到的是哪一部分。
  3. 单独隐藏不可见项:仅对当前不在可视区域的项设置aria-hidden="true",阻止屏幕阅读器读取,但不影响列表的总计数。

React代码示例

import { useState } from 'react';

const Carousel = ({ items }) => {
  const [currentPos, setCurrentPos] = useState(0);
  const totalItems = items.length;
  const visibleCount = 3;

  const handleNext = () => {
    if (currentPos + visibleCount < totalItems) {
      setCurrentPos(prev => prev + 1);
    }
  };

  const handlePrev = () => {
    if (currentPos > 0) {
      setCurrentPos(prev => prev - 1);
    }
  };

  return (
    <div className="carousel-wrapper">
      {/* 上一页按钮:添加明确的ARIA标签 */}
      <button
        onClick={handlePrev}
        disabled={currentPos === 0}
        aria-label="查看上一组项目"
      >
        ←
      </button>

      {/* 列表容器:用aria-setsize声明总项数 */}
      <ul 
        className="carousel-list"
        aria-setsize={totalItems}
        style={{
          display: 'flex',
          overflow: 'hidden',
          width: `${3 * 220}px`, // 按实际项宽调整
          listStyle: 'none',
          padding: 0,
          margin: 0
        }}
      >
        {items.map((item, idx) => {
          const isVisible = idx >= currentPos && idx < currentPos + visibleCount;
          return (
            <li
              key={idx}
              style={{
                width: '220px',
                flexShrink: 0,
                transform: isVisible ? 'none' : 'translateX(-100%)',
                transition: 'transform 0.3s'
              }}
              aria-hidden={!isVisible}
              {/* 仅可见项设置位置序号 */}
              {...isVisible && { 'aria-posinset': idx + 1 }}
            >
              {item.title}
            </li>
          );
        })}
      </ul>

      {/* 下一页按钮:添加明确的ARIA标签 */}
      <button
        onClick={handleNext}
        disabled={currentPos + visibleCount >= totalItems}
        aria-label="查看下一组项目"
      >
        →
      </button>
    </div>
  );
};

export default Carousel;

关键属性说明

  • aria-setsize={totalItems}:强制屏幕阅读器识别列表的总项数,比如总共有6项,即使只显示3个,也会提示“列表,6项”。
  • aria-posinset:给可见项标记它在总列表中的位置,比如当前显示第1-3项,屏幕阅读器会分别提示“第1项,共6项”“第2项,共6项”等。
  • aria-hidden={!isVisible}:仅对隐藏项设置,阻止屏幕阅读器读取这些内容,但不会影响列表的整体计数。

测试验证(Mac VoiceOver)

  1. 打开VoiceOver(快捷键Cmd + F5)。
  2. 聚焦到轮播列表时,VoiceOver会提示“列表,6项”。
  3. 聚焦到单个可见项时,会提示“第X项,共6项”。
  4. 隐藏项不会被VoiceOver读取,切换页码时也只会读取当前可见的项。

额外注意点

  • 不要用display: none隐藏项:这种方式会让屏幕阅读器完全忽略该元素,反而可能影响计数,用transform或position做视觉隐藏配合aria-hidden更合适。
  • 控制按钮要加语义化标签:确保屏幕阅读器用户知道按钮的作用,禁用状态也要保留disabled属性,VoiceOver会提示“禁用的按钮”。

内容的提问来源于stack exchange,提问作者kar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:52:58