从另一个文档导入 SVG 元素,而不会丢失原始文件中的 CSS <style>

Posted

技术标签:

【中文标题】从另一个文档导入 SVG 元素,而不会丢失原始文件中的 CSS <style>【英文标题】:Import an SVG element from another document, without losing the CSS <style> from the original file 【发布时间】:2021-12-12 19:56:34 【问题描述】:

我需要创建一些 SVG 文件,并希望在一个文件中保留一组常用符号并将它们导入到其他文件中。

我设法使用&lt;use&gt; 元素做到了这一点:

<use href="common.svg#symbol1" />

问题是如果common.svg有一个影响元素的CSS样式,那么该样式在导入元素的文件中没有影响。

我在 svgur.com 上上传了两个 SVG 来展示这个:

https://svgur.com/i/bYv.svg

...定义一个 ID 为 ball 的圆圈,该圆圈受在其周围设置红色边框的样式影响。

<svg   version="1.1" xmlns="http://www.w3.org/2000/svg">
    <style>#ball  stroke:#ff0000; stroke-width:10; </style>
    <circle id="ball" cx="50" cy="50" r="45" />
</svg>

https://svgur.com/i/bXA.svg

...使用圆圈。圆圈可见,但边框不可见。

<svg   version="1.1" xmlns="http://www.w3.org/2000/svg">
    <use href="bYv.svg#ball" />
</svg>

问题:

    这是我正在使用的 SVG 渲染器的错误,还是它的行为方式?

    我尝试过的每个渲染器(chrome、firefox、inkscape)都显示相同的结果,所以我怀疑这可能是预期的行为。

    有没有什么方法可以从外部 SVG 文件中导入元素以及影响它的 CSS 样式,使其看起来与原始文档中的完全一样?

【问题讨论】:

【参考方案1】:
    这是我正在使用的 SVG 渲染器的错误,还是它的行为方式?

这是预期的行为。 CSS 规则不适用于跨文档边界。您正在将 SVG 导入主文档,但您的 CSS 在另一个文档中。

    有没有办法从外部 SVG 文件中导入元素以及影响它的 CSS 样式...

没有。

我想你可以在技术上编写一些 javascript 来加载另一个文件并提取 CSS 规则。但我强烈怀疑你不想那样做。

您的 SVG“sprite 文档”不应在 &lt;style&gt; 标记中包含 CSS 规则。

最好的方法是预先准备好用作精灵的 SVG。

我要做的是将您的common.svg 导入矢量编辑器并将您的所有 CSS 属性转换为演示属性。例如,Illustrator 允许您在导出 SVG 时选择样式方法。

你想要的是这样的:

<svg>
  <style>
    .st0 
      fill: red;
    
  </style>

  <symbol id="whatever">
    <path d="..." class="st0"/>
  </symbol>
</svg>

要转换为:

<svg>
  <symbol id="whatever">
    <path d="..." fill="red"/>
  </symbol>
</svg>

【讨论】:

"这是预期行为。CSS 规则不适用于跨文档边界。您正在将 SVG 导入主文档,但您的 CSS 在另一个文档中。"这个前提是错误的。我用 SVG 2 规范的链接和引号发布了这个问题的另一个答案。 出于某种原因,我希望使用 CSS 样式表而不是属性或内联样式...我想一次控制多个元素的外观,这样如果我更改属性,更改会影响所有元素。 使用属性只会给他们原始文档的原始/默认样式。之后你仍然可以使用 CSS 来设置样式。【参考方案2】:

根据Scalable Vector Graphics (SVG) 2 specification(W3C 编辑草案,2021 年 6 月 8 日),似乎应该在导入元素的地方应用原始文档的样式。

部分5.5. The ‘use’ element:

克隆的内容从“use”元素继​​承样式,并且可以成为用户事件的目标。但是,这些克隆的元素实例仍然链接到引用的源并反映原始元素中的 DOM 突变。此外,适用于被引用元素范围内的所有样式规则也适用于克隆影子树的范围内

还有5.5.3. Style Scoping and Inheritance:

与其他阴影树一样,use-element 阴影树展示了样式封装,如 CSS 范围模块 [css-scoping-1] 中所定义。这意味着影子树中的元素从其宿主“使用”元素继承样式,但外部文档中定义的样式规则与影子树中的元素不匹配。相反,影子树维护自己的样式表列表,其 CSS 规则与影子树中的元素匹配

