Як змінити колір у файлі svg?
Колір у SVG задається через атрибути fill (заливка фігури) і stroke (обводка). Обидва можна вказати прямо в розмітці, через CSS або JavaScript, але який спосіб спрацює залежить від того, як SVG потрапив на сторінку.
Теорія
TL;DR
fillфарбує внутрішню частину фігури,strokeфарбує її межу- CSS на SVG працює лише якщо SVG вбудований прямо в HTML
- Зовнішні SVG через
<img>ізольовані браузером - CSS туди не дістається currentColorзмушує фігуру успадковувати значенняcolorвід найближчого предка- Правило вибору: inline SVG + CSS для темізації,
<img>для ізоляції,<object>для часткового контролю
Швидкий приклад
<!-- Прямий атрибут - працює скрізь -->
<circle fill="red" stroke="blue" stroke-width="2" />
<!-- CSS на inline SVG - лише коли SVG у HTML -->
<style>
circle { fill: green; }
</style>
<svg><circle r="40" cx="50" cy="50" /></svg>
<!-- currentColor - іконка наслідує колір тексту батьківського елемента -->
<div style="color: navy;">
<svg width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M12 2L15 10H23L17 15L19 23L12 18L5 23L7 15L1 10H9L12 2Z" />
</svg>
</div>
<!-- Зірка відображається в кольорі navy -->Inline SVG-елементи - це DOM-вузли. Браузер зчитує fill і stroke або з атрибутів елемента, або з обчисленого CSS. Для зовнішніх SVG через <img> це не діє.
Межа зовнішнього SVG
Коли ти завантажуєш SVG через <img src="icon.svg">, браузер вважає його непрозорим зображенням. Внутрішній DOM цього SVG не є частиною батьківського документа. CSS-селектори зі сторінки туди не проникають. Це межа безпеки браузера, а не обмеження, яке можна обійти вищою специфічністю.
Якщо потрібні динамічні кольори на зовнішньому SVG, є три варіанти:
- Вбудувати SVG inline прямо в HTML тегом
<svg> - Використати
<object data="icon.svg">(CSS-фільтри спрацюють на самому елементі<object>, але не на внутрішніх елементах SVG) - Використати
<use>з посиланням на inline<symbol>
Коли який метод підходить
- Прямі атрибути
fill/strokeдля статичних кольорів або коли ти контролюєш вихідний SVG-файл - CSS на inline SVG для hover-станів, темізації, темного режиму і адаптивних змін кольору
currentColorдля систем іконок, де іконки мають відповідати кольору тексту навколо- JavaScript для змін кольору в реальному часі на основі даних або дій користувача
Типові помилки
Помилка 1: CSS для SVG завантаженого через <img>
<style>
svg circle { fill: red; }
</style>
<img src="chart.svg" />
<!-- Коло залишається оригінального кольору. Правило до нього не дістається. -->Браузер не розбирає внутрішню структуру SVG, коли воно завантажене як зображення. Вирішення: вбудуй SVG inline або використай <object>.
Помилка 2: Атрибут fill перемагає CSS
<style>
circle { fill: blue; }
</style>
<svg>
<circle fill="red" cx="50" cy="50" r="40" />
<!-- Відображається ЧЕРВОНИМ. Атрибут перемагає. -->
</svg>SVG-атрибути поводяться як inline-стилі і мають вищу специфічність ніж зовнішні CSS-правила. Це перше, що варто перевіряти коли зміна кольору через CSS не дає ефекту. Або видали атрибут fill з SVG, або використай !important: circle { fill: blue !important; }.
Помилка 3: color замість fill
<style>
svg { color: red; }
</style>
<svg><circle cx="50" cy="50" r="40" /></svg>
<!-- Коло не червоне -->Властивість color впливає на текстові вузли, а не на SVG-фігури. Для фігур потрібен fill: red. Єдиний виняток: якщо фігура має fill="currentColor", тоді color батьківського елемента таки впливає на її колір.
Помилка 4: Неочевидна область дії currentColor
<div style="color: blue;">
<svg>
<circle fill="currentColor" cx="30" cy="50" r="20" />
<g style="color: red;">
<rect fill="currentColor" x="60" y="30" width="40" height="40" />
<!-- rect - ЧЕРВОНИЙ, circle - СИНІЙ -->
</g>
</svg>
</div>currentColor приймає значення color від найближчого предка. Це зручно для локалізованого тематичного оформлення, але з першого погляду дивує.
Де зустрічається в реальних проектах
- Heroicons, Feather Icons - всі іконки мають
fill="currentColor"і автоматично підлаштовуються під колір кнопок, посилань і заголовків - D3.js, Recharts -
fillіstrokeна SVG-елементах задаються динамічно на основі даних - Styled-components, Emotion - змінні теми передаються в inline SVG через CSS custom properties
- GSAP, Framer Motion - анімація
fillіstrokeдля морфінгу і переходів кольору
Питання на співбесіді
Q: Чому CSS не працює для SVG завантаженого через <img>?
A: Браузер ізолює зовнішні зображення. DOM цього SVG не є частиною батьківського документа, тому жодні селектори, змінні чи скрипти не можуть до нього дістатись. Це рішення прийнято на рівні безпеки браузера.
Q: Чи можна використовувати CSS custom properties всередині SVG?
A: Так, якщо SVG вбудований inline. <circle fill="var(--brand-color)" /> працює і є чистим способом темізувати систему іконок через одну CSS-змінну. Зовнішні SVG не мають доступу до змінних батьківської сторінки.
Q: Як змінити колір SVG при наведенні?
A: CSS-псевдокласи на inline SVG: svg path:hover { fill: #2563eb; }. Для зовнішнього SVG через <img> практичні варіанти: CSS filter на самому елементі <img>, або заміна src через JavaScript на подію mouseenter.
Q: (Senior) Як зробити підтримку темного режиму для 50 SVG-іконок без дублювання розмітки?
A: Вбудуй всі іконки inline з fill="currentColor". Задай color на елементі-обгортці через CSS custom property: .icon { color: var(--icon-color); }. Визнач змінну для кожного режиму: @media (prefers-color-scheme: dark) { :root { --icon-color: white; } }. Всі іконки оновляться автоматично без змін у розмітці і без JavaScript.
Приклади
Статичний SVG з прямими атрибутами
<svg width="100" height="100" viewBox="0 0 100 100">
<circle
cx="50" cy="50" r="40"
fill="#3b82f6"
stroke="#1e40af"
stroke-width="4"
/>
</svg>
<!-- Синє коло з темно-синьою обводкою -->Атрибути обробляються першими, до CSS. Використовуй їх для автономних SVG-файлів або для фігур, колір яких не має змінюватись залежно від контексту.
Інтерактивна кнопка-іконка з currentColor
<style>
.icon-btn {
color: #6b7280;
background: none;
border: none;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
}
.icon-btn:hover { color: #2563eb; }
.icon-btn svg {
stroke: currentColor;
width: 20px;
height: 20px;
}
</style>
<button class="icon-btn">
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round">
<circle cx="11" cy="11" r="6" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
Пошук
</button>
<!--
За замовчуванням іконка сіра.
При наведенні: і текст, і іконка стають синіми.
Одне CSS-правило (color) керує обома.
-->stroke: currentColor на <svg> прив'язує колір іконки до кольору тексту кнопки. Hover, focus, disabled - всі стани кольору працюють від однієї CSS-властивості на кнопці, без жодних змін у SVG-розмітці.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.