Pliki SVG (Scalable Vector Graphics) w dobie wszechobecnych smartfonów i innych urządzeń o ekranach z wysokim ppi powinny być standardem, ale nadal ze świecą szukać przykładów ich zastosowania w komercyjnych produktach. Po części jest to wina mało świadomych deweloperów, nadal bardzo popularny jest mit o słabym wsparciu dla SVG. Jeżeli zależy nam na wsparciu IE8 nic(?) nie stoi na przeszkodzie by zainteresować się np. SVGeezy.
Z mojego doświadczenia wynika, że plik SVG, w zależności od tego jak bardzo jest złożony, może być zawsze zmniejszony o kilkadziesiąt procent. Dla ikony złożonej z 5-6 elementów jest to nawet 60-70%. Jak to możliwe?
(Nie)czysty SVG
Winna leży po stronie edytorów. Za przykład weźmy opensourcowy Inkscape i logo WEBroad. Ikona 60×64 w formacie Inkscape SVG to 3 850b.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg3054" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="Nowy dokument 6"> <defs id="defs3056" /> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="11" inkscape:cx="42.030106" inkscape:cy="31.8742" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="1920" inkscape:window-height="1057" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" /> <metadata id="metadata3059"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> <g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer"> <path style="fill:#d70000;fill-opacity:1;fill-rule:evenodd;stroke:none" d="M 2.1469587,19.144324 C 2.7477757,10.064402 40.327302,-1.025797 46.893937,2.76281 c 6.93892,5.073804 18.16498,36.910875 14.32665,44.200722 -4.4077,8.288616 -39.727128,18.061036 -44.431678,14.14586 C 11.651025,57.672471 0.60066671,28.805927 2.1469587,19.144324 z" id="rect3003" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> <path style="fill:#eca702;fill-opacity:1;fill-rule:evenodd;stroke:none" d="M 7.5618827,16.138311 C 8.7573597,9.826203 35.691092,6.488753 39.970685,9.714543 c 4.311072,3.236788 8.631942,27.022469 5.319912,31.79869 -2.5923,5.18506 -29.120743,8.356652 -32.084354,5.203852 C 9.8981077,43.861842 5.6540957,22.775996 7.5618827,16.138311 z" id="rect3003-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> <path style="fill:#fff600;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 12.154016,15.047001 c 1.546443,-3.897751 19.269113,-3.64943 21.615229,-1.042245 2.327917,3.224683 3.085727,18.458081 0.371593,21.104558 -3.105071,3.002803 -19.631471,2.67902 -21.142643,0.284206 -1.768887,-2.247307 -2.887667,-16.329572 -0.844179,-20.346519 z" id="rect3003-4" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> <path style="fill:#fffcb2;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 20.268697,14.869558 c 0.940881,-2.371453 11.613036,-1.927403 13.040449,-0.341156 1.416346,1.961955 1.401857,11.219206 -0.249464,12.829367 -1.889183,1.826956 -11.800652,1.082429 -12.720083,-0.374616 -1.076223,-1.367296 -1.314195,-9.669619 -0.0709,-12.1136 z" id="rect3003-0" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" /> <path style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 20.360518,18.993825 c 0.702033,-1.378086 6.496464,-0.941347 7.288573,-0.0914 0.789611,1.054615 0.760123,6.163816 -0.123789,7.056318 -1.011375,1.012818 -6.596724,0.698008 -7.111029,-0.08647 -0.598837,-0.734112 -0.707659,-5.535884 -0.05376,-6.878451 z" id="rect3003-9" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" /> </g> </svg> |
Inkscape umożliwia również zapis do czystego SVG. Rozmiar takiego pliku to już 2 663b. Niby lepiej, ale jak podejrzymy źródło zobaczymy wiele zbędnego kodu. Jak się okazuje „czysty” to pojęcie względne.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3054"> <defs id="defs3056" /> <metadata id="metadata3059"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> <g id="layer1"> <path d="M 2.1469587,19.144324 C 2.7477757,10.064402 40.327302,-1.025797 46.893937,2.76281 c 6.93892,5.073804 18.16498,36.910875 14.32665,44.200722 -4.4077,8.288616 -39.727128,18.061036 -44.431678,14.14586 C 11.651025,57.672471 0.60066671,28.805927 2.1469587,19.144324 z" id="rect3003" style="fill:#d70000;fill-opacity:1;fill-rule:evenodd;stroke:none" /> <path d="M 7.5618827,16.138311 C 8.7573597,9.826203 35.691092,6.488753 39.970685,9.714543 c 4.311072,3.236788 8.631942,27.022469 5.319912,31.79869 -2.5923,5.18506 -29.120743,8.356652 -32.084354,5.203852 C 9.8981077,43.861842 5.6540957,22.775996 7.5618827,16.138311 z" id="rect3003-7" style="fill:#eca702;fill-opacity:1;fill-rule:evenodd;stroke:none" /> <path d="m 12.154016,15.047001 c 1.546443,-3.897751 19.269113,-3.64943 21.615229,-1.042245 2.327917,3.224683 3.085727,18.458081 0.371593,21.104558 -3.105071,3.002803 -19.631471,2.67902 -21.142643,0.284206 -1.768887,-2.247307 -2.887667,-16.329572 -0.844179,-20.346519 z" id="rect3003-4" style="fill:#fff600;fill-opacity:1;fill-rule:evenodd;stroke:none" /> <path d="m 20.268697,14.869558 c 0.940881,-2.371453 11.613036,-1.927403 13.040449,-0.341156 1.416346,1.961955 1.401857,11.219206 -0.249464,12.829367 -1.889183,1.826956 -11.800652,1.082429 -12.720083,-0.374616 -1.076223,-1.367296 -1.314195,-9.669619 -0.0709,-12.1136 z" id="rect3003-0" style="fill:#fffcb2;fill-opacity:1;fill-rule:evenodd;stroke:none" /> <path d="m 20.360518,18.993825 c 0.702033,-1.378086 6.496464,-0.941347 7.288573,-0.0914 0.789611,1.054615 0.760123,6.163816 -0.123789,7.056318 -1.011375,1.012818 -6.596724,0.698008 -7.111029,-0.08647 -0.598837,-0.734112 -0.707659,-5.535884 -0.05376,-6.878451 z" id="rect3003-9" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> </g> </svg> |
Pierwszą czynnością jaką możemy zrobić to ręcznie wyczyścić taki kod. Wymagany jest jedynie atrybut xmlns dla elementu svg oraz przydatne będą również jego rozmiary oraz opcjonalnie viewBox. Istnieją jednak narzędzia, które oferują automatyczne optymalizowanie jednego lub wielu plików.
SVGO
SVGO to proste i co najważniejsze skuteczne narzędzie obsługiwane z poziomu konsoli, oparte na Node.js. Instalacja i sposób korzystania z narzędzia jest opisany w repozytorium projektu, przejdźmy do efektów.
Zoptymalizowane za pomocą SVGO logo WEBroad to już tylko 1 022b. Prawie 4-krotnie mniej niż pierwotnie! Kod taki jest jednak uciążliwy przy dalszej pracy np. podczas animacji na poszczególnych ścieżkach.
1 | <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><g fill-rule="evenodd"><path d="M2.147 19.144c.601-9.08 38.18-20.17 44.747-16.382 6.939 5.074 18.165 36.911 14.327 44.201-4.408 8.289-39.727 18.061-44.432 14.146-5.138-3.437-16.188-32.303-14.642-41.965z" fill="#d70000"/><path d="M7.562 16.138c1.195-6.312 28.129-9.65 32.409-6.424 4.311 3.237 8.632 27.022 5.32 31.799-2.592 5.185-29.121 8.357-32.084 5.204-3.308-2.855-7.552-23.941-5.644-30.579z" fill="#eca702"/><path d="M12.154 15.047c1.546-3.898 19.269-3.649 21.615-1.042 2.328 3.225 3.086 18.458.372 21.105-3.105 3.003-19.631 2.679-21.143.284-1.769-2.247-2.888-16.33-.844-20.347z" fill="#fff600"/><path d="M20.269 14.87c.941-2.371 11.613-1.927 13.04-.341 1.416 1.962 1.402 11.219-.249 12.829-1.889 1.827-11.801 1.082-12.72-.375-1.076-1.367-1.314-9.67-.071-12.114z" fill="#fffcb2"/><path d="M20.361 18.994c.702-1.378 6.496-.941 7.289-.091.79 1.055.76 6.164-.124 7.056-1.011 1.013-6.597.698-7.111-.086-.599-.734-.708-5.536-.054-6.878z" fill="#fff"/></g></svg> |
Korzystając z opcji --pretty możemy wygenerować „ładnie” sformatowany plik o niewiele większym rozmiarze 1 079b.
1 2 3 4 5 6 7 8 9 | <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"> <g fill-rule="evenodd"> <path d="M2.147 19.144c.601-9.08 38.18-20.17 44.747-16.382 6.939 5.074 18.165 36.911 14.327 44.201-4.408 8.289-39.727 18.061-44.432 14.146-5.138-3.437-16.188-32.303-14.642-41.965z" fill="#d70000"/> <path d="M7.562 16.138c1.195-6.312 28.129-9.65 32.409-6.424 4.311 3.237 8.632 27.022 5.32 31.799-2.592 5.185-29.121 8.357-32.084 5.204-3.308-2.855-7.552-23.941-5.644-30.579z" fill="#eca702"/> <path d="M12.154 15.047c1.546-3.898 19.269-3.649 21.615-1.042 2.328 3.225 3.086 18.458.372 21.105-3.105 3.003-19.631 2.679-21.143.284-1.769-2.247-2.888-16.33-.844-20.347z" fill="#fff600"/> <path d="M20.269 14.87c.941-2.371 11.613-1.927 13.04-.341 1.416 1.962 1.402 11.219-.249 12.829-1.889 1.827-11.801 1.082-12.72-.375-1.076-1.367-1.314-9.67-.071-12.114z" fill="#fffcb2"/> <path d="M20.361 18.994c.702-1.378 6.496-.941 7.289-.091.79 1.055.76 6.164-.124 7.056-1.011 1.013-6.597.698-7.111-.086-.599-.734-.708-5.536-.054-6.878z" fill="#fff"/> </g> </svg> |
Iconizr
Iconizr to bardziej rozbudowane narzędzie pozwalające m. in. na łączenie plików svg i zmniejszenie w ten sposób ilości zapytań do serwera. Iconizr napisany został w PHP i poza dostępem z konsoli oferuje możliwość optymalizacji plików SVG z poziomu przeglądarki. Poza samym plikiem SVG otrzymujemy również kod CSS/SCSS. Efekt jest co najmniej zadowalający.
Plik SVG:
1 2 3 | <?xml version="1.0"?> <!--Icons from directory ""--> <svg xmlns="http://www.w3.org/2000/svg" width="64" height="192" viewBox="0 0 64 192"><svg width="64" height="64" id="webroad_blue" y="0"><g fill-rule="evenodd"><path d="m2.147 19.144c0.601-9.08 38.18-20.17 44.747-16.382 6.939 5.074 18.165 36.911 14.327 44.201-4.408 8.289-39.727 18.061-44.432 14.146-5.138-3.437-16.188-32.303-14.642-41.965z" fill="#00f"/><path d="m7.562 16.138c1.195-6.312 28.129-9.65 32.409-6.424 4.311 3.237 8.632 27.022 5.32 31.799-2.592 5.185-29.121 8.357-32.084 5.204-3.308-2.855-7.552-23.941-5.644-30.579z" fill="#005dff"/><path d="m12.154 15.047c1.546-3.898 19.269-3.649 21.615-1.042 2.328 3.225 3.086 18.458 0.372 21.105-3.105 3.003-19.631 2.679-21.143 0.284-1.769-2.247-2.888-16.33-0.844-20.347z" fill="#00beff"/><path d="m20.269 14.87c0.941-2.371 11.613-1.927 13.04-0.341 1.416 1.962 1.402 11.219-0.249 12.829-1.889 1.827-11.801 1.082-12.72-0.375-1.076-1.367-1.314-9.67-0.071-12.114z" fill="#00efff"/><path d="m20.361 18.994c0.702-1.378 6.496-0.941 7.289-0.091 0.79 1.055 0.76 6.164-0.124 7.056-1.011 1.013-6.597 0.698-7.111-0.086-0.599-0.734-0.708-5.536-0.054-6.878z" fill="#fff"/></g></svg><svg width="64" height="64" id="webroad_green" y="64"><g fill-rule="evenodd"><path d="m2.147 19.144c0.601-9.08 38.18-20.17 44.747-16.382 6.939 5.074 18.165 36.911 14.327 44.201-4.408 8.289-39.727 18.061-44.432 14.146-5.138-3.437-16.188-32.303-14.642-41.965z" fill="#008f00"/><path d="m7.562 16.138c1.195-6.312 28.129-9.65 32.409-6.424 4.311 3.237 8.632 27.022 5.32 31.799-2.592 5.185-29.121 8.357-32.084 5.204-3.308-2.855-7.552-23.941-5.644-30.579z" fill="#00af00"/><path d="m12.154 15.047c1.546-3.898 19.269-3.649 21.615-1.042 2.328 3.225 3.086 18.458 0.372 21.105-3.105 3.003-19.631 2.679-21.143 0.284-1.769-2.247-2.888-16.33-0.844-20.347z" fill="#00d600"/><path d="m20.269 14.87c0.941-2.371 11.613-1.927 13.04-0.341 1.416 1.962 1.402 11.219-0.249 12.829-1.889 1.827-11.801 1.082-12.72-0.375-1.076-1.367-1.314-9.67-0.071-12.114z" fill="#0f0"/><path d="m20.361 18.994c0.702-1.378 6.496-0.941 7.289-0.091 0.79 1.055 0.76 6.164-0.124 7.056-1.011 1.013-6.597 0.698-7.111-0.086-0.599-0.734-0.708-5.536-0.054-6.878z" fill="#fff"/></g></svg><svg width="64" height="64" id="webroad_red" y="128"><g fill-rule="evenodd"><path d="m2.147 19.144c0.601-9.08 38.18-20.17 44.747-16.382 6.939 5.074 18.165 36.911 14.327 44.201-4.408 8.289-39.727 18.061-44.432 14.146-5.138-3.437-16.188-32.303-14.642-41.965z" fill="#d70000"/><path d="m7.562 16.138c1.195-6.312 28.129-9.65 32.409-6.424 4.311 3.237 8.632 27.022 5.32 31.799-2.592 5.185-29.121 8.357-32.084 5.204-3.308-2.855-7.552-23.941-5.644-30.579z" fill="#eca702"/><path d="m12.154 15.047c1.546-3.898 19.269-3.649 21.615-1.042 2.328 3.225 3.086 18.458 0.372 21.105-3.105 3.003-19.631 2.679-21.143 0.284-1.769-2.247-2.888-16.33-0.844-20.347z" fill="#fff600"/><path d="m20.269 14.87c0.941-2.371 11.613-1.927 13.04-0.341 1.416 1.962 1.402 11.219-0.249 12.829-1.889 1.827-11.801 1.082-12.72-0.375-1.076-1.367-1.314-9.67-0.071-12.114z" fill="#fffcb2"/><path d="m20.361 18.994c0.702-1.378 6.496-0.941 7.289-0.091 0.79 1.055 0.76 6.164-0.124 7.056-1.011 1.013-6.597 0.698-7.111-0.086-0.599-0.734-0.708-5.536-0.054-6.878z" fill="#fff"/></g></svg></svg> |
Plik CSS:
1 2 3 4 5 6 7 | /* Icons from directory "" */ .icon-webroad_blue,.icon-webroad_blue\:regular{background-image:url('icons/icons.svg');background-position:0 0;background-repeat:no-repeat} .icon-webroad_blue-dims{width:64px;height:64px} .icon-webroad_green,.icon-webroad_green\:regular{background-image:url('icons/icons.svg');background-position:0 -64px;background-repeat:no-repeat} .icon-webroad_green-dims{width:64px;height:64px} .icon-webroad_red,.icon-webroad_red\:regular{background-image:url('icons/icons.svg');background-position:0 -128px;background-repeat:no-repeat} .icon-webroad_red-dims{width:64px;height:64px} |
Jeżeli chodzi o samo wykorzystanie plików SVG to Chris Coyier w artykule Using SVG przedstawił już większość sposobów pracy z grafiką wektorową. Jeżeli znacie jakieś ciekawe przykłady zastosowania SVG to dajcie nam znać w komentarzach.
Tagi: grafika wektorowa • iconizr • promowany • svg • svgo
SVG powinny szybko wyprzeć icon fonty, gdyż są lepsze w prawie wszystkich aspektach. I to jest najlepszy sposób użycia SVG obecnie ;)
Co do SVGO – nie ma sensu się bawić konsolą za każdym razem. Są odpowiednie pluginy dla grunta i gulpa, więc dorzuca się takie coś jako ostatni krok w build toolu i leci samo ;) a przy grunt-watch to naprawdę leci samo :D
co do SVG: http://www.smashingmagazine.com/2014/05/26/love-generating-svg-javascript-move-to-server/
Ikony SVG może wyprą fonty, a może nie. Może są lepsze w wielu aspektach, ale nie o wiele lepsze. Prawdziwa różnica wychodzi przy animacjach.
Co do grunta. Trochę jak: po co użyć packi na muchy, BAZOOKA! Wszyscy używają OSXa, Windowsa lub Linuksa, ale mały procent czytelników używa grunta. Z SVGO z łatwością skorzysta każdy. Nieważne czy programista czy grafik. Ilu znasz grafików używających grunta? Ja żadnego.
Svg są lepsze pod prawie każdym asoektem, poczynając od dostępności i semantyki a kończąc na możliwościach ostylowania. Jedyny mankament to stare IE.
co do grunta: a po kiego grzyba grafik ma z niego korzystać? On robi grafikę i mi ją dostarcza. I to juz moja broszka, żeby ta grafika nie zarżnęła mamuta ;)
Cała nasza strona jest oparta na SVG. Bitmapowy jest tylko 1 element serwisu. Jeden :)