Author: Zheng Chengzhong

This article is produced by a member of YFE, please respect the original, please contact the public account (ID: yuewen_YFE) for authorization to reprint, and indicate the author, source and link.

It’s 2020. If you haven’t used SVG in your project, it’s just like you haven’t used REACT or VUE in your project.

Regardless of compatibility (IE8+), SVG should be the best solution to the icon problem in a project by far.

SVG can be made larger or smaller without distortion (jagged or pixelated) and can move like a GIF. You will no longer have to cut two images just because the same icon has a different color. You can even modify your SVG ICONS in real time using HTML, CSS, AND JS if you want, even though the first and second ICONS may look completely different.

Our project directly chose SVG as our icon solution at the beginning of the site. Although the above benefits let us feel its good, but in the actual project still encountered some pits. To avoid headlines, here’s a summary of the big and small issues our team has had with SVG over the last three years.

  • A few ways to use SVG
    1. SVG as Img
    2. SVG as Sprite (Iconfont)
    3. SVG in HTML
    4. SVG in CSS
    5. SVG in JS
  • Ii. Actual body sense of technical scheme
    1. SVG as Img & Sprite
    2. SVG In HTML & CSS
    3. SVG In React
  • SVG In React Delivery best practices
  • SVG In React uses best practices
  • 5. Some pitfalls of SVG

A few ways to use SVG

1. SVG as Img

First, SVG can be used as an image file like JPG, PNG, and GIF.

<style>
[data-icon] {
  display: inline-block;
  width: 1em;
  height: 1em;
  background: no-repeat center/contain;
}
[data-icon][size="24"]{
  width: 24px;
  height: 24px;
}
[data-icon="hello"] {
  background-image: url("./assets/hello.svg");
}
</style>
<i aria-hidden="true" size="24" data-icon="hello"></i>
<img src="./assets/hello.svg" width="24" height="24" alt="hello" />
Copy the code

It works either as a background image or as a SRC attribute.

Also available as some Embed Object iframe… Tags and SRC attributes, but because they are rarely used in projects, I won’t go into them here.

2. SVG as Sprite (Iconfont)

We all know that in order to reduce the number of image resource requests, most of the small ICONS will be merged into Sprite images, and then use CSS to control the position of background-position to achieve the display of different ICONS.

For SVG Sprite images, of course, the first is iconFont just need to upload your SVG file, then click download, you can get three combined Sprite images using different poses (similar to the well-known icomoon).

plan Unicode Font class Symbol
compatibility IE6+ IE8+ IE9+
The characteristics of Rendering is not as good as the latter two Easy to use, intuitive writing For the future

Basically, you just need to consider the latter two options based on browser compatibility.

3. SVG in HTML

SVG is a language that uses XML to describe two-dimensional graphics and drawing programs.

Because SVG itself is in XML format, which is naturally similar to HTML, you can inline SVG directly into HTML.

<svg width="50" height="50" viewBox="0 0 50 to 50." " xmlns="http://www.w3.org/2000/svg">
	<rect width="50" height="50" fill="#ff0000"/>
</svg>
Copy the code

For example, if you want to draw a square that is 50px by 50px, just paste the above code into HTML. If you want to change the color or size, you only need to modify the corresponding attributes, which is very intuitive and convenient. This is another irreplaceable advantage of SVG over other image formats, in addition to its vector nature.

But our ICONS are often not only used once, not every icon HTML code is so small, if you want to directly copy and paste to achieve reuse effect is more trouble. Since this is HTML reuse, the easiest way to do this is to use an HTML template engine, using Nunjunks as an example.

<! -- components/Icons/ISquare.html -->
{% macro ISquare(color='red', size='16') %}
<svg width="{{ size }}" height="{{ size }}" viewBox="0 0 50 to 50." " xmlns="http://www.w3.org/2000/svg">
	<rect width="50" height="50" fill="{{ color }}"/>
</svg>
{% endmacro %}
Copy the code

Here we define a component with two input parameters, color and size, in the isquery.html file.

{% import ".. / components/Icons/ISquare. HTML "as ISquare %} < ul > < li > {{ISquare ()}} red size to 16 square < / li > < li > {{ISquare (' yellow ', 24)}} yellow size 24 square </li> </ul>Copy the code

Once the component is defined, we just need to import it where it is used and call it. This is the same as when you define a component in React.

4.SVG in CSS

While not all projects will necessarily use a template engine, you may have a very simple static active page.

For such projects we can take a different approach and inline SVG with CSS. Of course, this is just a new solution, because many build tools have the ability to inline our base64 code from images smaller than 8KB into our CSS.

