CSS中的内联SVG

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

我的意思是:

.my-class {
background-image: <svg>...</svg>;
}
392391 次浏览

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

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>");
}

(请注意,SVG内容需要进行url转义才能工作,例如#%23取代。)

这在IE 9中工作(支持SVG)。数据url在旧版本的IE中也可以工作(有限制),但它们本身不支持SVG。

有点晚了,但如果你们中的任何人已经疯狂地试图使用内联SVG作为背景,上面的转义建议并不完全有效。首先,它不能在IE中工作,而且取决于SVG的内容,该技术在其他浏览器(如FF)中会造成麻烦。

如果base64编码svg(不是整个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 = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
width: 100%;
height: 100%;
margin: 0;
}
<div id="myDiv"></div>

With JS you can generate SVGs on the fly, even changing its parameters.

One of the better articles on using SVG is here : http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Hope this helps

Mike

在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博客文章

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

当您需要为其他需要(CSS中的background-image或HTML中的img元素)重新使用这些svg片段时,请注意丢失的名称空间。如果没有名称空间,浏览器可能会拒绝显示SVG(无论编码是utf8还是base64)。

我在CodePen演示中也遇到了将内联SVG嵌入CSS的问题。使用SCSS的解决方案是构建一个简单的url编码函数。

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

然后,用__abc6代码替换%<>"':

@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/

对于那些仍在挣扎的人,我设法让它在所有IE11及以上的现代浏览器上工作。

base64不适合我,因为我想使用SASS根据任何给定的颜色生成SVG图标。这样我就可以用任何颜色创建一个特定的图标,并且只需要在CSS中嵌入SVG形状一次。(使用base64,你必须在你想使用的每一种颜色中嵌入SVG)

有三件事你需要注意:

  1. URL ENCODE YOUR SVG 正如其他人建议的那样,您需要对整个SVG字符串进行URL编码,以便在IE11中工作。在我的例子中,我省略了诸如fill="#00FF00"stroke="#FF0000"等字段中的颜色值,并将它们替换为SASS变量fill="#{$color-rgb}",以便它们可以替换为我想要的颜色。你可以使用任何在线转换器对字符串的其余部分进行URL编码。您将得到如下的SVG字符串:

    % 3 csvg % 20 xmlns % 3 d % 27 http % 3 a % 2 f % 2 fwww.w3.org % 2 f2000 % 2 fsvg % 20 viewbox % 3 d % 270% 27% 200% 20494.572% 20494.572% 27% 20宽度% 3 d % 27512% 27% 20高% 3 d % 27512% 27% 3 e % 0 a % 20% 20% 3 cpath % 20 d % d % 27 m257.063 % 200 c127.136 % 200% 2021.808% 20105.33% 2021.808% 20235.266 c0 % 2041.012% 2010.535% 2079.541% 2028.973% 20113.104 l3.825 % 20464.586 c345 % 2012.797% 2041.813% 2012.797% 2015.467% 200% 2029.872 - -4.721% 2041.813 -12.797 v158.184z % 20填补27% % 3 d % 27 # <强>{$色rgb} < /强> % 27% 2 f % 3 e % 3 c % 2 fsvg % 3 e < / p >


  1. 当创建你的数据URL时,你需要省略字符集,以便在IE11中工作。

    background-image: url(data:image/svg+xml;utf-8,%3Csvg%2....)
    BUT background-image: url(data:image/svg+xml,%3Csvg%2....)

    .

  1. 使用RGB()代替十六进制颜色 Firefox不喜欢SVG代码中的#所以你需要用RGB替换颜色十六进制值。

    < p > 填补= " # FF0000 " < br > 但< / >强填补= " rgb(255, 0, 0)”< / p >

在我的例子中,我使用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文件。

我找到了SVG的一个解决方案。但这只是Webkit的工作,我只是想与你分享我的工作方法。在我的例子中展示了如何使用SVG元素从DOM作为背景通过过滤器(background-image: url('#glyph')是不工作的)。

SVG图标渲染所需的特性:

  1. 应用SVG滤镜效果HTML元素使用CSS (IE和 边缘不支持)
  2. feImage片段加载支持(firefox没有 李支持)< / >

.test {
/*  background-image: url('#glyph');
background-size:100% 100%;*/
filter: url(#image);
height:100px;
width:100px;
}
.test:before {
display:block;
content:'';
color:transparent;
}
.test2{
width:100px;
height:100px;
}
.test2:before {
display:block;
content:'';
color:transparent;
filter: url(#image);
height:100px;
width:100px;
}
<svg style="height:0;width:0;" version="1.1" viewbox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="glyph">
<path id="heart" d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
</g>
<svg id="resized-glyph"  x="0%" y="0%" width="24" height="24" viewBox="0 0 100 100" class="icon shape-codepen">
<use xlink:href="#glyph"></use>
</svg>
<filter id="image">
<feImage xlink:href="#resized-glyph" x="0%" y="0%" width="100%" height="100%" result="res"/>
<feComposite operator="over" in="res" in2="SourceGraphic"/>
</filter>
</defs>
</svg>
<div class="test">
</div>
<div class="test2">
</div>

另一个解决方案是使用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{
height:50px;
width:250px;
display:block;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
}
<svg  height="100" width="500" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
</svg>
<div class="container"></div>

你也可以这样做:

<svg viewBox="0 0 32 32">
<path d="M11.333 13.173c0-2.51 2.185-4.506 4.794-4.506 2.67 0 4.539 2.053 4.539 4.506 0 2.111-0.928 3.879-3.836 4.392v0.628c0 0.628-0.496 1.141-1.163 1.141s-1.163-0.513-1.163-1.141v-1.654c0-0.628 0.751-1.141 1.419-1.141 1.335 0 2.571-1.027 2.571-2.224 0-1.255-1.092-2.224-2.367-2.224-1.335 0-2.367 1.027-2.367 2.224 0 0.628-0.546 1.141-1.214 1.141s-1.214-0.513-1.214-1.141zM15.333 23.333c-0.347 0-0.679-0.143-0.936-0.404s-0.398-0.597-0.398-0.949 0.141-0.689 0.398-0.949c0.481-0.488 1.39-0.488 1.871 0 0.257 0.26 0.398 0.597 0.398 0.949s-0.141 0.689-0.398 0.949c-0.256 0.26-0.588 0.404-0.935 0.404zM16 26.951c-6.040 0-10.951-4.911-10.951-10.951s4.911-10.951 10.951-10.951c6.040 0 10.951 4.911 10.951 10.951s-4.911 10.951-10.951 10.951zM16 3.333c-6.984 0-12.667 5.683-12.667 12.667s5.683 12.667 12.667 12.667c6.984 0 12.667-5.683 12.667-12.667s-5.683-12.667-12.667-12.667z"></path>
</svg>

我的解决方案是

基于前面提到的https://github.com/yoksel/url-encoder/所采用的方法以编程方式完成:

// Svg (string)


const hexagon = `
<svg
width="100"
height="20"
viewBox="0 0 100 20"
xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="redyel"
gradientUnits="objectBoundingBox"
x1="0"
y1="0"
x2="1"
y2="1"
>
<stop offset="0%" stop-color="#ff0000" />
<stop offset="100%" stop-color="#ffff00" />
</linearGradient>
</defs>
<polygon
points="0,10 5,0 95,0 100,10 95,20 5,20"
fill="#eee"
stroke="url(#redyel)"
/>
</svg>
`


// svgToBackgroundImage


const symbols = /[%#()<>?[\\\]^`{|}]/g;


const newLine = /\r?\n/;


const notEmptyString = (str) => str.length;
const trim = (str) => str.trim();


const toOneLine = (str) =>
str.split(newLine).filter(notEmptyString).map(trim).join(" ");


function addNameSpace(svgString) {
if (svgString.indexOf(`http://www.w3.org/2000/svg`) < 0) {
svgString = svgString.replace(
/<svg/g,
`<svg xmlns="http://www.w3.org/2000/svg"`
);
}


return svgString;
}


function encodeSVG(svgString) {
svgString = svgString.replace(/>\s{1,}</g, `><`);
svgString = svgString.replace(/\s{2,}/g, ` `);


// Using encodeURIComponent() as replacement function
// allows to keep result code readable
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);
#hexagon {
width: 100px;
height: 20px;
}
<div id="hexagon"/>

如果你正在使用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);
}