Комментарии 16
>На этот раз удобный
А что не удобного в стандартном способе import { ReactComponent as MyLogo } from './logo.svg';
А что у тебя прилетает в ReactComponent?
Если там Реакт-компонент (как я понимаю из контекста), подготовленный через SVGR, например, тогда все svg-изображения становятся частью js-бандла. Это по разным причинам не очень удобно, главная из которых - ты не можешь управлять их загрузкой. Плюс накладные расходы на рендеринг в Реакте.
А если там url до файла, получаемый через file-loader, то у тебя нет возможности встроить это svg на страницу так, чтобы работала стилизация через css.
При таком подходе не получиться нативно менять цвета или размеры изображения.
Получится. Через селектор `svg {}`
Получится, каскад будет работать:
https://css-tricks.com/cascading-svg-fill-color
А еще можно написать fill="currentColor"
прямо в SVG, примеры:
https://gomakethings.com/currentcolor-and-svgs
Ну вот представь что у тебя так вставляется иконка в элемент списка.
В списке рендерится например 20 строк и вот у тебя в итоге в html коде 20 раз одно и то же содержимое SVG файла. Которое может быть достаточно объемным. Растет Dom сильно.
Использование спрайтов и символов решает эту проблему.
P.s. именно лого обычно лучше встраивать через тег img
Тоже когда-то заморачивался и думал, что если 20 пунктов в списке - это 20 одинаковых иконок.. это плохо и нужно обязательно через спрайт и use всё это дело оформлять.
Однако потом пришло "прозрение" - что по сути иконки - это очень-очень простые фигуры.. как правило один короткий path.. ну может парочку. И поэтому смысла возится со спрайтом вроде как и нет.. ибо сами иконки всего чуть-чуть больше чем объвление тега use. И на 20-ти элементах списка выигрыша почти и нет.
Если же это иконка сложная - то скорее всего это уже не иконка, а какой-то отдельный элемент\иллюстрация, который встречается один раз на странице (лого там и др.).
По сути тег <use> - скорее изначально задумывался как хелпер для самих векторных редакторов, чтоб в сложной иллюстрации можно было бы переиспользовать повторяющиеся фигуры и комбинировать их.
Но потом кто-то придумал использовать этот эффект как возможность организации свг-спрайтов в html..))
Во-первых при всем этом не получится менять цвета и тд — т.к. SVG становится встроенным объектом (особенно при использовании svg-symbols) и придется поплясать с бубном, чтобы он стал обычным SVG в разметке и к его внутренностям можно было применять CSS.
Во-вторых все это делается крохотной функцией на vanila js, а не модулем ноды.
Интересно. Ндо будет попробовать. Спасибо за статью.
Действительно оно из лучших решений! А handy удобный инструмент для организации работы со спрайтами.
На деле представленные подходы можно и нужно комбинировать.
Картинки встречающиеся в приложении только один раз - инлайнить.
Используемые в нескольких местах картинки/иконки - брать из спрайта.
Статичные изображения не требующие модификации(ну типа лого в футере) - вставляем через обычный тег img
Что-то можно и в css через data-uri прописать.
Если по каким-то причинам не удается сменить цвет иконки через fill и store , можно заморочиться с фильтрами на css и подобрать любой цвет через hue-rotate, например
svg { filter: sepia() saturate(1000%) hue-rotate(0deg) }
Вот тут сравнивают перформанс разных способов втыкать svg: https://cloudfour.com/thinks/svg-icon-stress-test/
Не похоже чтобы спрайты как-то помогали с кучей повторяющихся иконок.
А у инлайна куча плюсов - он в CRA из коробки, ничего не моргает, грузится сразу все и только нужное. И даже подгружать можно по необходимости - через async-загрузку модулей у вебпака.
Хотя я тоже был когда-то адептом спрайтов.
Не знаю насчёт лучшего способа, но для себя я нашёл такой способ.
Способ позволяет менять РАЗМЕР иконки и любые другие цвета и свойства (надо для них CSS Custom properties написать, это несложно).
Файл SVG:
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100">
<!-- Delete width and height of <svg> tag, only viewBox is needed -->
<!-- If you specify there fill or stroke, they will be default -->
<!-- DO NOT PUT COMMENTS ABOVE <svg> TAG - it creates extra element-->
<!-- USING CSS VARIABLES -->
<style>
:root {
--first-circle-color: red;
--second-circle-color: black;
--third-circle-color: green;
--rect-color: blue;
}
</style>
<!--
Delete all fill and stroke in children
in order them to take fill and stroke from parent <svg> tag.
Set stroke="none" or fill="none" if you want to disable them.
(!!! if you not set them, then they can draw with defaults)
-->
<rect x="16" y="57" width="68" height="16" stroke="none" fill="var(--rect-color)" />
<circle cx="25.5" cy="40.5" r="9.5" stroke="none" fill="var(--first-circle-color)" />
<circle cx="50.5" cy="40.5" r="9.5" stroke="none" fill="var(--second-circle-color)" />
<circle cx="74.5" cy="40.5" r="9.5" stroke="none" fill="var(--third-circle-color)" />
</svg>
Файл компоненты React:
import React, {useLayoutEffect, useRef} from 'react'
import { ReactComponent as SomeSvgSvg } from 'src/assets/icons/some-svg-4.svg'
// USING CSS VARIABLES
const SomeSvgIc4 = (
{color1, color2, color3, color4, size}
: {color1:string, color2:string, color3:string, color4:string, size?:number}) => {
const svgRef = useRef<SVGSVGElement>(null)
useLayoutEffect(()=>{
const svg = svgRef.current
if (svg) {
svg.style.setProperty('--first-circle-color', color1)
svg.style.setProperty('--second-circle-color', color2)
svg.style.setProperty('--third-circle-color', color3)
svg.style.setProperty('--rect-color', color4)
}
},[color1,color2,color3,color4])
return <SomeSvgSvg ref={svgRef}
style={{ width: size, height: size, maxWidth: '100%', maxHeight: '100%' }}
/>
}
export default SomeSvgIc4
Использование:
{/* ... */}
<div style={{height:200, width:200, background: 'yellow'}}>
<SomeSvgIc4 color1={"gold"} color2={"red"} color3={"blue"} color4={"green"} />
</div>
<div>
<SomeSvgIc4
color1={"gold"} color2={"red"} color3={"blue"} color4={"green"}
size={200}
/>
</div>
{/* ... */}
Код взял из своего тестового реакт проекта, где иногда тестирую фичи реакта
https://github.com/RainFourth/react-ts-test/blob/main/src/components/SvgIcons/SomeSvgIc4.tsx
Спасибо за статью!
Я бы к минусам спрайта еще бы отнес то, что даже если мы отрендерили из него какие-то иконки, а затем у нас пропал интернет, и например появляется уведомление о неудачном действии (из за пропавшего интернета) - если в этом новом элементе (плашке уведомления) будет иконка из спрайта запрошенная через тег <use> - у нас отрисуется битая картинка, как будто отправляется вновь http запрос. Поэтому я чаще использую ReactComponent, а то что растет DOM - мы в реакте с ним и не работаем, а современные браузеры работают достаточно оптимизированно, мне кажется такие вещи они секут и не парсят каждую из 20ти блоков одинакого svg заново, но могу ошибаться. Вообщем для обычных задач ReactComponent пока что достаточен
Еще один способ использовать SVG в React. На этот раз удобный