<style>
[data-icon] {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: middle;
    background: no-repeat center/contain;
}
[data-icon][size="24"]{
   width: 24px;
   height: 24px;
}
[data-icon="square"] {
    background-image: url("data:image/svg+xml; base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9InJlZCIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PC9zdmc+");
}
</style>
<ul>
    <li><i data-icon="square"></i>Red 1em square</li>
    <li><i data-icon="square" size="24"></i>A 24px square in red</li>
</ul>
Copy the code

Similarly, we can convert our SVG to Base64 inline CSS. Background-size: contain; This property indirectly controls the size of the icon by controlling the size of the container, but also loses control over the color of the icon. And this mess looks particularly strange in CSS.

If you follow zhang Xinxu’s blog, you will find such an article “Learned that CSS has a better form for inlining SVG images than Base64”. The simple explanation is that SVG can be inlined into CSS without using Base64 and XML can be directly inlined into CSS.

<style>
[data-icon] {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: middle;
    background: no-repeat center/contain;
}
[data-icon][size="24"]{
   width: 24px;
   height: 24px;
}
[data-icon="square"] {
  background-image: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='red' d='M0 0h50v50H0z'/%3E%3C/svg%3E");
}
[data-icon="square"][color="blue"] {
  background-image: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='blue' d='M0 0h50v50H0z'/%3E%3C/svg%3E");
}
</style>
<ul>
  <li><i data-icon="square"></i> red size is1emThe square </li>
  <li><i data-icon="square" size="24" color="blue"></i> < p style = "max-width: 100%24The square </li>
</ul>
Copy the code

As you can see, we used CSS selectors to map two SVG ICONS with different colors to indirectly change the colors of the ICONS. Although this scheme is not perfect (a copy of XML is required), the readability is better than base64, and changing a color is very convenient.

5. SVG In JS

You can see that either inline HTML or CSS is not perfect. So we webpage three musketeers left JS only. As a matter of fact, we don’t choose JS over HTML or CSS. However, with the popularity of JAVASCRIPT frameworks such as React and Vue, JS has become our first choice.

This is where SVG inlines JS. This logic is essentially the same as inlining SVG into HTML using a template engine. However, we changed to a more advanced template engine, using JSX in React as an example.

import React from "react";
import "./styles.css";
// import ISquare from "./components/Icons/ISquare";
const ISquare = ({ size = "16", color = "red" }) = > (
  <svg width={size} height={size} viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100" height="100" fill={color} />
  </svg>
);
export default function App() {
  return (
    <ul>
      <li><ISquare />A blue square of size 24</li>
      <li><ISquare size="24" color="yellow" />Yellow size 24 square</li>
    </ul>
  );
};
Copy the code

You can see here that we define an icon component
with two properties: color and size. Once the component is defined, you can use it directly. If you want the icon to be used by other pages, you can just separate the component. And even better, you have control over all the nodes in the entire icon. You can customize any logic you want in there.

Ii. Actual body sense of technical scheme

The scheme is not good or bad, only to see whether it fits with the current scene

/ As the picture Sprite SVG (Iconfont) SVG In HTML SVG In CSS SVG In JS
advantages Primitive, simple Online editing, multi-person collaboration, color changing Convenient, color customization Convenient reuse, strong independence Easy reuse, high degree of freedom
disadvantages Request quantity, do not change color Cost is high and ICONS require extra processing Template engines are required Need to transfer format (color reuse inconvenience), management is not convenient You need a specific runtime environment

In the previous section we looked at five ways to use SVG, and in this section we’ll look at how these scenarios are actually used in a project.

1. SVG as Img & Sprite

Start with SVG as a normal image format, and the cost of getting started is minimal.

However, using only this feature of SVG vectors (zoom in and out without distortion), different colors of the same icon still require two files (consider using CSS filters to solve this problem, but it is expensive to get started). And one icon per request, which is a lot of pressure when pages are loaded with ICONS (perhaps HTTP2 will make the number of requests less of an issue).

In order to solve the number of requests we considered the picture Sprite solution. So we chose Iconfont, which works well online, acts as an icon manager, and gives designers a wySIWYG feel to the ICONS we’re using on our current project. However, incorporating Iconfont into a project can be more expensive than expected.

First, uploading ICONS in Iconfont is strictly standard. It becomes a problem who should handle the icon format. You say let the front end students handle it, and few front end students know how to handle these rules in the design tool. You say let the design students do it, and it’s like they don’t have to do it. The key is that it is impossible for us to pack the SVG used by the whole site into a large file, so there is some logic for code splitting, which you have to understand the design students, and they will reject it in their heart.

