当在 <img> 标记中使用 SVG 时,为什么 linearGradient ID 中的冒号会中断它们?

Why do colons in linearGradient IDs break them when the SVG is used in an <img> tag?

获取以下源并将其保存为 test.svg 文件。

<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <linearGradient id="myGradient:1234" gradientTransform="rotate(90)">
      <stop offset="5%" stop-color="gold"></stop>
      <stop offset="95%" stop-color="red"></stop>
    </linearGradient>
  </defs>

  <circle cx="5" cy="5" r="4" fill="url('#myGradient:1234')"></circle>
</svg>

打开Chrome中的test.svg文件,你会看到一个从黄色到红色混合的圆圈。但是,如果您创建一个 HTML 文件并以 <img src="text.svg" /> 的形式包含此 SVG,您将看到,至少在 Chrome 中,没有颜色应用于圆。

如果您更新 test.svg 以将 ID 从 myGradient:1234 更改为 myGradient,那么当在 <img> 标签中使用图像时颜色将开始工作。

为什么这种行为不同?

实际上包含 ':'(冒号)的 ID 也不应该在独立文件中工作。 这是 XML 命名合规性的问题。

An excerpt from the MDN Docs

It must be valid in XML documents. A stand-alone SVG document uses XML 1.0 syntax, which specifies that valid IDs only include designated characters (letters, digits, and a few punctuation marks), and do not start with a digit, a full stop (.) character, or a hyphen-minus (-) character.

根据经验:
应用相同的命名规则,您还需要 html/css/js 选择器:

  1. 保持 ansi:避免非英文字符,如 diacritics/accents 等
  2. 不要以任何数字开头选择器名称 - 像 'element-01' 一样附加它们是完全可以的
  3. 避免使用也用作运算符的字符:例如用于伪元素的冒号、用于相邻兄弟元素的加号或波浪号等。

#myGradient\:1234{
color:red
}

#myGradient\:1234,
# 234myGradient{
color:#000
}

#myGradient-1234{
color:green
}
<ul>
<li id="myGradient-1234">Selectable!</li>
<li id="myGradient:1234">Not selectable: selector contains <strong>colon operator reserved for pseudo elements</strong>. You might however escape the colon by a backslash</li>
<li id="1234myGradient">Not Selectable: selector starts with <strong>numbers</strong></li>
</ul>

编辑:这是一个检查有效性的辅助函数。

checkIDs(document.body);

// check id validity
function checkIDs(el) {
  let Ids = el.querySelectorAll('[id]');
  let allIds = [];
  let IdIssues = {
    'non-unique': {},
    'not-selectable': [],
  }
  for (let i = 0; i < Ids.length; i++) {
    let thisId = Ids[i].id;
    if (allIds.indexOf(thisId) == -1) {
      allIds.push(thisId);
    } else {
      let idKey = '\'' + thisId + '\'';
      if (!IdIssues['non-unique'][idKey]) {
        IdIssues['non-unique'][idKey] = 2;
      } else {
        IdIssues['non-unique'][idKey] += 1;
      }
    }
    try {
      let selection = document.querySelector('#' + thisId);
    } catch {
      if (IdIssues['not-selectable'].indexOf(thisId) == -1) {
        IdIssues['not-selectable'].push(thisId);
      }
    }
  }

  let errorCount = 0;
  let nonUniqueCount = Object.keys(IdIssues['non-unique']).length;
  let notSelectableCount = IdIssues['not-selectable'].length;
  errorCount = nonUniqueCount + notSelectableCount;

  if (errorCount) {
    console.log('Id naming issues found:\n' + 'non unique Ids: ' + nonUniqueCount + '\n' + 'not selectable Ids: ' + notSelectableCount);
    console.log(IdIssues);
  } else {
    console.log('Well done! – all Ids are valid and unique!')
  }
}
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <circle id="circle" fill="none" cx="50%" cy="100%" r="50%" stroke="red" stroke-width="2" />
  <circle id="circle:123" fill="none" cx="25%" cy="25%" r="25%" stroke="green" stroke-width="2" />
</svg>

  <p id="p1@test">test1</p>
  <p id="p1!test">test1</p>
  <p id="c'mon">test1</p>
  <p id="p2">test1</p>
  <p id="p2">test1</p>
  <p id="p2:1:2">test1</p>
  <p id="0123id">test1</p>

这个 js 辅助函数使用一个简单的 try/catch 来检查一个元素是否在 DOM 中实际上是可选的。所以我们不需要检查数百个著名的不合规 character/naming 问题。

此外,该脚本还将检查可能也会引起问题的非唯一 ID。