当引用的元素来自外部文档时,处理该文档时生成的样式表对象适用于影子树,并且是只读的。样式表中的所有 URL 引用,包括仅片段引用,都必须是绝对的,相对于包含被引用元素的文档的 URL。用户代理可以为引用相同外部文档的任何影子树重复使用相同的样式表对象。

所以是我尝试的浏览器和 SVG 渲染器不符合标准。

我仍在寻找在现有 SVG 用户代理上模拟这种行为的方法。

【讨论】:

这里指的是 SVG 2。我认为大多数浏览器对 SVG 1.1 标准的支持最好,Inkscape 和 Adob​​e Illustrator 等编辑器仍然建议将文档保存在 SVG 1.1 中。格式。您在 imgur.com 上的示例还在 version= 属性中指定 v1.1。 (只是说 SVG 1.1 规范可能与 v2 不同。)。【参考方案3】:

您的样式将被应用,前提是您的 svg 资产代码是内联

<svg style="display:none" class="svg-asset"   version="1.1" xmlns="http://www.w3.org/2000/svg">
    <style>
    #inline-ball  stroke:#ff0000; stroke-width:10; 
    </style>
    <circle id="inline-ball" cx="50" cy="50" r="45" />
</svg>


<svg   version="1.1" xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#inline-ball" />
</svg>

如果您不想内联 svg 代码,那么 “片段标识符” 可能是更好的嵌入方法。

它基本上是一个精灵概念: 因此,您的图像资产(如符号)需要在 sprite 窗格上以一些 x 或 y 偏移量定位(与可以重叠定位的符号不同)。 您实际上是在加载一个包含嵌入式 css 样式元素的完整 svg,但选择了一个特定的视图框架。

在 css.tricks.com 上查看这篇文章css.tricks.com: How SVG Fragment Identifiers Work

你的 svg 会是这样的

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 96" >
    <g id="icon01">
        <path d="M20.6,23.3L14,16.7V7.9h4v7.2l5.4,5.4L20.6,23.3z M16-0.1c-8.8,0-16,7.2-16,16s7.2,16,16,16s16-7.2,16-16S24.8-0.1,16-0.1z  M16,27.9c-6.6,0-12-5.4-12-12s5.4-12,12-12s12,5.4,12,12S22.6,27.9,16,27.9z"/>
    </g>
    <g id="icon02">
        <path d="M32,43.2c0,2.7-1.2,5.1-3,6.8l0,0l-10,10c-1,1-2,2-3,2s-2-1-3-2l-10-10c-1.9-1.7-3-4.1-3-6.8c0-5.1,4.1-9.2,9.2-9.2c2.7,0,5.1,1.2,6.8,3c1.7-1.9,4.1-3,6.8-3C27.9,33.9,32,38.1,32,43.2z"/>
    </g>
    <view id="icon-clock-view" viewBox="0 0 32 32" />
    <view id="icon-heart-view" viewBox="0 32 32 32" />
</svg>

为了使用片段标识符,我们需要添加 &lt;view&gt; 元素和相应的精灵区域坐标(在 viewBox 属性中定义)。 与符号定义不同,我们不会将实际路径数据嵌套在视图元素中。

通过将目标 ID 添加到我们的 src url 来嵌入 html

<img class="svg-fragment" src="fragment-ready-1.svg#icon-heart-view">

然而,在您的 html 中内联 svg 图形,仍然提供了最好的样式控制。 (例如,您网站 css 文件中的样式元素) 也许我们将来会看到对样式化远程嵌入 svg 资产的额外支持……在此之前,我们仍然必须应对一些浏览器怪癖。

【讨论】:

以上是关于从另一个文档导入 SVG 元素,而不会丢失原始文件中的 CSS <style>的主要内容,如果未能解决你的问题,请参考以下文章

生成和拖动 SVG 元素 - 方法

Flexbox 使用原始 SVG 宽度而不是缩放宽度

mPDF 从另一个文档导入页面

导入 img 而不是 SVG

SVG渐变

将Python导入函数从另一个目录导入文件,然后从另一个目录导入另一个函数