Again, when there is an icon update, we have to go through the same process of designing tools, exporting, uploading, downloading, and replacing local files. It’s also often the case that uploading to Iconfont fails and you have to go back to the design tool and do it again.

As a rule of thumb, a build tool is better suited for similar tasks. Agree on a folder format, and the SVG in that folder will be automatically packaged into a large image Sprite.

Ideal is full, reality is very skinny!

Integrating image-like processing capabilities into a build tool is also a messy business, which can greatly slow down the overall project build efficiency. Then two days go by and you probably don’t even see SVG in the project, it’s all infrastructure work.

2. SVG In HTML & CSS

Under build pressure, it might be better to use inline HTML or CSS.

Of course, of the two, inline HTML is preferred when it is possible to reuse it using a template engine. The advantage is that we can customize our SVG ICONS by passing in parameters.

Of course, both still require a process to convert SVG materials from the designer tool into a specific XML code format. If your project is relatively small, here again recommended, teacher Zhang Xinxu made SVG online compression merge tool.

One area where inline CSS is better than inline HTML, if at all, is the support for gradient ICONS. We all know that ID is unique in an HTML page. When we use SVG gradients for our SVG ICONS, we use the ID to reuse them. This makes it easy to have two different gradient ICONS with the same gradient ID name (which is dynamically generated by the design tool), causing the latter icon to use the gradient style of the previous icon. This logic does not exist in our CSS inline.

3. SVG In JS

In the React world, everything is component, everything is built.

The work of manually converting SVG to XML mentioned earlier can be done by the webpack plug-in @svgr/webpack. You can also use the NPM package SvGO in your project to compress and optimize SVG.

And then in the project, your actual experience looks like this.

As you can see here, you can change the SIZE of SVG but you don’t seem to know how to change the color of SVG ICONS.

<svg width="50" height="50" viewBox="0 0 50 to 50." " fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M50 0H0V50H50V0Z" fill="#FF0000"/>
</svg>
Copy the code

First, the
component, which is directly exposed to the SVG layer, has a path that corresponds to its internal components. To change the color of the path, we can only do it in a roundabout way with CSS.

svg{
 stroke-width: 0;
 stroke: currentColor;
 fill: currentColor;
}
svg path[fill] {
 fill: currentColor;
 fill-opacity: 1;
}
svg path[stroke] {
 stroke: currentColor;
 stroke-opacity: 1;
}
Copy the code

The core of this style is currentColor, which allows SVG’s internal path fill and stroke to inherit SVG color.

import React from "react";
import "./style.css";
const Icon = ({ size = 16, Svg, ... otherProps}) = > (
  <Svg width={size} height={size} {. otherProps} / >
);
export default Icon;
Copy the code

We then wrapped this logic into another component called
, where we replaced width and height with size to reduce the number of interfaces exposed.

This leaves us with the present notation (we can also condense the color property inside the
component, in this case to reduce the logical complexity of the code presentation).

Logically, the extra
encapsulation here would be unnecessary if the logic to change the size and color could be implemented in @svgr/webpack.

SVG In React Delivery best practices

In the last few sections, we’ve been going around in this little circle of how to optimize your logic. In practice, there is another problem that affects the experience even moreSVG Management delivery.

As mentioned earlier, Iconfont is an icon SpriteThe code segmentIt is difficult to. We usually pack the ICONS that are used globally into an SVG Sprite, and then pack the rest separately by page. The problem is that one page is unique and only uses one of the global Sprite SVG images. What do you do? Or if page A and page B share certain ICONS, what do you do? And our logic, design students may not perceive it at all.

