仅仅 内联 SVG 似乎是最简单、最灵活的图标系统。但这段 <svg>
代码可能包含 <title>
,并且您可能出于各种原因在这两个元素上都应用了 ID。
其中一个原因可能是您只是希望图标上有一个 ID 以便于 JavaScript 或样式目的进行唯一标识。
另一个原因是为了可访问性,建议您使用 aria-labelledby
连接 id 和 title,例如
<!-- aria-labelledby pointing to ID's of title and desc because some browsers incorrectly don't use them unless we do -->
<svg role="img" viewBox="0 0 100 100" aria-labelledby="unique-title-id unique-desc-id">
<!-- title becomes the tooltip as well as what is read to assistive technology -->
<!-- must be the first child! -->
<title id="unique-title-id">Short Title (e.g. Add to Cart)</title>
<!-- longer description if needed -->
<desc id="unique-desc-id">A friendly looking cartoon cart icon with blinking eyes.</desc>
<!-- all the SVG drawing stuff -->
<path d="..." />
</svg>
但是现在您在某个地方包含了两次该 SVG。假设您在使用 Rails…
<%= render "/icons/icon.svg.erb" %>
<p>yadda yadda yadda</p>
<%= render "/icons/icon.svg.erb" %>
现在页面上将有两个具有完全相同 ID 的元素,这…不好吗?
如果您依赖该 ID 用于任何与 JavaScript 相关的操作,那肯定是不好的,因为 JavaScript 只会找到第一个,这可能会造成混淆和奇怪的结果。
我不确定这是否对可访问性有害。也许其他人可以对此发表意见。假设标题相同,我的猜测是它不会有太大影响。
我认为这对 HTML 语义是不利的,但如果没有任何不良后果,我通常对此并不太在意。
如果您真的有兴趣解决此问题,我的首选方法是手动传入要使用的 ID。
同样,如果您在使用 Rails,您可以传递局部变量
<%=
render(
partial: "parts/modules/search",
locals: {
svg_id: "my-icon",
title_id: "my-icon-title",
desc_id: "my-icon-desc"
}
)
%>
然后设计图标以使用这些局部变量,例如
<svg title="<%= svg_id %> aria-labelledby="<%= title_id %>" ... >
<title id="<%= title_id %>>
...
</svg>
您可以将此概念移植到任何语言。React 应用程序可以有
<SVGIcon svg_id="..." title_id="..." />
PHP 应用程序可以在 include 之前设置变量
$svg_id = "...";
$title_id = "...";
include("/icons/icon.svg.php");
现在,您只需管理 ID 以使其唯一,就像我们一直以来对 ID 所做的那样。
这篇文章的灵感来自 Austin Wolf,他遇到了这个问题,并 思考了一些解决方案。这还包括自动生成唯一的 ID
<svg aria-labelledby="star-6c84fb90-12c4-11e1-840d-7b25c5ee775a">
<title id="star-6c84fb90-12c4-11e1-840d-7b25c5ee775a">star icon</title>
// ...
</svg>
对我来说,这似乎也是一个不错的解决方案。
我很想听听更多想法!
如果它不好?它不仅不好,而且拥有重复的 ID 本身就是无效的 HTML——当然无法通过 w3c 验证器,所以我认为不修复它是不行的。
这就是我所说的“无所谓”。验证是查找错误的绝佳工具,但我不会对此过于纠结。或者更糟糕的是,假设如果您的代码通过了验证,那么它就是完美的。
好吧,事实证明,对于有效的 HTML 确实存在一些后果,因为它是一项 WCAG A 级要求
https://www.w3.org/TR/UNDERSTANDING-WCAG20/ensure-compat-parses.html
但在这种情况下,如果不遵守 A 级要求并不会对可访问性产生实质性的负面影响,前提是标题相同。
尽管如此,我还是会解决这个问题,只是为了让 aXe 不再烦我。
ARIA 的 第一条规则 是:“如果您可以使用具有您所需语义和行为的原生 HTML 元素或属性,而不是重新利用元素并添加 ARIA 角色、状态或属性以使其可访问,那么请这样做。”
我认为这完全适用于此处。我尝试过使用 VoiceOver。只需删除 id 和
aria-labelledby
属性即可。VoiceOver 会读取标题,用户可以选择是否进入图像并阅读说明。在使用内联 SVG 图标时,最重要的是实际包含标题(以及可能包含描述)。我认为以这种方式使用
aria-labelledby
来自 Léonie Watson很难反驳像 Léony Watson 这样经验丰富的用户,但是,您提到的文章来自 2014 年。我的测试是使用 Firefox 中的 VoiceOver,这通常不是您期望完美工作的组合。还在 Safari 中进行了测试,结果也完美无缺。因此,您使用的是一种旧的解决方法(如果我多年无法接触源代码,我最初会谨慎地实施它,因为 AT 客户端也逐年改进),这似乎已过时,并且会导致您陷入困境……我建议您重新考虑是否仍然需要此解决方法 :)
自我在 Chris 提到的文章中写下这篇文章以来,屏幕阅读器对 SVG title 元素的支持有所改进,但还没有达到不再需要 ARIA 的程度。一个 快速测试 表明 Firefox 中的 Jaws 或 NVDA 仍然不支持它。
我建议您不要仅根据 VoiceOver 的行为做出任何设计决策。我们现有的 最佳统计数据 表明,VoiceOver 被不到 8% 的屏幕阅读器用户使用,Safari 是大约相同百分比用户的首选浏览器。Jaws 和 NVDA 共同占屏幕阅读器使用的 50% 以上,Firefox 是使用屏幕阅读器的用户中 30% 以上的首选浏览器。
我觉得从可访问性的角度来看,这可能无关紧要。在多个位置使用相同的 svg 会产生重复的 id,但同时,这些标题和描述的值没有改变,因此
aria-labeledby
仍然会在技术上报告正确的值,即使它们指向标记中不同的 SVG。我唯一看到的问题是 JavaScript 选择显然是一个问题,以及 HTML 验证。
我几乎在创建的所有网站中都使用 twig,这就是我处理此问题的方式,通过传入 ID。也就是说,如果我被迫在多个元素上使用相同的 ID(我在像“OpenTable”预订按钮这样的插件中遇到过这种情况,这些按钮是由第三方脚本呈现的),我只需更改我的 js 选择器以使其更具通用性
document.querySelectorAll('[id=some-id]')
有什么理由不直接使用
document.querySelectorAll('#some-id')
吗?似乎运行良好
一个普遍的想法,为什么不为常用的 SVG 删除 ID,而只在特定需要时使用 ID?就像我们对 HTML 已经做的那样?
然后,嵌入时无需担心,尤其是在它只是一个图标的情况下,您真的需要在其中使用 ID 吗?
在这种情况下,如果重用很重要,另一种方法是使用 aria-label 而不是 aria-labelledby。例如
我个人根本不会在 svg 上使用 id。
如果您需要一个可点击的图标,则将其包装在一个带有 id 的 span 中。
这样一来,即使全世界都是重复的,也不会有什么区别。
如果你第二次包含图标,为什么不简单地使用它呢?这应该可以节省字节并解决多个ID的问题。
这里有一个想法……如果我们谈论的是图标,那么它们可能只是装饰性的。那么如何使用
aria-hidden="true"
将它们隐藏在屏幕阅读器中呢?我有一个小的(418字节)SVG图标,可以轻松嵌入到我的CSS中——我的CSS非常小(不包含SVG的情况下为472字节),我可以轻松地将其全部弹出到HEAD中。是的,朋友们,一个基于Jeff Starr的H5的简单文本博客,仅供参考。但是我们老朋友IE肯定不喜欢嵌入的SVG,因此,与其费力地使用IE hack,我发现从长远来看,简单地使用CSS中的URL()引用到小型SVG文件要轻松得多。就像人们常说的,老婆孩子热炕头。