生成的伪元素内容:`::before` / `::after` 中的 `alt` 属性与屏幕阅读器朗读

生成的伪元素内容:::before / ::after 中的 alt 属性与屏幕阅读器朗读

大家好,今天我们要深入探讨一个前端开发中比较容易被忽视,但对于网页可访问性至关重要的主题:生成的伪元素 (::before::after) 内容中的 alt 属性,以及它对屏幕阅读器朗读的影响。

1. 伪元素与内容生成

在CSS中,伪元素允许我们在不修改HTML结构的前提下,向元素添加额外的样式或内容。::before 在元素内容之前插入,::after 在元素内容之后插入。 它们通常与 content 属性一起使用,用于插入文本、图像或其他媒体。

例如:

.my-element::before {
  content: "前缀:";
  color: blue;
}

.my-element::after {
  content: url("icon.png"); /* 这里仅仅是一个示例,实际情况需要结合可访问性考虑 */
  display: inline-block;  /* 使图像可以设置尺寸和对齐 */
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

.my-element {
  border: 1px solid black;
  padding: 5px;
}
<div class="my-element">这是我的元素</div>

这段代码会在 my-element 元素之前插入蓝色的 "前缀:" 文本,并在之后插入一个名为 "icon.png" 的图像。

2. 屏幕阅读器与可访问性

屏幕阅读器是为视力障碍人士设计的辅助技术,它们将屏幕上的文本转换为语音或盲文输出。 确保网页内容对屏幕阅读器友好,是实现网页可访问性的关键组成部分。

WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) 提供了一套属性,可以增强网页内容的可访问性,允许开发者向辅助技术提供关于元素角色、状态和属性的额外信息。

3. alt 属性的含义与重要性

alt 属性 (alternative text) 用于 <img> 标签,提供图像的文本描述。 当图像无法加载或用户使用屏幕阅读器时,alt 属性的内容会被显示或朗读。 一个良好的 alt 属性应该简洁、准确地描述图像的内容和功能。

4. ::before / ::afteralt 属性:挑战与解决方案

关键问题在于: alt 属性不能直接应用于 ::before::after 生成的内容。 因为伪元素本身不是HTML元素,它们只是CSS渲染的结果。 这意味着,如果我们在 ::before::after 中使用 content: url("image.png"); 插入图像,屏幕阅读器默认情况下不会朗读任何关于该图像的信息。

这会造成严重的可访问性问题,特别是当图像包含重要的信息或功能时。

解决方案:

以下是一些解决此问题的策略:

4.1. 使用 aria-labelaria-labelledby 属性

aria-label 为元素定义一个字符串标签,供辅助技术使用。 aria-labelledby 通过引用页面上已存在的元素的 id 属性,来为元素定义标签。

  • aria-label 示例:

    .icon-link::before {
      content: url("icon.png");
      display: inline-block;
      width: 20px;
      height: 20px;
      vertical-align: middle;
    }
    
    .icon-link {
      /* 其他样式 */
      aria-label: "链接到我们的联系页面"; /* 添加 aria-label */
    }
    <a href="/contact" class="icon-link">联系我们</a>

    在这个例子中,屏幕阅读器会朗读 "链接到我们的联系页面",即使图像是通过 ::before 插入的。 请注意,aria-label 属性添加到包含伪元素的 宿主元素 上。

  • aria-labelledby 示例:

    <p id="contact-label">链接到我们的联系页面</p>
    <a href="/contact" class="icon-link" aria-labelledby="contact-label">联系我们</a>
    .icon-link::before {
      content: url("icon.png");
      display: inline-block;
      width: 20px;
      height: 20px;
      vertical-align: middle;
    }
    
    .icon-link {
      /* 其他样式 */
    }

    在这里,屏幕阅读器会朗读 idcontact-label 的段落的内容,也就是 "链接到我们的联系页面"。 同样,aria-labelledby 属性添加到 宿主元素 上,并指向包含描述文本的元素的 id

    选择 aria-label 还是 aria-labelledby

    • 如果描述文本已经存在于页面上,并且适合作为标签,则使用 aria-labelledby
    • 如果描述文本不需要显示在页面上,或者需要更简洁的描述,则使用 aria-label

4.2. 使用 aria-hidden="true" 隐藏装饰性图像

如果伪元素插入的图像仅仅是装饰性的,不包含任何重要的信息,那么应该使用 aria-hidden="true" 将其从屏幕阅读器中隐藏。

.decorative-element::before {
  content: url("decorative-image.png");
  display: inline-block;
  width: 50px;
  height: 50px;
  aria-hidden: true; /* 错误用法:aria-hidden 不应该直接应用于伪元素 */
}

.decorative-element{
  aria-hidden: true; /* 正确用法,应用于宿主元素 */
}
<div class="decorative-element">这是一个装饰性的元素</div>

同样,aria-hidden="true" 应该应用到宿主元素上,而不是伪元素本身。

4.3. 使用 SVG 内联图像并添加 <title><desc> 标签

