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

WCAG可访问性:展开文本下方的显示更多/更少按钮是否需移动焦点?

按钮位于展开文本下方时的焦点处理方案

针对你的场景,将焦点移动到刚展开的文本区域是更合理的选择,而非仅依赖aria-live。以下是具体分析和实现建议:

为什么常规“不移动焦点”的做法不适用

常规手风琴组件中,按钮位于展开内容上方,焦点留在按钮上时,用户向下导航(无论是用键盘箭头还是滚动)自然就能看到展开的内容。但你的场景恰好相反:展开文本在按钮上方,若焦点停留在按钮,用户继续向下浏览会直接跳过刚展开的内容,必须回退才能查看,这对键盘用户、屏幕阅读器用户甚至普通视觉用户都不友好。

移动焦点的正确实现要点

  1. 等待过渡完成再移动焦点
    你的代码中已经考虑到这点,确保动画结束后再操作焦点,避免视觉与焦点状态不一致。

  2. 合理设置文本容器的属性

    • 保留tabIndex="-1":允许通过JS移动焦点,但不会让该元素进入正常的Tab导航流,避免干扰用户的常规操作。
    • 移除文本容器的aria-label:文本本身有具体内容,屏幕阅读器会直接读取文本内容,额外的标签会造成冗余。
    • 保留aria-live="polite":作为辅助提示,告知屏幕阅读器内容已更新,但焦点移动是更直接的引导方式。
    • 确保aria-hidden与展开状态同步:折叠时设为true,避免屏幕阅读器读取隐藏内容;展开时设为false,保证内容可访问。
  3. 折叠时的焦点回退
    当用户点击“Show less”折叠文本时,记得将焦点移回按钮,让用户可以继续执行其他操作或导航。

优化后的示例代码调整

import { useRef, useState } from 'react';
import { Card, CardMedia, Typography, Button } from '@mui/material';

// 假设组件接收的props
interface Props {
  heading: string;
  firstPieceOfText: string;
  secondPieceOfText: string;
}

export const ExpandableCard = ({ heading, firstPieceOfText, secondPieceOfText }: Props) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const lastPRef = useRef<HTMLElement>(null);

  const handleExpansion = () => {
    const newExpandedState = !isExpanded;
    setIsExpanded(newExpandedState);
    
    // 等待过渡完成后处理焦点(假设过渡时长300ms)
    setTimeout(() => {
      if (newExpandedState) {
        // 展开时,焦点移到展开文本
        lastPRef.current?.focus();
      } else {
        // 折叠时,焦点移回按钮
        buttonRef.current?.focus();
      }
    }, 300);
  };

  return (
    <Card>
      <CardMedia />
      <Typography>{heading}</Typography>
      <Typography>{firstPieceOfText}</Typography>
      <Typography
        id="collapsed-text"
        style={{ visibility: isExpanded ? "visible" : "hidden" }}
        aria-hidden={!isExpanded}
        aria-live="polite"
        ref={lastPRef}
        tabIndex={-1}
      >
        {secondPieceOfText}
      </Typography>
      <Button
        ref={buttonRef}
        onClick={handleExpansion}
        aria-expanded={isExpanded}
        aria-controls="collapsed-text"
      >
        {isExpanded ? "Show less" : "Show more"}
      </Button>
    </Card>
  );
};

仅用aria-live的局限性

aria-live="polite"只能让屏幕阅读器读取新增内容,但对于依赖键盘箭头键浏览的用户来说,他们的焦点仍在按钮上,继续向下移动会完全错过上方的展开文本;视觉用户也可能因为没有明确的位置引导,忽略掉按钮上方的内容变化。因此仅靠aria-live无法解决核心的导航问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 02:50:12