🔥

Тред (@xnimorz)


Тред про иконки. >>>

Ограничения в задаче: есть базовые иконки, которые используются везде. Есть специфические иконки, которые выполняют одну задачку и их не планируется использовать где-то еще. Есть специфические для платформы.

Сверху добавляем браузерную поддержку и желание, чтобы иконки кешировались, реиспользовались и работали на двух стеках: xslt + mustache, react. Последнее уже наша специфика, но все остальное справедливо для большинства проектов.

Накидываем, прототипируем варианты:

Inline svg. Идея проста: каждую svg вставляем inline в код. fill, stroke убираем и будем стилизовать иконку через css классы. Чтобы просто было использовать в react пишем свой loader.

Код прототипа для inline варианта (вместе с кастомным webpack loader): gist.github.com/xnimorz/8dfe0c… Лоадер направляем на .svg иконки.

Выглядит просто и легко, но каждая иконка — это куча тегов в DOM, а значит куча данных, которые используются при SSR, увеличение количества DOM нод. Вроде бы сам подход удобный, но что-то не хочется.

В защиту решения: можно сделать поддержку многоцветных иконок, анимацию цветовых переходов.

Можем улучшить этот вариант и использовать inline svg + use директиву.

Идея такая: на этапе сборки превращаем все иконки в одну большую мега-иконку, где весь контент описан, например в <symbol /> теге. Вставляем эту иконку на страницу (она будет не видна для пользователя), а все реальные иконки просто используют тег <use />

Код становится проще, нам уже не обязательно делать кастомный лоадер. Достаточно обычного react-компонента: gist.github.com/xnimorz/543dc8…

Вместо одной большой мега-иконки можно использовать другой подход: в компоненте icon храним singleton-Map, в ней отмечаем, какая иконка была использована.

Если добавляется новая иконка, то вставляем эту иконку через symbol, помечаем в singleton и добавляем реальное использование через use. Этот подход избавляет нас от необходимости клеить все в одну иконку и делает подгрузку иконок на странице ленивой.

Главная проблема подхода: у <symbol> должен быть id. А значит мы получаем опасность пересечений, если иконки не сосредоточены в одном месте и мы не берем их id по пути к файлу. То есть мы приходим к глобальной области видимости, от которой так стараемся в том же css уходить.

Можно для иконок сделать решение аналогичное подходу css-modules и добавлять хеши например. Но мы начинаем строить космические корабли и переусложнять архитектуру.

Сама идея inline svg + use хороша и для многих проектов может зайти. Этот подход экономит и размер данных, и имеет хорошие возможности кастомизации.

Спрайты. Старые-добрые спрайты. Сама иконка выглядит примерно так: gist.githubusercontent.com/xnimorz/e0f107… Через use задаем состояния иконки и через background-position управляем тем, какую иконку увидит пользователь.

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

Если вы не поддерживаете "старые" браузеры типа IE11, то можно выбрать хипстерский способ через filter. Работает очень просто, вставляете иконку через background-image одного цвета и фильтрами настраиваете нужный вам цвет.

Здесь есть даже готовый калькулятор таких стилей codepen.io/sosuke/pen/Pjo…

Главные минусы: вас будут не очень сильно любить за стили вида: filter: invert(17%) sepia(32%) saturate(5440%) hue-rotate(344deg) brightness(89%) contrast(93%); Также не работает в старых браузерах и поддержку нескольких цветов настроить будет сложно.

Здесь этот способ описан подробнее: css-tricks.com/solved-with-cs… Плюсы — удобно, все средствами css.

Можно использовать css mask и затем через background-color задавать цвет. способ крайне простой, и нативно понятный, но с поддержкой все еще хуже caniuse.com/#feat=css-masks. И иконки в этом случае должны быть одноцветные (или градиентные)

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

Какое бы вы решение выбрали?
🤔 60.6% inline (c use или без)
🤔 22.1% Спрайты
🤔 5.8% filter или mask
🤔 11.5% Свой вариант