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:
- I want a vector. Well, okay, vector is a means, not a goal. The goal is not to worry ALL about resizing, retina displays, saving images in different formats for different purposes.
- I want styling icons. Because we have at least two sets of themes out of the box (light and dark), or even a contrast, for people with unusual eyesight, or some orange one will appear closer to the New Year ... In general, the same thing The icon should look slightly different depending on the theme selected on the page.
- I want a dynamic styling of icons. Statics are not enough for us. This is enough for screenshots and advertising booklets, but not for live users. And we wanted a life! We wanted a hover! We wanted selections !!! And disabuse, disagree them all! .. Sorry.
- I do not want JavaScript to participate in this in any form or manifestation. Icons are an appearance, and for it responsible HTML + CSS. Well, okay, the class selected, I am ready to hang on the elements, but this is the last border ...
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
- We can make a cloud of png-icons and put them inside the tags image. And to replace mouse-pointing on JS-events. When I made the site in the third year, this method really worked. It was good, and it was not necessary to take care of the many connections to the server. Maybe when the circle closes and HTTP 2.0 wins ... but for now it is expensive. Let's go further.
- PNG sprites + CSS / background-image - good, but not enough. Our colleagues from DevExtreme lived like this for a while ... but they rested on the need for at least some styling. After all, with the PNG-icon of trouble, you can not even paint it in red on the client ! They switched to Font Icons, and we? ..
- Font Icons for writing an application (not a large library, namely, an attachment) turned out to be slightly inconvenient in work. Icon changes require some maintenance (collecting icons, saving to a font file, hinting all sorts ...) If the Internet already has all the icons you need as part of Font Awesome - it’s better not to look for an option. But if the icons need their own ... we have so far gone further.
- Unicode characters for icons. He himself joked, he laughed himself.
Although...although I can not help but note that I love Pts to use them in development, prior to design and release. Quick, easy, Ctrl + C, Ctrl + V, font-size, color,: hover, .selected {color:} - and here you have a beautiful icon with hover and selections for free, without SMS ...
- SVG + CSS / background-image - we have normal scaling. We do not have styling icons directly. No, we can turn it around - the hover state is in principle done by changing the background color, and the disabled state is to some extent by changing the opacity. This is a working version, this was our first repository-loaded version. But we cannot stylize the drawing itself. Because he is not in DOMe. And when there is nothing in the house, it is a disaster ...
To what is not part of the document, you will not apply CSS styles, you will not tint, you will not change.
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"> <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 characterThis 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 catThe 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
- Our icons are stored and stored in separate SVG files, small ones, loved in VCS, understandable in diffs and opened in the browser
- Our icons at the time of build are collected into one large file - icons.svg. What was a file becomes a template.
- This file should be put inside the HTML markup. With your hands, build tool, or javascript
- Icons can be referenced using this design:
<svg> <use xlink:href="#kotik"/> </svg>
The design is more explicit and more semantically correct than when creating an icon using background-image
- The icon template is inside the DOM and can be modified via CSS.
path.tail { fill: darkgrey; }
- A specific icon is made on the basis of a template, it does not fall into the DOM itself, but it falls into the shadow DOM and it can be styled by inheriting the CSS properties from the parent element anchor anchor use.
#dvorovayBreed.selected use { fill: darkgreen; }
- The icon can be stylized as you like at the document level - you can set classes for internal elements of the SVG and paint / modify the whole document as you please and as CSS allows
- For one particular icon, you can modify two colors - exactly two. One - in a civilized way, the second - thanks to magic. Magic is very strong and works everywhere, but magic has its price - be careful in production!
- JavaScript is needed a maximum of once, during the life of the page is no longer used
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 ).