With the exception of SVG In CSS, for SVG In Html and SVG In JS, you can put each icon file In a single folder (./components/Icons/*) and then load the references as needed without the problem of group management. Yet it was all too simple.

For example, in one iteration we needed A “like” icon, student A exported the icon and named it good.svg, and student B found that he also needed the icon, but he didn’t find like.svg in the ICONS folder, so he exported an icon named like.svg.

As the project progressed, another stroke version of the icon, good-outline.svg, was created. Then, two days later, a new designer was added to create a version of gradient.svg, like-gradient.svg.

After the boss saw the whole website said, why this site with a thumbs-up icon and so much style, give me a unified style. Then the designer came up with a new versiongood-new.svgLet you do global substitution. Now I think you’re in the loop. Because you don’t know which corner of the page these ICONS are on, and they have different names, you’re afraid to delete them and you’re afraid to ask.

The reason for this is that developers and design students are maintaining the same set of design resources. And the management styles at both ends may be inconsistent. As developers, we naturally think, since the design students already have a management plan? Can we just take it and use it?

This conundrum became a reality when I saw this article using Figma + GitHub Actions to complete the fully automated delivery of SVG ICONS (a Call for the original author).

For a brief introduction, designers just need to edit and modify the icon in Figma (design tool), click the Update button, and then front-end NPM install will do everything. The previous tedious management and build in the use phase do not need to care about all (overall time delay, about 2-3 minutes).

In particular, we can take over the whole process from Figma SVG to NPM in github warehouse, that is to say, we can customize any logic we want based on the actual project. Here’s a look at the React version modelled on our team’s tonality:

  1. Simplified the style of the final generated component;
  2. [Fixed] ICONS that start with an underscore are ignored and will not be published in NPM.
  3. Only the last icon with the same file name will be selected.
  4. The generated React Component names will always be uppercaseIAt the beginning, like<ICamera />;
  5. Components are generated in alphabetical order (easier to find);
  6. The original author used Github Pages to display the icon. For higher degree of freedom, we replaced it with CodesandBox to display the icon.

If you want the same mod version, you can Fork webNovel – ICONS here

As you can see, there are 183 ICONS in the entire site, and you can also modify the size, color, and background color of the ICONS in the display interface. If you want to show the same Demo, you can directly click the link Edit on CodeSandBoxFork to use.

The most pleasant thing about all this is that the front end students do not need to maintain this set of ICONS, the design students can help us directly. All we need to do is install NPM when ICONS are updated.

SVG In React uses best practices

After this operation, we will be the icon management directly transferred to the design students, then we only need to solve the problem of icon use.

As you can see here we are compatible with @svgr/webpack and WebNovel – ICONS.

In our project we actually manage the colors through CSS as our Token. The React Component does not expose a color like property to change colors. This can be customized based on your actual project.

.icon {
  display: inline-block;
  vertical-align: middle;
}
.icon:not(._self_color) {
  stroke-width: 0;
  stroke: currentColor;
  fill: currentColor;
}
.icon:not(._self_color) path[fill] {
  fill: currentColor;
  fill-opacity: 1;
}
.icon:not(._self_color) path[stroke] {
  stroke: currentColor;
  stroke-opacity: 1;
}
Copy the code

In order to be compatible with multi-color ICONS, we also expose an additional property isSelfColor using CSS selectors to decide whether to remove the default color of our ICONS. In our project, monochrome ICONS are used more often than multicolor ICONS, so we default to monochrome ICONS. In this way, we have solved several major problems with SVG fairly completely.

  1. SVG management
  2. SVG compression, optimization
  3. SVG turn React Component
  4. SVG customizes the size and changes the color
  5. Multi-color icon support
  6. Other customized requirements

Another point that needs to be specifically mentioned here is that although both @svgr/webpack and WebNovel-icons can achieve SVG compression and optimization, their time points are different. @svgr/webpack is handled in real time before the Webpack, whereas WebNovel-icons are handled before they become the React Component.

5. Some pitfalls of SVG

1. The deformation of SVG

When using some circular ICONS, you will find that the icon is round in the design, but not in the browser. This is usually the case because the path path in our icon is not an integer. When this happens, ask the designer to change it to an integer. But this is a probability, can only be said to try, fail to continue to change (this problem is actually a bit of a mystery).

This is probably due to the compression tool. When the SVG native size is small, the value might be 1.233458. In this case, the compression tool will take the appropriate decimal place and the result will be distorted details. This problem is less likely if SVG has a large original size, such as iconfont.cn, where ICONS are more than 200.

2. The SVG event is not triggered

In some browsers, the onClick event does not fire if you bind it directly to an SVG component. The logic we suggest here is to add an < I /> tag or a tag to the < SVG /> tag. This event is then bound to the outer container.

3. The color of SVG is only half changed

The problem is that in an SVG icon, there are two types of path, fill and stroke, which is recommended to make the icon outline stroke and then Flatten in the design tool. This may be different design tools called different, you can consult a designer.

4. SVG edges are cut off

The problem is that the SVG edges provided by the design students suggest leaving at least one pixel between the SVG icon and the container.

End

So far we have covered various poses for using SVG ICONS in projects large and small. I hope I can help you as much as possible, so the volume is a little bigger. If there is any missing or you have a better plan, you are also welcome to leave a message to me, exchange.

Of course, SVG has more advantages than that, especially in terms of some animation capabilities that are particularly convenient and excellent. This is also highly recommended.