ChatGPT解决这个技术问题 Extra ChatGPT

CSS 中的内联 SVG

是否可以在 CSS 中使用内联 SVG 定义?

我的意思是:

.my-class {
  background-image: <svg>...</svg>;
}
请注意,如果 SVG 是多个图像的混合(除非嵌入),则建议的解决方案不适用于 CSS 图像、HTML <img> 标记和其他情况,请参阅 background image SVG with mask using external image not working,特别是 restrictions on SVG used as an image

P
Paul D. Waite

对的,这是可能的。尝试这个:

body { background-image: 
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url(%23gradient)' x='0' y='0' width='100%' height='100%'/></svg>");
      }

http://jsfiddle.net/6WAtQ/

(请注意,需要对 SVG 内容进行 url 转义才能使其正常工作,例如 # 被替换为 %23。)

This works in IE 9 (which supports SVG)。数据 URL 也适用于旧版本的 IE(有限制),但它们本身并不支持 SVG。


唯一看起来运行良好的浏览器是 Safari (5.1.4)。在 Opera 11.62 中渐变为黑色,在 IE 9 和 Firefox 12 中为白色。在 Chrome 19 中,除非您以 % 为单位指定 SVG 的宽度/高度,否则它可以工作。我会说这比真正的功能更奇怪。这是一个很酷的发现。
对……当我向同事们展示这样一个可爱的小怪物时,我仍然很想看到他们脸上的表情,所以再次感谢展示它是可能的。我只是去了标准规范并说这几乎是不可能的,结果证明是一个错误(有点)
这里的“浏览器不兼容”主要是缺少正确的 URL 转义,url() 中的所有内容都应该进行 url 转义。有关在 Opera、Firefox 和 Safari 中运行良好的示例,请参见 jsfiddle.net/6WAtQ
base64 编码的 svg 与非 base64 之间是否存在兼容性差异? Base64 使我的 css 文件膨胀,我想只使用内联 svgs ..
注意,指定字符集的标准方法是使用“;charset=UTF-8”而不是“;utf8”。 tools.ietf.org/html/rfc2397
O
Ofer Zelig

有点晚了,但是如果你们中的任何一个人一直在疯狂地尝试使用内联 SVG 作为背景,那么上面的转义建议并不完全奏效。一方面,它在 IE 中不起作用,并且根据 SVG 的内容,该技术会在其他浏览器(如 FF)中引起问题。

如果您对 svg 进行 base64 编码(不是整个 url,只是 svg 标签及其内容!)它适用于所有浏览器。这是 base64 中相同的 jsfiddle 示例:http://jsfiddle.net/vPA9z/3/

CSS 现在看起来像这样:

body { background-image: 
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");

请记住在转换为 base64 之前删除任何 URL 转义。换句话说,上面的例子显示color='#fcc'转换为color='%23fcc',你应该回到#。

base64 效果更好的原因是它消除了单引号和双引号以及 url 转义的所有问题

如果您使用的是 JS,您可以使用 window.btoa() 来生成您的 base64 svg;如果它不起作用(它可能会抱怨字符串中的无效字符),您可以简单地使用 https://www.base64encode.org/

设置 div 背景的示例:

var mySVG = " "; var mySVG64 = window.btoa(mySVG); document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')"; html,正文,#myDiv { 宽度:100%;高度:100%;边距:0; }

使用 JS,您可以动态生成 SVG,甚至可以更改其参数。

一篇关于使用 SVG 的更好的文章在这里:http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

希望这可以帮助

麦克风


谢啦。 Base64 的解决方案效果很好,而我在接受答案时遇到了麻烦。
你救了我的命。我有一个 SVG 边框图像,它在 chrome 中工作,但在 FF 上没有。现在它起作用了! :D
也帮助了我(在浪费时间尝试接受的答案之后) - 这绝对应该是接受的答案。
如果有人在 6 年后仍然在看这个答案:您可能不应该使用 base64 SVG css-tricks.com/probably-dont-base64-svg
回复“您可能不应该使用 base64 SVG”评论。如果您是对整个 svg 库进行 base64 编码的野兽,请重新考虑您迄今为止的决定,不要对世界进行 base64。但是,如果您正在制作一个模块或插件并且想要嵌入非常小的 SVG 而不是包含一个全新的文件,请这样做。包含一个 base64 编码的 SVG 而不是另一个目录依赖项对于您和使用您的小模块/插件的人来说更容易。
D
Davy Baert

对于仍在苦苦挣扎的人,我设法让它在所有现代浏览器 IE11 及更高版本上运行。

base64 对我来说是没有选择的,因为我想使用 SASS 根据任何给定的颜色生成 SVG 图标。例如:@include svg_icon(heart, #FF0000); 这样我可以创建任何颜色的特定图标,并且只需在 CSS 中嵌入一次 SVG 形状。 (使用 base64,您必须将 SVG 嵌入到您想要使用的每种颜色中)

您需要注意三件事:

URL 编码您的 SVG 正如其他人所建议的,您需要对整个 SVG 字符串进行 URL 编码,以便它在 IE11 中工作。就我而言,我省略了诸如 fill="#00FF00" 和 stroke="#FF0000" 等字段的颜色值,并用 SASS 变量 fill="#{$color-rgb}" 替换它们,因此可以替换它们用我想要的颜色。您可以使用任何在线转换器对字符串的其余部分进行 URL 编码。你最终会得到一个像这样的 SVG 字符串:%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27 %20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0% 2041.012%2010.535%2079.541%2028.973%20113.104L3.825%20464.586c345%2012.797%2041.813%2012.797%2015.467%200%2029.872-4.721%2041.813-12.797v158.184z%27%20fill%3D%27#{$color-rgb }%27%2F%3E%3C%2Fsvg%3E

省略数据 URL 中的 UTF8 字符集 创建数据 URL 时,您需要省略字符集以使其在 IE11 中工作。不是背景图像:url(数据:图像/svg+xml;utf-8,%3Csvg%2....)但是背景图像:url(数据:图像/svg+xml,%3Csvg%2... .)

使用 RGB() 代替十六进制颜色 Firefox 不喜欢 SVG 代码中的 #。因此,您需要将颜色十六进制值替换为 RGB 值。不填充="#FF0000" 但填充="rgb(255,0,0)"

就我而言,我使用 SASS 将给定的十六进制转换为有效的 rgb 值。正如评论中指出的那样,最好也对您的 RGB 字符串进行 URL 编码(因此逗号变为 %2C)

@mixin svg_icon($id, $color) {
   $color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
   @if $id == heart {
      background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
   }
}

我意识到这可能不是非常复杂的 SVG 的最佳解决方案(在这种情况下,内联 SVG 从来都不是),但对于只有几种颜色的平面图标,这真的很好用。

我能够省略整个精灵位图,并在我的 CSS 中用内联 SVG 替换它,压缩后结果只有 25kb 左右。因此,这是限制您的站点必须执行的请求数量的好方法,而不会使您的 CSS 文件膨胀。


顺便说一句,如果我错了,请纠正我,但一旦编码,rgb(255,0,0) 应该变成 rgb(255%2C0%2C0)
我的意思是我不对 RGB 字符串进行编码,它仍然可以工作。但是像你提到的那样对其进行编码可能会更好。
好吧,实际上,我刚刚测试过 %23ff0000 在 Firefox 中对 #ff0000 运行良好
@Capsule 我不知道发生了什么,但 %23ff0000 是唯一适用于 Chrome 和 FF 的方法。 #ff0000 不起作用,RGB(255,0,0) 和 rgb(255%2C0%2C0) 方法也不起作用。
需要较少编码的方法(包括 SCSS 代码):codepen.io/jakob-e/pen/doMoML
A
Anna Vlasenko

我的解决方案是https://yoksel.github.io/url-encoder/您只需插入 svg 并取回背景图像代码


这行得通。快速,超级简单,非常干净。
万一它对任何人有帮助,我尝试了这个并且它对我有用,并且还添加了 background-size: cover 属性,并且 svg 似乎与其容器成比例地伸展。
S
Simon East

在 Mac/Linux 上,您可以使用这个简单的 bash 命令轻松地将 SVG 文件转换为 CSS 背景属性的 base64 编码值:

echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"

在 Mac OS X 上测试。这样您还可以避免 URL 转义混乱。

请记住,对 SVG 文件进行 base64 编码会增加其大小,请参阅 css-tricks.com blog post


致读者:请评论您的意见,而不是仅仅投反对票,这样这个答案可以通过您的合作来改进!在这样的问答网站中,协作是必不可少的。谢谢!
@LorDex 您在评论中提供的链接与我的回答中的链接相同:)
如果纯文本 svg 占用更少的空间并准备好使用内联,那么 base4 转换的原因是什么?
L
Lea Rosema

我已经分叉了一个 CodePen 演示,它在将内联 SVG 嵌入 CSS 时遇到了同样的问题。与 SCSS 一起使用的解决方案是构建一个简单的 url 编码函数。

可以从内置的 str-slice、str-index 函数创建字符串替换函数(请参阅 css-tricks,感谢 Hugo Giraudel)。

然后,只需将 %<>"' 替换为%xx代码:

@function svg-inline($string){
  $result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
  $result: str-replace($result, '%', '%25');
  $result: str-replace($result, '"', '%22');
  $result: str-replace($result, "'", '%27');
  $result: str-replace($result, ' ', '%20');
  $result: str-replace($result, '<', '%3C');
  $result: str-replace($result, '>', '%3E');
  @return "data:image/svg+xml;utf8," + $result;
}

$mySVG: svg-inline("<svg>...</svg>");

html {
  height: 100vh;
  background: url($mySVG) 50% no-repeat;
}

Compass 中还有一个 image-inline 辅助函数,但由于 CodePen 不支持它,因此该解决方案可能有用。

CodePen 上的演示:http://codepen.io/terabaud/details/PZdaJo/


我还创建了一支笔,它允许您将 svg 字符串转换为适当的 css 背景值:s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb 所以,基本上,您将 <svg><path></svg> 粘贴到顶部文本区域,它会直接在 url() 中输出经过清理的路径价值。
这太棒了。谢谢你。一注。你需要使用 ;charset=utf8 来让它在 IE 中工作。
A
Alex Nikulin

我找到了一种 SVG 解决方案。但这仅适用于 Webkit,我只想与您分享我的解决方法。在我的示例中,展示了如何通过过滤器将 DOM 中的 SVG 元素用作背景(背景图像:url('#glyph')不起作用)。

此 SVG 图标渲染所需的功能:

使用 CSS 将 SVG 滤镜效果应用于 HTML 元素(IE 和 Edge 不支持)feImage 片段加载支持(firefox 不支持)

.test { /* 背景图片: url('#glyph');背景尺寸:100% 100%;*/ 过滤器:url(#image);高度:100px;宽度:100 像素; } .test:before { display:block;内容:'';颜色:透明; } .test2{ 宽度:100px;高度:100px; } .test2:before { display:block;内容:'';颜色:透明;过滤器:网址(#image);高度:100px;宽度:100 像素; }

另一种解决方案是使用 url 编码

var container = document.querySelector(".container"); var svg = document.querySelector("svg"); var svgText = (new XMLSerializer()).serializeToString(svg); container.style.backgroundImage = `url(data:image/svg+xml;utf8,${encodeURIComponent(svgText)})`; .container{ 高度:50px;宽度:250px;显示:块;背景位置:中心中心;背景重复:不重复;背景尺寸:包含; }


m
mp31415

来自第 3 方来源(如 Google 图表)的内联 SVG 可能在 SVG 元素中不包含 XML 命名空间属性 (xmlns="http://www.w3.org/2000/svg")(或者可能在呈现 SVG 后将其删除 - 浏览器检查器和浏览器控制台中的 jQuery 命令都不会显示 SVG 中的命名空间元素)。

当您需要将这些 svg 片段重新用于您的其他需求(CSS 中的背景图像或 HTML 中的 img 元素)时,请注意缺少的命名空间。没有命名空间的浏览器可能会拒绝显示 SVG(不管编码是 utf8 还是 base64)。


I
Izhaki

根据已经提到的 https://github.com/yoksel/url-encoder/ 采用的方法以编程方式完成:

// Svg (string) const hexagon = ` ` // svgToBackgroundImage 常量符号 = /[%#()<>?[\\\]^`{|}] /G; const newLine = /\r?\n/;常量 notEmptyString = (str) => str.length;常量修剪 = (str) => str.trim(); const toOneLine = (str) => str.split(newLine).filter(notEmptyString).map(trim).join(" ");函数 addNameSpace(svgString) { if (svgString.indexOf(`http://www.w3.org/2000/svg`) < 0) { svgString = svgString.replace( /\s{1,}<`); svgString = svgString.replace(/\s{2,}/g, ` `); // 使用 encodeURIComponent() 作为替换函数 // 允许保持结果代码可读 return svgString.replace(symbols, encodeURIComponent); } const svgToBackgroundImage = (svgString) => `url('data:image/svg+xml,${encodeSVG(addNameSpace(toOneLine(svgString)))}')`; // DOM const element = document.querySelector("#hexagon"); element.style.backgroundImage = svgToBackgroundImage(六边形); #hexagon { 宽度:100px;高度:20px; }


这个问题的重点是如何内联。例如,如果您没有添加到页面的某些元素的事件挂钩,并且您必须使用纯 CSS 覆盖它。
D
Dr Nic

如果您使用的是 postcss,您可以尝试 postcss-inline-svg 插件 https://www.npmjs.com/package/postcss-inline-svg

.up {
    background: svg-load('img/arrow-up.svg', fill: #000, stroke: #fff);
}
.down {
    background: svg-load('img/arrow-down.svg', fill=#000, stroke=#fff);
}

E
Eduardo La Hoz Miranda

你也可以这样做: