把svg图标制作成字体图标
by Sarah Dayan
通过莎拉·达扬
让我们用SVG符号和CSS变量制作彩色图标 (Let’s make multi-colored icons with SVG symbols and CSS variables)
Long gone are the days of using images and CSS sprites to make icons for the web. With the explosion of web fonts, icon fonts have become the number one solution for displaying icons in your web projects.
使用图像和CSS精灵为网络创建图标的日子已经一去不复返了。 随着Web字体的爆炸式增长,图标字体已成为在Web项目中显示图标的第一解决方案。
Fonts are vectors, so you don’t have to worry about resolution. They benefit from the same CSS properties as text. As a result, you have full control over size, color, and style. You can add transforms, effects, and decorations such as rotations, underlines, or shadows.
字体是矢量,因此您不必担心分辨率。 它们受益于与文本相同CSS属性。 因此,您可以完全控制大小,颜色和样式。 您可以添加变换,效果和修饰,例如旋转,下划线或阴影。
Icon fonts aren’t perfect though, which is why a growing number of people prefer using inline SVG images. CSS Tricks wrote a list of areas where icon fonts fall short compared to native SVG elements: sharpness, positioning, or even failures because of cross-domain loading, browser-specific bugs, and ad-blockers. Now you can circumvent most of these issues, generally making icon fonts a safe choice.
图标字体并不是很完美,这就是为什么越来越多的人更喜欢使用嵌入式SVG图像的原因。 与本地SVG元素相比, CSS Tricks 列出了图标字体不足的区域列表 :锐度,位置,甚至由于跨域加载,浏览器特定的错误和广告拦截器而失败。 现在,您可以解决大多数这些问题,通常使图标字体成为安全的选择。
Yet, there’s one thing that remains absolutely impossible with icon fonts:multicolor support. Only SVG can do this.
但是,图标字体仍然绝对不可能实现一件事:多色支持。 只有SVG可以做到这一点。
TL;DR: this post goes in-depth into the how and why. If you want to understand the whole thought process, read on. Otherwise you can look at the final code on CodePen.
TL; DR:这篇文章深入探讨了如何以及为什么。如果您想了解整个思考过程,请继续阅读。否则,您可以在CodePen上查看最终代码。
设置SVG符号图标 (Setting up SVG symbol icons)
The problem with inline SVGs is how verbose they are. You don’t want to copy/paste all those coordinates every single time you need to use the same icon. This would be repetitive, hard to read, and a pain to maintain.
内联SVG的问题在于它们的详细程度。 您不想每次都需要使用同一图标复制/粘贴所有这些坐标。 这将是重复的,难以阅读的并且难以维护。
With SVG symbol icons, you have one copy of each SVG element, and you instantiate them anywhere with a reference.
使用SVG符号图标,您可以获得每个SVG元素的一个副本,并且可以在任何地方使用参考实例化它们。
You start by including the SVG inline, hide it, wrap it in a<symb
ol> and identify it with
an id attribute.
你通过包括SVG内联展开,隐藏它,它包装在一个<symb
醇>和识别它无线th
的id属性。
<svg xmlns="/2000/svg" style="display: none"> <symbol id="my-first-icon" viewBox="0 0 20 20"> <title>my-first-icon</title> <path d="..." /> </symbol></svg>
The full SVG markup is included once and hidden in the HTML.
完整的SVG标记仅包含一次并隐藏在HTML中。
Then, all you have to do is instantiate the icon with a<u
se> element.
然后,您要做的就是使用<u
se>元素实例化图标。
<svg> <use xlink:href="#my-first-icon" /></svg>
This will display an exact copy of your original SVG icon.
这将显示原始SVG图标的精确副本。
That’s it!Pretty nice, right?
而已!很好,对吗?
You probably noticed the funnyxlink:href
attribute: this is the link between your instance and the original SVG.
您可能已经注意到了有趣的xlink:href
属性:这是您的实例和原始SVG之间的链接。
It’s important to mention thatxlink:href
is a deprecated SVG attribute. Even if most browsers still support it,you should usehref
instead. Now the thing is, some browsers like Safari don’t support SVG resource references through thehref
attribute, so you still need to providexlink:href
.
重要的是要提到xlink:href
是已弃用的SVG属性。 即使大多数浏览器仍然支持它,您也应该改用href
。 现在的事情是,某些浏览器(例如Safari)不通过href
属性支持SVG资源引用,因此您仍然需要提供xlink:href
。
To be safe, provide both attributes.
为了安全起见,请同时提供两个属性。
添加一些颜色 (Adding some color)
Unlike with fonts,color
doesn’t have any effect on SVG icons: you must use thefill
attributes to define a color. This means that they won’t inherit parent text color like icon fonts do, but you can still style them in CSS.
与字体不同,color
对SVG图标没有任何影响:您必须使用fill
属性定义颜色。 这意味着它们不会像图标字体那样继承父级文本颜色,但是您仍然可以在CSS中设置样式。
// HTML<svg class="icon"> <use xlink:href="#my-first-icon" /></svg>
// CSS.icon { width: 100px; height: 100px; fill: red;}
From here, you can create other instances of the same icon with a different fill color.
在这里,您可以使用不同的填充颜色创建同一图标的其他实例。
// HTML<svg class="icon icon-red"> <use xlink:href="#my-first-icon" /></svg>
<svg class="icon icon-blue"> <use xlink:href="#my-first-icon" /></svg>
// CSS.icon { width: 100px; height: 100px;}.icon-red { fill: red;}.icon-blue { fill: blue;}
It works, but this isn’texactlywhat we want. So far, all we have done can be achieved with a regular icon font. What we want is to have adifferentcolor for eachpartof the icon. We want to fill eachpathwith a different color, without altering other instances, and we want to be able to override it if necessary.
它的工作原理,但是这不正是我们想要的。 到目前为止,我们可以使用常规图标字体完成所有操作。 我们想要的是图标的每个部分都有不同的颜色。 我们希望用不同的颜色填充每个路径,而无需更改其他实例,并且我们希望能够在必要时覆盖它。
At first, you might be tempted to rely on specificity.
首先,您可能会想依赖于特异性。
// HTML<svg xmlns="/2000/svg" style="display: none"> <symbol id="my-first-icon" viewBox="0 0 20 20"> <title>my-first-icon</title> <path class="path1" d="..." /> <path class="path2" d="..." /> <path class="path3" d="..." /> </symbol></svg>
<svg class="icon icon-colors"> <use xlink:href="#my-first-icon" /></svg>
// CSS.icon-colors .path1 { fill: red;}.icon-colors .path2 { fill: green;}.icon-colors .path3 { fill: blue;}
This won’t work.
这行不通。
We’re trying to style.path1
,.path2
and.path3
as if they were nested in.icon-colors
, but technically speakingthey’re not. The<u
se> element isn’t a placeholder that gets replaced by your SVG definition. It’s a reference which clones the content it’s pointing to into the shadow DOM ?
我们正在尝试对.path1
,.path2
和.path3
进行样式.path1
,就好像它们嵌套在.icon-colors
,但从技术上讲,它们不是。<u
se>元素不是被SVG定义替换的占位符。 我的参考是克隆它指向影子DOM的内容吗?
What can we do then?How can we affect children content in a scoped way when said children aren’t in the DOM?
那我们该怎么办?当所说的子代不在DOM中时,我们如何以限定范围的方式影响子代内容?
CSS变量解救 (CSS variables to the rescue)
In CSS, some properties are inherited from ancestors to children. If you assign a text color to thebody
, all the text in the page will inherit that color until it’s overridden. The ancestor isn’t aware of the children, but theinheritablestyles are still propagated.
在CSS中, 某些属性是从祖先继承到孩子的。 如果您分配文本颜色的body
,直到它覆盖在页面中的所有文本将继承这种颜色。 祖先不知道孩子,但是可继承的样式仍然传播。
In our early example, we inherited thefill
property. Look again, and you’ll see that the class in which we declared afill
color is appended on theinstances, not the definitions. This is how we were able to get different colors for each instance of a single definition.
在我们的早期示例中,我们继承了fill
属性。 再次查看,您会看到在其中声明了fill
颜色的类附加在实例上,而不是定义的后面。 这就是我们能够为单个定义的每个实例获取不同颜色的方式。
Now here’s the problem: we want to passdifferentcolors todifferentpaths of the original SVG, but there’s only onefill
attribute we can inherit from.
现在是问题所在:我们想将不同的颜色传递到原始SVG的不同路径,但是只能继承一个fill
属性。
MeetCSS variables.
符合CSS变量。
CSS variables are declared within rulesets just like any other property. You can name them anything you want, and assign them any valid CSS value. Then, you declare it as avaluefor itself, or any child property, andit will be inherited.
就像其他任何属性一样,CSS变量在规则集中声明。 您可以为它们命名任何所需的名称,并为它们分配任何有效CSS值。 然后,声明它作为本身就是一种价值,或任何子属性,它将被继承。
.parent { --custom-property: red; color: var(--custom-property);}
All children of.parent
will have red text.
.parent
所有子代.parent
将显示红色文本。
.parent { --custom-property: red;}.child { color: var(--custom-property);}
All.child
nested in.parent
elements will have red text.
嵌套在.parent
元素中的所有.child
都将带有红色文本。
Now let’s apply this concept to our SVG symbol. We’ll use thefill
attribute on each path of the SVG definition, and set them to different CSS variables. Then, we’ll assign them different colors.
现在,将这个概念应用于我们的SVG符号。 我们将在SVG定义的每个路径上使用fill
属性,并将它们设置为不同CSS变量。 然后,我们将为它们分配不同的颜色。
// HTML<svg xmlns="/2000/svg" style="display: none"> <symbol id="my-first-icon" viewBox="0 0 20 20"> <title>my-first-icon</title> <path fill="var(--color-1)" d="..." /> <path fill="var(--color-2)" d="..." /> <path fill="var(--color-3)" d="..." /> </symbol></svg>
<svg class="icon icon-colors"> <use xlink:href="#my-first-icon" /></svg>
// CSS.icon-colors { --color-1: #c13127; --color-2: #ef5b49; --color-3: #cacaea;}
And…it works! ?
而且...有效! ?
From now on, all we need to do to create an instance with a different color scheme is to create a new class.
从现在开始,创建具有不同配色方案的实例所需要做的就是创建一个新类。
// HTML<svg class="icon icon-colors-alt"> <use xlink:href="#my-first-icon" /></svg>
// CSS.icon-colors-alt { --color-1: brown; --color-2: yellow; --color-3: pink;}
If you still want to have monochrome icons,you don’t have to repeat the same color on every CSS variable. Instead, you can declare a singlefill
rule: because CSS variables aren’t defined, it will fall back on yourfill
declaration.
如果您仍然想要单色图标,则不必在每个CSS变量上重复相同的颜色。 相反,您可以声明一个fill
规则:由于未定义CSS变量,因此它将落入fill
声明中。
.icon-monochrome { fill: grey;}
Yourfill
declaration will work because thefill
attributes on the original SVG are set with undefined CSS variables values.
您的fill
声明将起作用,因为原始SVG上的fill
属性是使用未定义CSS变量值设置的。
用什么来命名我CSS变量? (What to name my CSS variables?)
There are usually two routes you can take when it comes to naming things in CSS:descriptiveorsemantic. Descriptive means calling a colorwhat it is: if you’re storing#ff0000
, you’d call it--red
. Semantic means calling the color byhow it’s applied: if you’re using#ff0000
for the handle of a coffee cup, you’d call it--cup-handle-color
.
在CSS中命名时,通常可以采取两种方法:描述性或语义性。 描述性意味着将颜色--red
为:如果存储#ff0000
,则将其--red
。 语义意味着通过颜色的应用来调用颜色:如果您将#ff0000
用作咖啡杯的句柄,则将其--cup-handle-color
。
Descriptive names might be your first instinct. It feels DRYer since#ff0000
can be used for other things than the handle of the coffee cup. A--red
CSS variable is reusable for other icon paths that need to be red. After all, this is how utility-first CSS works and it’s a fine system.
描述性名称可能是您的本能。 因为#ff0000
可以用于咖啡杯手柄以外的其他用途,所以感觉很干。--red
CSS变量可用于需要为红色的其他图标路径。 毕竟,这是实用程序优先CSS的工作方式, 并且是一个不错的系统 。
Problem is, in our casewe can’t apply granular classes to the elements we want to style. Utility-first principles can’t apply, because we have a single reference for each icon, and we have to style it through class variations.
问题是,在我们的案例中,我们无法将粒度类应用于要设置样式的元素。 实用程序优先原则不适用,因为我们对每个图标都有一个引用,并且必须通过类变体对其进行样式设置。
Using semantic class names, like--cup-handle-color
for example, makes more sense for this use case. When you want to change the color of a part of an icon, you instantly know what it is and what to override. The class name will remain relevant no matter what color you assign.
对于这种用例,使用语义类名称(例如--cup-handle-color
更有意义。 当您想要更改图标的一部分的颜色时,您会立即知道它是什么以及要覆盖的内容。 无论您分配什么颜色,班级名称都将保持相关。
默认还是不默认 (To default or not to default)
It’s tempting to make the multi-colored version of your icons their default state. This way, you could use them with no need for extra styling, and you would add your own classes only when necessary.
诱使图标的多色版本成为默认状态。 这样,您可以使用它们而无需额外的样式,并且仅在必要时添加自己的类。
There are two ways to achieve that::rootandvar() default.
有两种方法可以实现::root和var()default。
:根 (:root)
You can define all your CSS variables on the:root
selector. This keeps them all in one place and allows you to “share” similar colors.:root
has the lowest priority, so it remains easy to override.
您可以在:root
选择器上定义所有CSS变量。 这样可以将它们全部放在一个位置,并允许您“共享”相似的颜色。:root
具有最低优先级,因此仍然易于覆盖。
:root { --color-1: red; --color-2: green; --color-3: blue; --color-4: var(--color-1);}
.icon-colors-alt { --color-1: brown; --color-2: yellow; --color-3: pink; --color-4: orange;}
However,there are major drawbacks to this method. First, keeping color definitions separate from their respective icons can be confusing. When you decide to override them, you have to go back and forth between the class and the:root
selector. But more importantly,it doesn’t allow you to scope your CSS variables, thus keeps you from reusing the same names.
但是,该方法存在主要缺点。 首先,将颜色定义与其各自的图标分开可能会造成混淆。 当您决定覆盖它们时,必须在类和:root
选择器之间来回切换。 但更重要的是,它不允许您限制CSS变量的范围,从而使您避免重用相同的名称。
Most of the time, when an icon only uses one color, I use the--fill-color
name. It’s simple, understandable, and it makes sense to use the same name for all icons that only need one fill color. If I have to declare all variables in the:root
declaration, I can’t have several--fill-color
. I’ll be forced to define--fill-color-1
,--fill-color-2
, or use namespaces like--star-fill-color
,--cup-fill-color
.
大多数情况下,当图标仅使用一种颜色时,我会使用--fill-color
名称。 这是简单,易于理解的,并且对于只需要一种填充颜色的所有图标使用相同的名称是有意义的。 如果必须在:root
声明中声明所有变量,则不能有多个--fill-color
。 我将不得不定义--fill-color-1
,----fill-color-2
或使用--star-fill-color
,----cup-fill-color
类的命名空间。
var()默认 (var() default)
Thevar()
function, which you use to assign a CSS variable to a property, can take a default value as a second argument.
用来将CSS变量分配给属性的var()
函数可以将默认值用作第二个参数。
<svg xmlns="/2000/svg" style="display: none"> <symbol id="my-first-icon" viewBox="0 0 20 20"> <title>my-first-icon</title> <path fill="var(--color-1, red)" d="..." /> <path fill="var(--color-2, blue)" d="..." /> <path fill="var(--color-3, green)" d="..." /> </symbol></svg>
Until you define--color-1
,--color-2
and--color-3
, the icon will use the default values you set for each<pa
th>. This solves the global scope issue we have whenusing
:root, but be careful: you now have a default value and it’s doing its job. As a result, you can’t use a singl
e fill declaration to define monochrome icons anymore. You’ll have to assign the color to every CSS variable used on the icon, one by one.
在定义--color-1
,----color-2
和--color-3
,图标将使用为每个<pa
th>设置的默认值。 这解决了我们在using
:root时遇到的全局范围问题,但要小心:您现在有了一个默认值,并且可以正常工作。 因此,您不能ingl
用作ingl
填充声明来定义单色图标。 您必须将颜色逐一分配给图标上使用的每个CSS变量。
Setting default values can be useful, but it’s a tradeoff. I suggest you don’t make it a habit, and only do it when it makes sense for a given project.
设置默认值可能很有用,但这是一个折衷。 我建议您不要养成习惯,只有在对给定项目有意义时才这样做。
所有这些对浏览器的友好程度如何? (How browser-friendly is all that?)
CSS variables are compatible with most modern browsers, but as you probably expect it, Internet Explorer doesn’t support itat all. Not even IE11, and since development was discontinued in favor of Edge, there’s no chance it will ever get up to speed.
CSS变量是最现代的浏览器兼容 ,但正如你可能想到吧,Internet Explorer不会在所有支持它。 甚至没有IE11,并且由于支持Edge而中止了开发,因此它永远不会加速。
Now, just because a feature isn’t supported by a browser you need to cater to, that doesn’t mean you have to rule it out altogether. In such cases, go forgraceful degradation: offer multi-colored icons to modern browsers, and provide a fallback fill color for older ones.
现在,仅仅因为您需要迎合某个浏览器不支持的功能,就并不意味着您必须将其完全排除在外。 在这种情况下,请进行适当的降级:向现代浏览器提供彩色图标,并为较旧的浏览器提供后备填充颜色。
What you want to do is set a declaration that will only work if CSS variables aren’t supported. This can be achieved by setting thefill
property to the fallback color: if CSS variables are supported, it won’t even be taken into account. If they’re not, yourfill
declaration will apply.
您要做的是设置一个声明,该声明仅在不支持CSS变量的情况下才有效。 这可以通过将fill
属性设置为后备颜色来实现:如果支持CSS变量,则甚至不会考虑它。 如果不是,则将使用您的fill
声明。
If you’re using Sass, this can be abstracted into a@mixin
.
如果您使用的是Sass,则可以将其抽象为@mixin
。
@mixin icon-colors($fallback: black) { fill: $fallback; @content;}
We can now define color schemes without worrying about browser compatibility.
现在,我们可以定义配色方案,而不必担心浏览器的兼容性。
.cup { @include icon-colors() { --cup-color: red; --smoke-color: grey; };}
.cup-alt { @include icon-colors(green) { --cup-color: green; --smoke-color: grey; };}
Passing the CSS variables in the mixin through@content
is optional. If you do it outside, the compiled CSS will be the same. But it can be helpful to package it all in one place: you can fold snippets in your editor and visually identify declarations that go together.
通过@content
传递mixin中CSS变量是可选的。如果在外部执行,则编译后CSS将相同。但是将所有内容打包在一个位置可能会有所帮助:您可以在编辑器中折叠代码片段,并直观地标识在一起的声明。
Check out this pen on different browsers. On up-to-date versions of Firefox, Chrome, and Safari, the last two cups will respectively be red with grey smoke and blue with grey smoke. On Internet Explorer and Edge before version 15, the third cup will be all red and the fourth will be all blue! ✨
在不同的浏览器上签出这支笔 。 在最新版本的Firefox,Chrome和Safari上,最后两个杯子分别是带有灰色烟雾的红色和带有灰色烟雾的蓝色。 在版本15之前的Internet Explorer和Edge上,第三个杯子将全为红色,第四个杯子将全为蓝色! ✨
If you want to learn more about SVG symbol icons (and SVG in general), Istronglysuggest you read everything by Sara Soueidan. And if you have any question about CSS symbol icons, don’t hesitate to hit me up on Twitter!
如果您想了解有关SVG符号图标(以及一般SVG)的更多信息,强烈建议您阅读Sara Soueidan的所有文章 。 如果您对CSS符号图标有任何疑问,请立即在Twitter上与我联系!
Originally published at frontstuff.io.
最初发布在frontstuff.io上 。
翻译自: /news/lets-make-your-svg-symbol-icons-multi-colored-with-css-variables-cddd1769fca4/
把svg图标制作成字体图标