如果使用 SVG 图像,可以将 SVG 代码直接嵌入到HTML中,并使用 <title><desc> 标签提供图像的描述。 屏幕阅读器会读取这些标签的内容。

<svg width="100" height="100" aria-hidden="false">  <!--Important to set aria-hidden to false if it has been set on parent.-->
  <title>公司logo</title>
  <desc>这是我们公司的logo,一个蓝色的圆形包含字母 C。</desc>
  <circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="white" />
  <text x="50" y="50" font-size="30" text-anchor="middle" dominant-baseline="middle">C</text>
</svg>

然后,可以像这样在伪元素中使用 SVG:

.logo::before {
  content: url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E%3Ctitle%3E公司logo%3C/title%3E%3Cdesc%3E这是我们公司的logo,一个蓝色的圆形包含字母 C。%3C/desc%3E%3Ccircle cx='50' cy='50' r='40' stroke='blue' stroke-width='4' fill='white'/%3E%3Ctext x='50' y='50' font-size='30' text-anchor='middle' dominant-baseline='middle'%3EC%3C/text%3E%3C/svg%3E");
  display: inline-block;
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

虽然这种方法可行,但将完整的 SVG 代码嵌入到 CSS 中会导致代码变得臃肿且难以维护。 更推荐的做法是将 SVG 存储为单独的文件,然后使用 aria-labelaria-labelledby 来提供描述。

4.4. 避免使用 content: "" 插入重要的信息

最简单也是最有效的方法是: 避免使用 content 属性来插入任何重要的信息。 如果信息至关重要,应该将其直接添加到 HTML 结构中,并使用语义化的 HTML 标签。

例如,与其使用:

.required-field::after {
  content: "*";
  color: red;
}

来指示必填字段,不如直接在 HTML 中添加 <span> 标签:

<label for="name">姓名:<span class="required">*</span></label>
<input type="text" id="name" name="name">
.required {
  color: red;
}

这样,屏幕阅读器会正确地朗读 "*",并且代码也更易于理解和维护。

5. 代码示例与最佳实践

下面是一个更完整的代码示例,演示了如何结合使用 aria-labelaria-hidden 来提高伪元素的可访问性:

<!DOCTYPE html>
<html>
<head>
  <title>伪元素与可访问性</title>
  <style>
    .notification::before {
      content: url("notification-icon.png");
      display: inline-block;
      width: 20px;
      height: 20px;
      vertical-align: middle;
    }

    .notification {
      padding: 10px;
      border: 1px solid #ccc;
      margin-bottom: 10px;
    }

    .decorative-line::after {
      content: ""; /* 使用空字符串,并用 border 实现线条 */
      display: block;
      width: 100%;
      height: 2px;
      background-color: #eee;
    }

    .decorative-line {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>

  <div class="notification" aria-label="您有 3 条未读消息">
    您有 3 条未读消息
  </div>

  <div class="decorative-line" aria-hidden="true"></div>

  <p>这是一个段落,演示了装饰性的线条。</p>

</body>
</html>

在这个例子中, notification 元素使用 aria-label 提供关于通知的描述,而 decorative-line 元素使用 aria-hidden="true" 将其从屏幕阅读器中隐藏。

6. 测试与验证

在开发过程中,应该使用屏幕阅读器(例如 NVDA, JAWS, VoiceOver)测试网页的可访问性。 可以使用浏览器的开发者工具检查元素的辅助功能属性。

可以使用以下检查列表来验证伪元素的可访问性:

检查项 描述 解决方案
伪元素是否包含重要的信息? 如果是,需要确保屏幕阅读器能够正确地朗读这些信息。 使用 aria-labelaria-labelledby 提供描述。 避免使用 content 属性插入重要的信息。
伪元素是否仅仅是装饰性的? 如果是,应该将其从屏幕阅读器中隐藏。 使用 aria-hidden="true" 将宿主元素隐藏。
是否使用了 SVG 图像? 如果是,可以使用 <title><desc> 标签提供图像的描述。 确保 <title><desc> 标签的内容简洁、准确。 考虑使用 aria-labelaria-labelledby 来提供更灵活的描述。
代码是否简洁、易于维护? 避免过度使用伪元素来插入复杂的内容。 尽可能使用语义化的 HTML 结构。 将 CSS 代码组织良好,易于理解和修改。
使用屏幕阅读器测试了吗? 始终使用屏幕阅读器测试网页的可访问性。 下载并安装免费的屏幕阅读器(例如 NVDA)。 学习如何使用屏幕阅读器浏览网页。 注意屏幕阅读器如何朗读伪元素的内容。

7. 总结与重要建议

总而言之,在 ::before::after 中使用 alt 属性是不可能的。要保证伪元素内容的可访问性,我们需要谨慎地使用 ARIA 属性,避免使用 content 属性插入重要的信息,并始终使用屏幕阅读器进行测试。希望通过这次的分享,大家能更加重视网页的可访问性,为所有用户创造更好的体验。务必牢记,屏幕阅读器无法识别伪元素中的 alt 属性,需要使用替代方案。

更多IT精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注