JS动态添加SVG子元素title后tooltip不生效的解决方法
问题
我有一个包含<title>元素的SVG,父级<title>用于ARIA屏幕阅读器。因为给多边形/矩形实现了自定义JavaScript tooltip,希望鼠标悬停这些元素时不显示父级title的tooltip,所以尝试通过JavaScript给多边形/矩形动态添加<title>元素(可为空)。但添加后,尽管DOM中已存在该title,悬停时仍显示父级tooltip;而手动在SVG代码中为子元素添加title则可正常生效。此外,若在开发者工具中无修改编辑HTML后,tooltip可正常显示自定义效果,怀疑浏览器缓存了ARIA元数据状态。已尝试添加/移除类等基础方法,现询问如何通过JavaScript强制浏览器重新评估ARIA元数据。
示例代码
<svg aria-labelledby="title1"> <title id = "title1">My big title</title> <polygon aria-labelledby="title2"></polygon> <!-- 这个title元素是SVG加载后通过JS动态生成的 --> <title id="title2"></title> </svg>
编辑后的测试代码
<svg viewBox="0 0 20 10" xmlns="http://www.w3.org/2000/svg"> <title>Title 1</title> <rect id="rect1" x="11" y="1" width="8" height="8"> </rect> </svg>
var newtitle=document.createElement("title") newtitle.innerText = "Title 2" $("#rect1").append(newtitle)
手动编写的正常生效代码
<svg viewBox="0 0 20 10" xmlns="http://www.w3.org/2000/svg"> <title>Title 1</title> <rect id="rect1" x="11" y="1" width="8" height="8"> <title>Title 2</title> </rect> </svg>
解决方案
1. 使用SVG命名空间创建title元素
SVG元素属于专属命名空间,直接用document.createElement创建的<title>是HTML命名空间的,浏览器不会将其识别为SVG的title节点。必须使用SVG命名空间创建:
// 用SVG命名空间创建title元素 const newTitle = document.createElementNS("http://www.w3.org/2000/svg", "title"); newTitle.textContent = "Title 2"; document.getElementById("rect1").appendChild(newTitle);
2. 触发DOM重排强制更新
若已使用正确命名空间仍存在问题,可通过触发DOM重排让浏览器重新评估元素状态。临时修改元素属性再恢复即可:
const rect = document.getElementById("rect1"); // 临时修改display触发重排 rect.style.display = "none"; void rect.offsetWidth; // 强制浏览器计算布局,触发重排 rect.style.display = "";
3. 动态关联ARIA属性
直接给子元素设置aria-labelledby指向自身的title,或设置aria-label为空来覆盖父级ARIA关联:
const rect = document.getElementById("rect1"); const newTitle = document.createElementNS("http://www.w3.org/2000/svg", "title"); newTitle.id = "rectTitle"; newTitle.textContent = "Title 2"; rect.appendChild(newTitle); // 关联aria-labelledby rect.setAttribute("aria-labelledby", "rectTitle");
4. 替换子元素重置DOM状态
如果以上方法无效,可将目标元素从DOM中移除,替换为包含title的新元素:
const rect = document.getElementById("rect1"); const parent = rect.parentElement; // 创建新rect元素并复制原属性 const newRect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); newRect.setAttribute("x", rect.getAttribute("x")); newRect.setAttribute("y", rect.getAttribute("y")); newRect.setAttribute("width", rect.getAttribute("width")); newRect.setAttribute("height", rect.getAttribute("height")); newRect.id = "rect1"; // 添加title const newTitle = document.createElementNS("http://www.w3.org/2000/svg", "title"); newTitle.textContent = "Title 2"; newRect.appendChild(newTitle); // 替换旧元素 parent.replaceChild(newRect, rect);
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

