SVG-иконки – много и со стилем


    Маленький рассказ о том, как наша команда решила организовать иконки в грядущем проекте. Чуть-чуть исторического экскурса, взгляды по сторонам (на PNG и векторные шрифты) и рассказ о том, как мы всё-таки обустроились в итоге.

    Иконки у нас используются, и активно – хорошо подобранная иконка заменяет слова и предложения (а фигово подобранной иконке можно сделать всплывающую подсказку, но не будем о грустном)

    В общем, есть (и продолжают создаваться) иконки. Надо их положить на веб-страницу. Надо сделать это так, чтобы потом голова не болела про них весь остаток проекта и ещё пару лет в поддержке. Ну и есть дополнительные хотелки:
    • хочется вектора. Ну, ладно, вектор – это средство, а не цель. Цель – не беспокоиться ВООБЩЕ об изменении размеров, ретина дисплеях, сохранении изображения в разных форматах для разных целей.
    • хочется стилизации иконок. Потому что у нас из коробки как минимум два набора тем (светлая и тёмная), а то и контрастная, для людей с нестандартным зрением, а то и оранжевенькая какая-нибудь появится ближе к Новому году… В общем – одна и та же по сути иконка должна выглядеть слегка иначе в зависимости от выбранной на странице темы.
    • хочется динамической стилизации иконок. Статики – нам мало. Этого хватает для скриншотиков и рекламных буклетиков, но не для живых пользователей. А мы хотели жизни! Мы хотели ховера! Мы хотели селекшена!!! И дизаблить, дизаблить их всех!.. Извините.
    • НЕ хочется, чтобы в этом участвовал JavaScript в любой его форме и проявлении. Иконки – это внешний вид, а за него ответственный HTML + CSS. Ну, ладно, класс selected я готов навесить на элементы, но это последняя граница…

    Есть и факторы, облегчающие задачу. Иконки сейчас (2015, осень, начинает снежить) в моде плоские, строгие. Если лет пять назад иконки пестрели, то сейчас это ушло под влиянием МС, Эппла, Материал Дизайна…

    tl;dr Внимание. Следующие несколько разделов – это расплывание мыcлею по древу, причём вширь, обзор решений (в том числе – неудачных) и котик в разных ракурсах.
    Кому хочется технических подробностей того, что же вышло в итоге – пожалуйте сюда.

    Чем не удовлетворяли классические решения


    • Мы можем сделать тучу png-иконок и класть их внутрь тэгов image. И подменять на JS-событиях наведения мыши. Когда я делал сайт на третьем курсе, этот метод реально работал. Хорошо было, и не надо было заботиться о множестве соединений с сервером. Может, когда круг замкнётся и HTTP 2.0 победит… а пока это накладно. Поехали дальше.
    • PNG-спрайты + CSS/background-image – хорошо, но не хватает. Наши коллеги из DevExtreme жили так некоторое время… но упёрлись в необходимость хоть какой-нибудь стилизации. Ведь с PNG-иконкой беда, её даже в красный на клиенте не покрасишь! Они перешли на Font Icons, а мы?..
    • Font Icons для написания приложения (не большой библиотеки, а именно приложеньица) оказался слегка неудобным в работе. Изменения иконок требуют некоторого обслуживания (сбор иконок, сохранение в файл шрифта, хинтинги всякие…) Если в интернете уже есть все нужные вам иконки в составе Font Awesome – лучше варианта и искать не стоит. Но если иконки нужны свои… мы пока пошли дальше.
    • Unicode-символы для иконок. Сам пошутил, сам посмеялся.
      Хотя...
      хотя не могу не отметить, что я оч люблю их использовать в девелопменте, до дизайна и релиза. Быстро, просто, Ctrl + C, Ctrl +V, font-size, color, :hover, .selected { color: } – и вот у вас прекрасная иконка с ховером и селекшеном бесплатно, без СМС…

    • SVG + CSS/background-image – имеем нормальное масштабирование. Не имеем стилизации непосредственно иконки. Нет, мы можем это заворкараундить – hover-состояние в принципе делается изменением цвета бэкграунда, а disabled-состояние — в какой-то мере изменением opacity. Это рабочий вариант, такой была наша первая залитая в репозиторий версия. Но вот сам рисунок мы стилизовать не можем. Потому что он не в DOMe. А когда в доме чего-то нету – это беда…
      К тому, что не является частью документа, не применишь стили CSS, не подкрасишь, не изменишь.


    А давайте положим SVG в ДОМ?


    Мы, конечно, можем это сделать. Скопипастить каждую иконку и вставить её туда, где она будет нужна, в каждый кусочек HTML-разметки.

    Код котика

    <?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>
    

    Сам котик лежит тут.
    То есть вот это всё предлагается положить внутрь документа.

    А если она поменяется, то перескопипастить во все места использования.
    Или поднапрячься и написать для нашего проекта узкоспециальное решение, которое во время сборки, или во время деплоймента, или во время исполнения будет по магическим атрибутам понимать, что вот тут должна быть иконка, и инжектить (inject, не знаю, как перевести) содержимое одного файлика внутрь содержимого другого файлика.
    Это очень весело звучит и очень напрягает в поддержке.

    К сожалению или к счастью, нам в DevExpress этот путь не подходит по определению. Мы не пишем (почти) конечные программные решения, мы пишем то, что другие люди будут использовать в своих решениях.
    Представив себе лица этих людей, которых бы мы попросили ручками инжектить наши SVG на их странички, мы резко перешли к следующему возможному решению…

    А если положить в DOM, но чуть-чуть, а лучше – автоматически?


    Ну то есть подсоединить к нашему документу некое хранилище, аналог спрайта с иконками, в котором лежали бы всеее иконки.

    А там, где они нужны, мы бы сказали – а дай-ка нам, дорогой браузер, иконку kotik!

    Да, так можно делать, и люди так делают. Собираем все наши иконки пофайлово и кладём их все внутрь одного большооого SVG-спрайта, который содержит в себе лишь шаблоны иконок. Технически для этого используется элемент symbol.
    Про символ
    Этот элемент и задуман как шаблонный. Весьма самодостаточен, по уровню возможностей – почти как маленький svg-файлик. Позволяет определять свои условные «размеры» — viewBox, к которым будут применяться координаты элементов. То есть у нас полностью уйдёт проблема сопоставления наших размеров с размерами иконки, что плюсит. Чуть-чуть подробностей. Сейчас поддерживается из коробки билдёжками для gulp/grunt.

    Символический кот
    Результат оборачивания кота в символ плагином gulp-svgstore. Собственно, почти ничего и не поменялось.
    <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>
    


    Этот элемент нигде не отображается – by design. Он всего лишь маска для будущих настоящих иконок.
    Мы можем взять этот шаблон и положить его на страницу, сославшись на него из элемента use.
    <svg>
        <use xlink:href="#kotik" />
    </svg>
    

    Всё, котик тут.

    Белохвостый, обычный.

    А ещё можем сделать интереснее. Шаблон – он уже дома. В смысле в DOMе. И его уже можно стилизовать совсем как настоящий. Используя имена svg-элементов (path, circle, rect и т.д.), мы можем применять к ним CSS-правила и модифицировать атрибуты (цвета через fill и stroke, толщины и стиль линий)
    .tail { color: orange; }
    

    И теперь все коты, ссылающиеся на этот шаблон, станут оранжевохвосты.



    Так, наш последний метод уже дал нам два из трёх пунктов наших хотелок.
    А вот при попытке застилизовать одну конкретную иконку меня сначала ждало разочарование.

    Удивиться истории про use, xlink: href и деревья вместе


    Как только мы пытаемся кастомизить одного взятого котика в лоб – всё перестаёт работать.
    <svg id="barsik">
        <use xlink:href="#kotik"/>
    </svg>
    

    #barsik .tail {
        fill: orangered;
    }
    

    Увы, хвост Барсика не рыжеет.
    Причина этого интересна. Барсика на самом деле там нет.
    Барсик – в тени.

    ДОМ теней


    Shadow DOM – штука уже как бы не новая. Её начали использовать производители браузеров для того, чтобы слепить input type=datebox, а мы об этом и не знали. В тот момент они ещё не были в курсе, что используют Shadow DOM, имя и форму он обрёл несколько позже…

    Элемент use – в современных терминах – использует именно что Shadow DOM.

    Элементы, которые мы *клонируем* внутрь *корня* use – помещаются в наш DOM… но не до конца.
    В частности, к ним нельзя применить CSS правила.

    Но корень теневого дерева, элемент <use /> – он как бэ с одной стороны в нашем основном дереве, а с другой – является предком всего, что в дереве лежит.
    С первой стороны мы применим к нему CSS-стиль.
    Со второй же стороны – он пробросит приданные ему CSS-свойства своим потомкам. Если мы скажем шаблону, чтобы он к этому прислушался.
    //явно указываем на уровне шаблона, что хвост должен унаследовать цвет заливки от своего предка
    .tail {
        fill: inherit;
    }
    //стилизуем предка
    #barsik use {
        fill: orangered;
    }
    

    Так Барсик приобретает оранжевый окрас, а Васька — дымчато-белый.

    (если частям и элементам его кошачьего SVG-тела не указано иного. Приоритет наследованных CSS-свойств довольно низок, ниже атрибутов и уж точно ниже других правил, примененных к темплейту – а темплейт живёт полностью в DOM, без всяких оговорок. Подробности чуть ниже)
    А дальше мы можем уже использовать любые вариации.
    .cat-house:hover #barsik use {
         fill: red;
    }
    

    Таким образом, один цвет мы уже можем кастомизить совершенно свободно и в полном соответствии с буквой CSS. Реализовать подсветку при наведении становится проще простого.




    Порядок применения стилей, свойств и атрибутов


    В этот момент с непривычки начинает становиться непонятно, поэтому я постараюсь расписать ещё раз.
    Для меня это было небольшим камнем преткновения.
    Подход первый, без CSS

    У SVG-элемента может быть атрибут, указывающий его цвет. Для большинства фигур (path, circle, ellipsis) это fill, реже используется stroke (для указания цвета границ фигуры).
    <circle fill="green" cx="200" cy="200" r="30"></circle>
    

    Если у элемента этого атрибута нет – он пытается получить его у предков. Идёт вверх по своим родителям до тех пор, пока не находит кого-то с указанным атрибутом.
    <g fill="darkblue">
        <circle cx="100" cy="100" r="25"></circle>
        <circle cx="300" cy="100" r="25"></circle>
    </g>
    

    Два круга, заливка не указана, берут у родителя. Очень удачно – у первого же родителя, группы, в которой они лежат, есть заливка. Оба круга становятся синими.
    Подход второй. Появление стилизации

    Как только мы применяем стили – они побеждают. Правило
    circle  {
        fill: orange;
    }
    

    Сделает оранжевыми оба круга. Оно просто сильнее…

    Подход третий. Стилизация убивает атрибуты, чтобы элементы использовали атрибуты


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

    Вот такой код даст нам фиолетовый эллипс.
    Однако добавление CSS-правила
    ellipse {
        fill: inherit;
    }
    

    Заставит его забыть собственный цвет и начать брать его у предков.
    Вот так выглядит пример целиком. Любые совпадения случайны.

    Эллипс станет оранжевым.

    В общем-то, на этом трюке и основана большая часть примеров.
    Ещё могут быть inline-стили и !important, но там уже всё идёт по аналогии

    Ну и ещё немножечко магии

    Стилизация второго цвета


    С помощью хакотрюка, основанного на переменной SVG currentColor, мы можем кастомизить уже два цвета:
    .tail {
        fill: inherit;
    }
    
    .body {
        fill: currentColor;
    }
    
    svg use {
        fill: brown;
        color: orange;
    }
    
    svg:hover use {
        fill: orange;
        color: brown;
    } 
    


    Как-то так.

    Трюк с невидимым котом


    Ещё одна минорная вещь, которая, в принципе, может когда-то пригодиться — скрывать элементы изображения при некоторых условиях.

    Напрямую мне этого добиться не удалось — у опции visibility так, всё или ничего…
    Но мне удалось, с помощью тех же цветов, покрасить элемент в прозрачный цвет. Очень красиво, главное — правильно подобрать оттенок.



    Технические мелочи


    SVG-спрайт должен лежать в DOMe. Большинство браузеров смогли бы показать шаблоны и из залинкованного файла, но не ИЕ. Поэтому – выкачиваем через AJAX и вставляем в ДОМ. Есть статья.

    Движки шаблонов могут работать странно. Атрибут xlink:href живёт в своём неймспейсе (собственно, в неймспейсе xlink, там так и написано), и это не все любят. Например, Knockout не умеет это биндить из коробки. Есть воркараунд. Он работает.

    Могу предположить, что в других движках темплейтов могут возникнуть схожие проблемы. Могу предположить, что их можно решить схожим образом.

    Что же получилось в итоге


    • Наши иконки хранятся и лежат в отдельных SVG файликах, маленьких, любимых в VCS, понятных в диффах и открываемых в браузере
    • Наши иконки в момент билдёжки собираются внутрь одного большого файлика – icons.svg. То, что было файликом, становится шаблоном.
    • Этот файлик нужно положить внутрь HTML-разметки. Руками, инструментом сборки или JavaScript
    • На иконки можно ссылаться с помощью вот такой конструкции:
      <svg>
          <use xlink:href="#kotik"/>
      </svg>
      

      Конструкция является более явной и более семантически верной, чем при создании иконки при помощи background-image
    • Шаблон иконки лежит внутри DOM и может быть модифицирован через CSS
      path.tail { fill: darkgrey; }
    • Конкретная иконка делается на основе шаблона, сама в DOM не попадает, но попадает в теневой DOM и её можно стилизовать благодаря наследованию CSS-свойств от родительского элемента-якоря use.
      #dvorovayBreed.selected use { fill: darkgreen; }
      
    • Иконку можно стилизовать как угодно на уровне документа – задавать внутренним элементам SVG классы и красить/модифицировать для всего документа как душе угодно и как CSS позволяет
    • Для одной конкретной иконки можно модифицировать два цвета – ровно два. Один – цивилизованно, второй – благодаря магии. Магия очень сильная и работает везде, но магия имеет свою цену – будьте аккуратны в продакшене!
    • JavaScript нужен максимум один раз, в процессе жизни страницы больше не используется

    Решение получилось не привязанным чрезмерно к специфике билдёжке, хорошо стилизуемым.

    Работает в IE9+, вебкитах, на читалке Amazon Kindle и на телевизоре Samsung.

    Все примеры стилизации SVG-иконок лежат на Гитхабе. Я давал ссылки на GitHub Pages этого репозитория.
    Надеюсь, кого-то заинтересовал этот рассказ.

    UPD Добавил по результатам вопроса в комментариях ещё одну страничку, показывающую стилизацию 122-х настоящих иконок, всего 500 экземпляров на странице
    Иконки для этого примера взяты на www.flaticon.com

    Благодарности


    При подготовке блог-поста не пострадало ни одно животное.
    Котик, изначально растровый, был переведён в СВГ-термины в онлайн-редакторе (исходники).

    Навык рисования котиков я получил, рисуя котиков своему сыну, который был ими чрезвычайно доволен.
    Претензии же по поводу несимметричности ушей я принимать отказываюсь.

    Список литературы


    Очень-очень-очень подробный рассказ про стилизацию теневого SVG
    Про SVG-иконки в принципе, а также о том, почему символ лучше группы
    История темы иконок на хабре — SVG, Iconfonts vs PNG
    SVG-иконки — разные подходы, тоже с котиками
    Как правильно подгрузить SVG-спрайт в DOM
    SVG библиотека рисования чартов. Никакого отношения к иконкам она не имеет, но там тоже котики, в том числе и моя кошка, (помогавшая мне писать статьи и служившая моделью для рисования).

    Developer Soft

    74,01

    Компания

    Поделиться публикацией

    Похожие публикации

    Комментарии 34
      +3
      Вопрос такой: на сколько медленее работает SVG посравнению с PNG изображением. Да я понимаю, что вы предпочли SVG потому что вам нужно менять цвет и размер. Но всеже браузеру придется читать SVG код и отрисовывать графику. На сколько это влияет на скорость отображения на стороне клиента? А если иконок на странице много? Делали ли вы такие исследования?
        +2
        У нас иконок не слишком много, порядка пары десятков. На таком количестве ничего не заметили, а мерять целенаправленно — не меряли.
        Год назад меряли вот тут; там, в частности, автор рассказал о том, что в ИЕ SVG сразу работает нормально, в Firefox результаты SVG-рендерёжки кэшируются и сильно не тормозят. В хроме же на тот момент кэширование было отключено, иконки пересчитывались.
        Чую, что за год положение должно было измениться, но доказать не могу.
          0
          Да эту статью годовой давности я тоже почтал. Но мне потребуется найти какие-то более убедительные результаты бенчмарков чтоб уговорить команду перейти на SVG иконки. А их у нас ожидается от 50 до 100 на нашем landingpage. Так что скорость очень важна.
            +2
            Отдал страничку с пятью сотнями котов (создающихся нокаутом)
            kaatula.github.io/svg-icons/samples/hunderds-of-cats.html
            На компе с восемью ядрами всё хорошо
            На винфоне имеет место задержка около секунды на старте страницы — я пока не понял, то ли это создание элементов, то ли конкретно SVG. Скроллинг при этом плавный.
            Сейчас ещё буду на устройствах котиков мучать…
              +1
              Но это же один и тот-же SVG? Просто к нему применены разные стили? Мне кажется браузер может оптимизировать использование одного и тогоже SVG и не рендерить его несколько раз. Интересно что будет если это разные изображения объединенные в такой «SVG спрайт».
                +5
                Тогда ещё примерчик

                122 различные иконки, всего на странице 500

                (исходники иконок на гитхаб класть не стал, встроил сконкатенированный и минифицированный результат непосредственно в страничку)

                Иконки брал вот у этих ребят
                Они простенькие и симпатичные. Бесплатные при условии атрибуции.
                  +2
                  У меня обе странички браузер прожевал даже не поперхнувшись. Моментально и без всякого напряга. Мне кажется, «тяжеловесность» для браузера SVG сильно преувеличена.

                  Firefox 43.0a2 (Dev Edition, или альфа)
                    0
                    Я вот, например, порядком волнуюсь о мобильных устройствах. Но iPad, найденый в соседних кабинетах, никаких признаков утомления не показал…
                      +1
                      Firefox for Android 41.0.2, HTC One M9, аналогично десктопу прожевал даже не поморщившись.
                    +1
                    Осталось теперь для сравнения тоже самое только в PNG =)
                    А то не с чем сравнивать. Я покапался, вроде эти SVG рендерятся за 250ms… что довольно много, но надо сравнивать.
        +5
        >инжектить
        Вставлять, встраивать.

        Спасибо за статью!
        Во время Вы) Как раз обдумывал на проекте картинки-иконки заменить СВГшками.
          +2
          Вот встраивать, кстати, хорошо в контекст ложится. Спасибо :)

          И я буду рад, если статья окажется полезной. С СВГ жить очень хорошо, в общем-то. Нам пока нравится.
          +3
          Есть умеренно грязный хак, позволяющий красить PNG-иконки — файл иконки должнен быть белым или в цвет бекграунда, с «вырезанной» по центру иконкой. Ну, как дырка в бумаге, сквозь которую видно подложку. Красим подложку, видим цвет иконки.



          Не пропогандирую этот метод, там тоже куча нюансов есть, но он быстрый, кросбраузерный вплоть до 6 IE и очень простой.
            +2
            Согласен, такое тоже может работать.
            Любой задаче — правильное решение.
            Для этого решения тоже вполне бывали задачи.
              0
              Можно живой пример кода?
                0
                Да чего тут особо демонстрировать, вот смотрите, за минуту сделал: jsfiddle.net/yq1rqmyd/2
              0
              <?xml version="1.0" encoding="UTF-8"?>
              <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
              

              Удалите из поста вот эту ненужну шапку SVG-файла, пока кто-то её случайно не скопировал.
                +1
                Эта заразу генерит gulp-плагин. Я тоже недоволен, но не настолько, чтобы вмешиваться в работу робота…
                Но я согласен, в человекочитаемой статье ей не место
                  +3
                  «The only available option is:
                  inlineSvg — output only element without <?xml ?> and DOCTYPE to use inline, default: false.»
                    +2
                    Вот это я понимаю — community
                    Спасибо, отдал.
                      0
                      Автор плагина просто неправ: этот заголовок не нужен не только для инлайна, а вообще никогда на практике
                  0
                  .
                    +1
                    Для пользователей вебпака мы написали лоадер, который создаёт спрайт и вставляет его в DOM автоматически. На выходе из require получается uri для <use>.
                      +2
                      Моя иконка хорошо гармонируют с владельцем репозитория
                      Должны сработаться )
                      0
                      почему-то подход с символами не работает вместе с анимациями в хроме (на айпаде работает). Если символ заменить на группу, то проблема исчезает.
                        0
                        Интересно. Звучит как баг…
                        Я-то с анимацией, признаться, не заморачивался…

                        Как доберусь до рабочего компа, поэкспериментирую. Возможно, будет повод завести им бажок они-то проигнорят, зато совесть будет чистая
                          0
                          Вообще, простая-простая анимация у меня заработала
                          kaatula.github.io/svg-icons/samples/animation.html
                          Не завелась, из десктопных бразуеров, только в MS Edge/IE и в старом виндовом Сафари (при этом она хотя бы стилизуется...)

                          А что не заработало?
                            0
                            речь шла о цсс анимациях. в ие работать и не будет, там цсс трансформации не передаются в свг а smil не поддерживается.
                          0
                          +1
                          UPD через два года
                          Поскольку тут ещё есть люди и приходят новые, решил дописать о результатах.

                          Подход полностью летит на нашем рабочем проекте — веб-дизайнере дэшбоардов.



                          Все иконки, что вы видите на это скриншоте, добавлены на страницу при помощи описанной технологии.
                          Иконки готовятся в Adobe Illustrator; средствами самого иллюстратора создаются «стили», которые при экспорте в SVG становятся настоящими CSS-стилями, которые мы перебиваем своими правилами. Дизайнер делает всё своими инструментами, помощь программиста для создания иконок не нужна. То есть всё на удивление нативно вышло с дизайнерскими средствами.

                          Коды иконок до и после
                          Вот так экспортирует Adobe Illustrator:
                          <?xml version="1.0" encoding="utf-8"?>
                          <!-- Generator: Adobe Illustrator 19.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
                          <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
                            viewBox="4 -4 24 24" style="enable-background:new 4 -4 24 24;" xml:space="preserve">
                          <style type="text/css">
                            .dx_blue{fill:#579ADD;}
                            .dx_darkgray{fill:#414141;}
                          </style>
                          <path class="dx_darkgray" d="M5,7h10V-3C9.5-3,5,1.5,5,7z"/>
                          <path class="dx_blue" d="M17-1V9H7c0,5.5,4.5,10,10,10s10-4.5,10-10C27,3.5,22.5-1,17-1z"/>
                          </svg>
                          


                          Вот такой иконка становится после прогона через билдёжку (в данный момент — Gulp, плагины gulp-svgstore + gulp-svgmin)

                          <svg xmlns="http://www.w3.org/2000/svg">
                          ...
                          <symbol id="dx-dashboard-toolbox-pie" viewBox="4 -4 24 24"><path class="dx_darkgray" d="M5 7h10V-3C9.5-3 5 1.5 5 7z"/><path class="dx_blue" d="M17-1V9H7c0 5.5 4.5 10 10 10s10-4.5 10-10S22.5-1 17-1z"/></symbol>
                          ...
                          ещё 114 иконок
                          ...
                          </svg>
                          
                          


                          Вот так мы прям в начале CSS отбиваем эти стили у иконок на уровне темплейта:

                          //меняет сам шаблон
                          .dx_blue {
                            fill: #579ADD;
                          }
                          // вот это, кстати, перекрашивается в тёмной теме - отдельной CSS 
                          // без использования описанной технологии, но оч. удобно
                          .dx_darkgray {
                             fill: #414141;
                          }
                          
                          symbol#dx-dashboard-binding-panel-pie {
                            .dx_blue {
                              fill: inherit;
                            }
                          }
                          

                          И с этого момента можем использовать описанную технику с use для изменения цвета элемента иконки.

                          Какие ещё тонкие моменты:
                          — IE зачастую оооочень странно прокидыет ивенты мыши из таких теневых элементов.
                          Поэтому почти везде на самих иконках мы ставим pointer-events: none, и обрабатываем ивенты на уровень выше;
                          — IE зачастую не перерисовывает иконки, если играться с display свойствами их родителей. Поскольку у нас много иконок лежит на оверлеях — мы с этим прилично наборолись. Приходилось заниматься мистическими перестановками в ДОМе, надеясь, что очередной способ IE поймёт правильно
                          В последних версиях они это как будто бы починили.

                          И в общем-то, у нас всё хорошо. Разве что каждого нового программиста приходится отправлять читать эту статью :)
                            0
                            А как на счет вставить вот этот огромный «спрайт» с иконками в index.html на этапе сборки и сделать ему display: none?
                              0
                              Мы — не можем так сделать, потому что мы не пишем приложение
                              Мы пишем контрол, который люди вставляют в свои приложения

                              А в нашем девелоперском приложении, где мы разрабатываемся — мы так и делаем, понятное дело. Да и в нашем ASP.NET WebForms контроле тоже врендериваем в рантайме как часть страницы.

                              Вот только это очень хороший пункт:

                              display: none

                              делать нельзя. В некоторых браузерах в некоторых случаях (честное слово, не помню деталей — то ли ИЕ, то ли FF) — это губит работу с иконками.
                              Поэтому див должен быть display: block, visibility: hidden, position: absolute, left: -10px, top: -10px, width: 1px, height: 1px

                              Так у него работают градиенты и не растаращивает файрфокс огромный скроллбаром на этом невидимом элементе.
                                0
                                Ясно, спасибо за развернутый ответ.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое