Как подготовить максимально простые при использовании в вёрстке SVG-иконки, нарисованные дизайнером?

Иконки Material Design очень хороши тем, что в них содержимое тэга svg состоит из одного-единственного тэга path, например:

<svg style="width:24px;height:24px" viewBox="0 0 24 24">
    <path fill="currentColor" d="M9.12,11.94V16.89H5.69V5.69H16.89V9.12H11.94L18.31,15.5L15.5,18.31L9.12,11.94Z" />
</svg>

Всё что нужно сделать для изменения цвета иконки - изменить свойство fill (можно через css, а атрибут fill убрать). Это их сильная сторона. Так почему бы их везде не использовать?

  1. Эти иконки имеют непрошенные отступы по умолчанию, привязанные к viewBox="0 0 24 24" убрать которые невозможно, не перерисовав картинку. Это становится серьёзной помехой при простановке отступов от этих иконок и указании размера. При точной качественной вёрстке это не то, что можно терпеть.

введите сюда описание изображения

  1. Должна быть возможность использовать и другие иконки. Не должно быть такого ограничения, что "использовать только иконки Material Design и больше никакие другие".

Но как добиться такого же качества SVG-кода, что и у иконок Material Design? Если мы возьмём SVG-файл, изготовленный дизайнером, там такого же чистого кода, как в примере выше, не будет! Вот пример: простенькая иконка крестика, нарисованная в Adobe Illustrator:

введите сюда описание изображения

Вот какой ужас мы увидим, если посмотрим её SVG-код:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.3, 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="0 0 18.7 18.7" style="enable-background:new 0 0 18.7 18.7;" xml:space="preserve">
<style type="text/css">
    .st0{fill:none;stroke:#000000;}
</style>
<g id="Group_374" transform="translate(-1190.881 -26.636)">
    <path id="Path_9" class="st0" d="M1191.2,27l18,18"/>
    <path id="Path_11" class="st0" d="M1191.2,45l18-18"/>
</g>
</svg>

Оптимизатор SVG - отнюдь не панацея. В данном случае он не сделает почти ничего, сколько не играй с параметром precision:

введите сюда описание изображения

Аналогичная иконка из MaterialDesign:

<svg style="width:24px;height:24px" viewBox="0 0 24 24">
    <path fill="currentColor" d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</svg>

Но уродливый код ещё можно потерпеть, используя возможности препроцессоров. Дело в том, что в одних случаях для изменения цвета иконки нужно указывать параметр fill (как и в MaterialDesign), а в каких-то - stroke. Получается, что изменение иконки будет влечь за собой изменение CSS-кода, а нужно, чтобы одна иконка легко заменялась другой.

Возникает вопрос: как же организовать подготовку качественных SVG-иконок в идеале состоящих из одного тега path? Вы представляете, что будет, если я скажу дизайнеру: "Ты Illustrator-е иконке не рисуй, а он код плохой генерирует, давай-ка бери редактор кода и вручную прописывай значение аттрибута 'path' и чтобы он был как можно короче"?


Ответы (3 шт):

Автор решения: BlackStar1991

Для того что бы делать "правильные" иконки, вам самому необходимо немного разбираться в дизайне. То как создает иконки в Illustrator зависит от правильности рук дизайнера и грамотно поставленного ТЗ. В приведенном вами примеров дизайнер например использовал отдельный слой для иконки и карандаш, вместо пера(или кисти), ну или же строил автофигурами, по тому и получили на выходе теги <g> и атрибут <stroke> Если хотите получать только path на выходе svg, то на сам дизайн должны накладываться ограничения, например - при работе используется, только перо, не допускается использование обводок, градиентов, фильтров и тд... По факту все иконки которые должны вы получать от дизайнера должны быть путями с fill="#000000" Очень сомневаюсь что вы сможете убедить дизайнера отдавать вам такой материал... Так что если для вас это критично, то переделывание svg будет зависеть от вас. PS Проблема с неправильными размерами при рендеринге svg решается заданием атрибутов viewBox width height самому тегу svg Вот такое написание не верно style="width:24px;height:24px"

→ Ссылка
Автор решения: Alexandr_TT

Эти иконки имеют непрошенные отступы по умолчанию, привязанные к viewBox="0 0 24 24" убрать которые невозможно, не перерисовав картинку. Это становится серьёзной помехой при простановке отступов от этих иконок и указании размера. При точной качественной вёрстке это не то, что можно терпеть.

Отступы можно убрать изменением атрибутов viewBox, но эти отступы сделаны разработчиками икон специально, чтобы например, можно было использовать иконки в разных цветовых темах. У вас вариант для светлой темы, но для темной темы эти отступы можно будет покрасить под цвет фона

let bb = arrow.getBBox();
console.log(bb);
svg {
background:#000;
fill:white;
}
<div class="container">
<svg width="3%" height="3%"  viewBox="0 0 24 24" style="border:1px solid red;">
    <path id="arrow"  d="M9.12,11.94V16.89H5.69V5.69H16.89V9.12H11.94L18.31,15.5L15.5,18.31L9.12,11.94Z" />
</svg> 
</div>

Красный прямоугольник показывает границы холста SVG. Раз дизайнер рисовал вам иконки 24 x 24px значит такой размер уже зарезервирован им в дизайне и с отступами вроде бы не нужно бороться, НО если, действительно нужно убрать зазоры, то можно воспользоваться методом JS getBBox()

Убираем отступы

В примере выше уже выведены физические размеры иконки 12.61 x 12.61px и отступы от верхнего левого угла холста SVG x="5.69" y="5.69"

Было : viewBox="0 0 24 24"
Стало : viewBox="5.69 5.69 12.61 12.61"

<svg width="3%" height="auto" viewBox="5.69 5.69 12.61 12.61" preserveAspectRatio="none" style="border:1px solid red;">
    <path id="arrow" d="M9.12,11.94V16.89H5.69V5.69H16.89V9.12H11.94L18.31,15.5L15.5,18.31L9.12,11.94Z" />
</svg> 

<script>

let bb = arrow.getBBox();
console.log(bb);
</script>

Обратите внимание
Отступы убрали, но за счет этого иконка стала иметь меньшие размеры. Не 24px, а 12.62px

Использование stroke и fill в иконках

Немного теории:

  • Если атрибут fill не указан, то криволинейные и замкнутые прямолинейные path будут закрашены чёрным цветом по умолчанию.
  • Если цвет stroke (обводка) для линий, а также для path в форме прямых линий не указан, то линий не будет видно. fill="black" в этом случае не работает.

Возьмем для примера вашу иконку от дизайнера:

введите сюда описание изображения

Крестик нарисован двумя прямолинейными path, поэтому fill="black" не работает.

<style> 
 .st0{fill:black;}
</style>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink" width="18.7" height="18.7" viewBox="0 0 18.7 18.7" >

<g id="Group_374" transform="translate(-1190.881 -26.636)">
    <path id="Path_9" class="st0" d="M1191.2,27l18,18"/>
    <path id="Path_11" class="st0" d="M1191.2,45l18-18"/>
</g>
</svg>

stroke="black" работает:

<style> 
 .st0{stroke:black; stroke-width:2;}
</style>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink" width="18.7" height="18.7" viewBox="0 0 18.7 18.7" >

<g id="Group_374" transform="translate(-1190.881 -26.636)">
    <path id="Path_9" class="st0" d="M1191.2,27l18,18"/>
    <path id="Path_11" class="st0" d="M1191.2,45l18-18"/>
</g>
</svg>

Склеивание нескольких Path

В конец первого path добавляете начало (M) второго path

<style> 
 .st0{stroke:black; stroke-width:2;}
</style>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink" width="18.7" height="18.7" viewBox="0 0 18.7 18.7" >

<g id="Group_374" transform="translate(-1190.881 -26.636)">
    <path id="Path_9" class="st0" d="M1191.2,27l18,18M1191.2,45l18-18"/>
   
</g>
</svg>

Иконки Material Design очень хороши тем, что в них содержимое тэга svg состоит из одного-единственного тэга path, например:

<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" style="border:1px solid red;">
    <path id="arrow" d="M9.12,11.94V16.89H5.69V5.69H16.89V9.12H11.94L18.31,15.5L15.5,18.31L9.12,11.94Z" />
</svg> 

введите сюда описание изображения

Иконка нарисована одним замкнутым path, поэтому по умолчанию работает fill="black"

Замечу, что во многих других иконках с этого ресурса, может быть несколько path, а также бывают плюс и polygon, polyline, - это зависит от сложности иконки.

Рекомендации дизайнеру

<g id="Group_374" transform="translate(-1190.881 -26.636)">
    <path id="Path_9" class="st0" d="M1191.2,27l18,18"/>
    <path id="Path_11" class="st0" d="M1191.2,45l18-18"/>
</g>

Из кода видно, что иконку размером 24px, начали рисовать из точки M1191.2 а затем, переместили иконку обратно transform="translate(-1190.881 к началу координат.

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

  1. Лучшим решением является выбор нужного размера документа, например 24x24px и стараться рисовать таким образом, чтобы иконка не выходила за границы документа. Тогда ничего не нужно будет двигать, ничего не обрежется, иконка не будет смещаться вниз и вправо при scale()
  2. Универсального решения, чтобы было в иконках или только fill или stroke нет. Всё равно надо будет тщательно выбирать, рисовать иконки.
→ Ссылка
Автор решения: Alexandr_TT

Google Material Icons

Во многих случаях можно использовать символьный шрифт svg иконок от Google, состоящий из 900 иконок. И ваша иконка крестика close тоже есть в этом наборе.
Дополнительная доработка иконок не потребуется. Стилизация иконок из внешнего CSS

Подключение и использование шрифта от Google

  • Подключение шрифта:

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

  • Выбирать иконки по названиям можно здесь
  • Пример использования гугловского символьного шрифта:

i {
  margin: 50px 25px 25px 80px;
  transition: transform 0.3s ease-in-out;
}
i {color:black}
i:hover {
  transform: scale(2);
}
.red:hover{color:red}
.green:hover{color:yellowgreen}
.blue:hover{color: dodgerblue}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<i class="material-icons red">close</i> 
<i class="material-icons green">north_west</i>
<i class="material-icons blue">menu</i>

→ Ссылка