⬆️ ⬇️

SVG icons - a lot and with style



A little story about how our team decided to organize the icons in the upcoming project. A bit of historical excursion, views on the sides (on PNG and vector fonts) and the story of how we finally settled in the end.



The icons are used here, and actively - a well-chosen icon replaces words and sentences (and you can make a pop-up hint with a suited icon, but let's not talk about sad things)



In general, there are (and continue to create) icons. It is necessary to put them on a web page. We need to do this so that then the head does not hurt about the rest of the project and a couple of years in support. Well, there are additional Wishlist:



There are factors that facilitate the task. Icons now (2015, autumn, it starts to snow) are flat, strict in fashion. If five years ago, the icons were full, now it has gone under the influence of MC, Epple, Design Material ...

')

tl; dr Warning. The next few sections are the blurring of a mouse on a tree, and breadth, a review of solutions (including unsuccessful ones) and a cat in different angles.

Who wants the technical details of what happened in the end - welcome here .



Than classical solutions did not satisfy







And let's put the SVG in the house?



Of course, we can do it. Copy each icon and paste it where it will be needed into each piece of HTML markup.



Kit Code


<?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"> <!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ --> <ellipse class="face" ry="55" rx="55" cy="120.5" cx="154.5" stroke-width="1.5" stroke="#000" fill="#fff" /> <ellipse class="ear" ry="21.5" rx="11" cy="58" cx="116.5" stroke-width="1.5" stroke="#000" fill="#fff" /> <ellipse class="ear" ry="22.5" rx="5.5" cy="53" cx="189" stroke-width="1.5" stroke="#000" fill="#fff" /> <g class="whiskers"> <line y2="90.5" x2="288.5" y1="115.5" x1="186.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="134.5" x2="193.5" y1="139.5" x1="304.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="146.5" x2="192.5" y1="167.5" x1="302.5" stroke-width="1.5" stroke="#000" fill="none" /> </g> <g class="whiskers" transform="rotate(-185 70.50000000000001,139.00000000000003) "> <line y2="100.5" x2="113.5" y1="125.5" x1="11.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="144.5" x2="18.5" y1="149.5" x1="129.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="156.5" x2="17.5" y1="177.5" x1="127.5" stroke-width="1.5" stroke="#000" fill="none" /> </g> <ellipse fill="#fff" stroke="black" class="body" ry="55.5" rx="107.5" cy="221" cx="248" /> <ellipse fill="#fff" stroke="black" class="tail" ry="76" rx="8.5" cy="128.5" cx="353" /> <g class="legs" fill="darkgray"> <ellipse ry="54.5" rx="7.5" cy="290" cx="153" /> <ellipse ry="58" rx="9.5" cy="309.5" cx="190" /> <ellipse ry="48" rx="10" cy="291.5" cx="311.5" /> <ellipse ry="42.5" rx="8.5" cy="269" cx="342" /> </g> <circle class="eye" r="8" cx="134.5" cy="94.5" fill="darkgreen"/> <circle class="eye" r="8" cx="171.5" cy="94.5" fill="darkgreen"/> <ellipse class="nose" ry="5.5" rx="5.5" cy="118" cx="153" fill="grey" /> <g class="checkmark" visibility="hidden"> <line y2="250" x2="270" y1="194.5" x1="234.5" stroke-width="3" stroke="#000" fill="none"/> <line y2="250" x2="270" y1="170.5" x1="314.5" stroke-width="3" stroke="#000" fill="none"/> </g> </svg> 


The cat itself is here .

That is, this is all proposed to put inside the document.



And if it changes, then skip to all places of use.

Or try to write for our project a highly specialized solution, which during assembly, or during deployment, or during execution, will understand by magic attributes that there should be an icon, and inject (inject, I don’t know how to translate) the contents of one file inside the contents of another file.

It sounds very fun and very annoying in support.



Unfortunately or fortunately, we in DevExpress this way is not suitable by definition. We do not write (almost) final software solutions, we write what other people will use in their decisions.

Having imagined the faces of these people, whom we would ask to inject our SVGs onto their pages with pens, we abruptly moved to the next possible solution ...



And if you put in the DOM, but a little bit, and better - automatically?



Well, that is, to connect to our document some kind of storage, an analogue of the sprite with icons, in which all the icons would lie.



And where they are needed, we would say - but give us, dear browser, the icon of kotik!



Yes, you can do it, and people do it. We collect all our icons by file and put them all inside one big SVG sprite, which contains only templates of icons. Technically, the symbol element is used for this.

Pro character
This element is intended as a template. Very self-sufficient, in terms of capabilities, almost like a small svg-file. Allows you to define your conditional "dimensions" - the viewBox, to which the coordinates of the elements will be applied. That is, we will completely leave the problem of comparing our sizes with the size of the icon, which is a plus. A little bit of the details . Now supported out of the box with builds for gulp / grunt .



Symbolic cat
The result of wrapping the cat in a symbol with the plugin gulp-svgstore . Actually, almost nothing has changed.

 <svg xmlns="http://www.w3.org/2000/svg"> <symbol id="kotik" viewBox="0 0 400 400"> <ellipse class="face" ry="55" rx="55" cy="120.5" cx="154.5" stroke-width="1.5" stroke="#000" fill="#fff" /> <ellipse class="ear" ry="21.5" rx="11" cy="58" cx="116.5" stroke-width="1.5" stroke="#000" fill="#fff" /> <ellipse class="ear" ry="22.5" rx="5.5" cy="53" cx="189" stroke-width="1.5" stroke="#000" fill="#fff" /> <g class="whiskers"> <line y2="90.5" x2="288.5" y1="115.5" x1="186.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="134.5" x2="193.5" y1="139.5" x1="304.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="146.5" x2="192.5" y1="167.5" x1="302.5" stroke-width="1.5" stroke="#000" fill="none" /> </g> <g class="whiskers" transform="rotate(-185 70.50000000000001,139.00000000000003) "> <line y2="100.5" x2="113.5" y1="125.5" x1="11.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="144.5" x2="18.5" y1="149.5" x1="129.5" stroke-width="1.5" stroke="#000" fill="none" /> <line y2="156.5" x2="17.5" y1="177.5" x1="127.5" stroke-width="1.5" stroke="#000" fill="none" /> </g> <ellipse fill="#fff" stroke="black" class="body" ry="55.5" rx="107.5" cy="221" cx="248" /> <ellipse fill="#fff" stroke="black" class="tail" ry="76" rx="8.5" cy="128.5" cx="353" /> <g class="legs" fill="darkgray"> <ellipse ry="54.5" rx="7.5" cy="290" cx="153" /> <ellipse ry="58" rx="9.5" cy="309.5" cx="190" /> <ellipse ry="48" rx="10" cy="291.5" cx="311.5" /> <ellipse ry="42.5" rx="8.5" cy="269" cx="342" /> </g> <circle class="eye" r="8" cx="134.5" cy="94.5" fill="darkgreen" /> <circle class="eye" r="8" cx="171.5" cy="94.5" fill="darkgreen" /> <ellipse class="nose" ry="5.5" rx="5.5" cy="118" cx="153" fill="grey" /> <g class="checkmark" visibility="hidden"> <line y2="250" x2="270" y1="194.5" x1="234.5" stroke-width="3" stroke="#000" fill="none" /> <line y2="250" x2="270" y1="170.5" x1="314.5" stroke-width="3" stroke="#000" fill="none" /> </g> </symbol> <symbol id="shapes" viewBox="0 0 400 400"> <circle fill="green" cx="200" cy="200" r="30" /> <g fill="darkblue"> <circle cx="100" cy="100" r="25" /> <circle cx="300" cy="100" r="25" /> </g> <g fill="orangered"> <ellipse fill="violet" cx="200" cy="300" rx="200" ry="25" /> </g> </symbol> </svg> 




This element is not displayed anywhere - by design. He is just a mask for future real icons.

We can take this template and put it on the page, referring to it from the use element.

 <svg> <use xlink:href="#kotik" /> </svg> 


Everything, cat here.



Whitetail, ordinary.



And we can also make it more interesting. Template - he is already at home. In sense in DOM. And it can already be stylized quite as real. Using the names of the svg elements ( path , circle , rect , etc.), we can apply CSS rules to them and modify attributes (colors through fill and stroke , thickness and line style)

 .tail { color: orange; } 


And now all the cats that link to this template will become orange-tailed.







So, our last method has already given us two of the three points of our desires.

But when I tried to stil one particular icon, I was at first disappointed.



Surprise to use xlink: href and trees together



As soon as we try to customize one taken cat in the forehead - everything stops working.

 <svg id="barsik"> <use xlink:href="#kotik"/> </svg> 


 #barsik .tail { fill: orangered; } 


Alas, the tail of Barsik is not red.

The reason for this is interesting. Barsika is actually not there.

Barsik - in the shade.



HOUSE OF SHADOWS



Shadow DOM - the thing is no longer new. Browser manufacturers began to use it in order to blind input type = datebox, and we didn’t know about it. At that moment, they were not yet aware that they were using the Shadow DOM, he acquired the name and form a bit later ...



The use element - in modern terms - uses precisely that Shadow DOM.



Elements that we * clone * inside * of the root * use are placed in our DOM ... but not completely.

In particular, CSS rules cannot be applied to them.



But the root of the shadow tree , the <use /> element, is like a BE on the one hand in our main tree, and on the other it is the ancestor of everything in the tree.

From the first side we will apply the CSS style to it.

On the other hand, he will forward the CSS properties attached to him to his descendants. If we tell the template to listen to it.

 //    ,          .tail { fill: inherit; } //  #barsik use { fill: orangered; } 


So Barsik gets orange color, and Vaska - smoky white.



(unless the parts and elements of his feline SVG body indicate otherwise. The priority of inherited CSS properties is quite low, lower than attributes and certainly lower than other rules applied to the template - and the template lives completely in the DOM, without any reservations. Details below )

And then we can already use any variations.

 .cat-house:hover #barsik use { fill: red; } 


Thus, we can customize one color completely freely and in full accordance with the letter CSS. Implementing the backlight when hovering becomes easy .









Order of applying styles, properties and attributes



At this moment, with the habit of starting to become incomprehensible, so I will try to paint again.

For me it was a small stumbling block.

Approach the first, without CSS


An SVG element may have an attribute indicating its color. For most shapes (path, circle, ellipsis), this is fill, stroke is less commonly used (to indicate the color of the borders of the shape).

 <circle fill="green" cx="200" cy="200" r="30"></circle> 


If the element of this attribute is not - he tries to get it from ancestors. Going up through their parents until they find someone with the specified attribute.

 <g fill="darkblue"> <circle cx="100" cy="100" r="25"></circle> <circle cx="300" cy="100" r="25"></circle> </g> 


Two circles, the fill is not specified, taken from the parent. Very well - the first parent, the group in which they lie, has a fill. Both circles turn blue.

Approach the second. The appearance of stylization


As soon as we apply styles, they win. Rule

 circle { fill: orange; } 


Make both circles orange. It is just stronger ...

Approach the third. Styling kills attributes so elements use attributes.



 <g fill="orangered"> <ellipse fill="violet" cx="200" cy="300" rx="200" ry="25"/> </g> 


This code will give us a purple ellipse.

However, adding CSS rules

 ellipse { fill: inherit; } 


Make him forget his own color and start taking it from his ancestors.

This is what the whole example looks like. Any matches are random.



The ellipse will turn orange.



In general, most of the examples are based on this trick.

There may still be inline-styles and! Important, but there everything is already going by analogy



Well, a little more magic



Stylization of the second color



With the help of a hack -off based on the SVG currentColor variable, we can customize two colors already:

 .tail { fill: inherit; } .body { fill: currentColor; } svg use { fill: brown; color: orange; } svg:hover use { fill: orange; color: brown; } 




Something like this.



Invisible Cat Trick



Another minor thing that, in principle, can be useful once is to hide the elements of the image under certain conditions.



I did not manage to achieve this directly - with the visibility option like this, all or nothing ...

But I managed, using the same colors, to paint the element in a transparent color. Very beautiful, the main thing - to choose the right shade.







Technical stuff



The SVG sprite must be in the DOMe. Most browsers would be able to show templates from a linked file, but not IE. Therefore - pumped through AJAX and inserted into the house. There is an article .



Template engines can work strangely. The xlink: href attribute lives in its namespace (actually, in the xlink namespace, it is written there), and not everyone loves it. For example, Knockout is not able to bind this out of the box. There is a workout . He works .



I can assume that similar problems may arise in other template engines. I can assume that they can be solved in a similar way.



What happened in the end





The solution turned out to be unrelated to the specificity of the build, well-styled.



Works in IE9 +, webkits, on the Amazon Kindle reader and on the Samsung TV.



All examples of styling SVG-icons are on Gietgab . I gave links to the GitHub Pages of this repository .

I hope someone interested in this story.



UPD By the results of the question added in the comments one more page showing the styling of 122 real icons , only 500 copies per page

The icons for this example are taken at www.flaticon.com



Thanks



When preparing a blog post, no animals were injured.

Kotik, originally raster , was transferred to the SVG-terms in the online editor ( source ).



I got the skill of drawing cats by drawing cats to my son, who was extremely pleased with them.

I refuse to accept claims about the asymmetry of the ears.



Bibliography



Very, very, very detailed story about the styling of the shadow SVG

About SVG icons in principle , as well as why a symbol is better than a group

History of a theme of icons on Habré - SVG, Iconfonts vs PNG

SVG icons - different approaches , also with cats

How to load a SVG sprite into the DOM

SVG drawing library charts . She has nothing to do with icons, but there are also cats, including my cat ( who helped me write articles and served as a model for drawing ).

Source: https://habr.com/ru/post/269331/



All Articles