Suggest an editImprove this articleRefine the answer for “How to change color in svg file?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**SVG color** is set through `fill` (shape interior) and `stroke` (outline) attributes. ```html <circle fill="red" stroke="blue" stroke-width="2" /> ``` CSS works only on inline SVG. External SVGs loaded via `<img>` are browser-sandboxed and ignore page styles. Use `fill="currentColor"` to inherit the parent element's `color` value. **Key point:** `fill` attributes have higher specificity than CSS rules and override them unless you remove the attribute or use `!important`.Shown above the full answer for quick recall.Answer (EN)Image**SVG color** is controlled through `fill` (interior of a shape) and `stroke` (outline). Both can be set in the markup, through CSS, or with JavaScript - but which method actually works depends on how the SVG is loaded into the page. ## Theory ### TL;DR - `fill` paints the inside of a shape, `stroke` paints its border - CSS works on SVG only when the SVG is inline in the HTML document - External SVGs loaded via `<img>` are browser-sandboxed - no CSS gets in - `currentColor` makes a shape inherit the `color` value from its nearest ancestor - Decision rule: inline SVG + CSS for theming; `<img>` for isolation; `<object>` for partial control ### Quick example ```html <!-- Direct attribute - works everywhere --> <circle fill="red" stroke="blue" stroke-width="2" /> <!-- CSS on inline SVG - only when SVG is inside HTML --> <style> circle { fill: green; } </style> <svg><circle r="40" cx="50" cy="50" /></svg> <!-- currentColor - icon follows parent text color --> <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> <!-- Star renders in navy --> ``` Inline SVG elements are DOM nodes. The browser reads `fill` and `stroke` from either the element's attributes or its computed CSS style, then passes the result to the graphics renderer. For SVGs loaded via `<img>`, none of that applies. ### The external SVG boundary When you load an SVG with `<img src="icon.svg">`, the browser treats it as an opaque image. The SVG's internal DOM is not part of the parent document. CSS selectors from the page never reach inside. This is a browser security boundary, not something you can override with more specific selectors. When you need dynamic colors on an external SVG, the options are: - Embed it inline with `<svg>` directly in the HTML - Use `<object data="icon.svg">` (CSS filters apply to the `<object>` container, not the SVG internals) - Use `<use>` referencing an inline `<symbol>` definition ### When to use each method - **Direct `fill`/`stroke` attributes** for static colors or when you control the SVG source file - **CSS on inline SVG** for hover states, theming, dark mode, and responsive color changes - **`currentColor`** for icon systems where icons should match surrounding text color - **JavaScript** for real-time color changes driven by user interaction or data values ### Common mistakes **Mistake 1: Styling an SVG loaded via `<img>` with CSS** ```html <style> svg circle { fill: red; } </style> <img src="chart.svg" /> <!-- Circle stays its original color. The rule never reaches it. --> ``` The browser does not parse the SVG's internal structure when it is loaded as an image. Fix: embed the SVG inline, or use `<object>`. **Mistake 2: CSS losing to the `fill` attribute** ```html <style> circle { fill: blue; } </style> <svg> <circle fill="red" cx="50" cy="50" r="40" /> <!-- Renders RED. The attribute wins. --> </svg> ``` SVG attributes act like inline styles and have higher specificity than external or embedded CSS rules. This is the first thing to check when a color change does nothing. Either remove the `fill` attribute from the SVG source or add `!important`: `circle { fill: blue !important; }`. **Mistake 3: Setting `color` instead of `fill`** ```html <style> svg { color: red; } </style> <svg><circle cx="50" cy="50" r="40" /></svg> <!-- Circle is not red --> ``` `color` affects text nodes, not SVG shapes. Use `fill: red` directly. The only time `color` influences an SVG shape is when that shape has `fill="currentColor"`. **Mistake 4: Unexpected `currentColor` scope** ```html <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 is RED, circle is BLUE --> </g> </svg> </div> ``` `currentColor` resolves to the `color` value of the nearest ancestor. This is useful for scoped theming, but it catches people off guard the first time. ### Real-world usage - **Heroicons, Feather Icons** - all icons ship with `fill="currentColor"` so they automatically adapt to button, link, and header colors - **D3.js, Recharts** - `fill` and `stroke` are set dynamically on SVG elements based on data values - **Styled-components, Emotion** - theme variables flow into inline SVGs through CSS custom properties - **GSAP, Framer Motion** - animate `fill` and `stroke` for morphing and color transition effects ### Follow-up questions **Q:** Why doesn't CSS work on SVG loaded via `<img>`? **A:** The browser sandboxes external images. The SVG's DOM is not accessible to the parent document, so no selectors, no variables, and no scripts can reach it. This is enforced at the browser level for security. **Q:** Can I use CSS custom properties inside SVG? **A:** Yes, if the SVG is inline. `<circle fill="var(--brand-color)" />` works and is a clean way to theme an icon system from a single CSS variable. External SVGs cannot access variables from the parent page. **Q:** How do I change SVG color on hover? **A:** Use CSS pseudo-classes on inline SVG: `svg path:hover { fill: #2563eb; }`. For an external SVG via `<img>`, the practical options are a CSS `filter` on the `<img>` element or swapping the `src` with JavaScript on the `mouseenter` event. **Q:** (Senior) How would you build a dark mode system for 50 SVG icons without duplicating markup? **A:** Embed all icons inline with `fill="currentColor"`. Set `color` on a wrapper via a CSS custom property: `.icon { color: var(--icon-color); }`. Define the variable per mode: `@media (prefers-color-scheme: dark) { :root { --icon-color: white; } }`. Every icon updates automatically with zero markup changes and no JavaScript. ## Examples ### Static SVG with direct attributes ```html <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> <!-- Blue circle with a darker blue border --> ``` Direct attributes are processed before CSS. Use them for standalone SVG files or any shape whose color should never change based on context. ### Interactive icon button with currentColor ```html <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> Search </button> <!-- Icon is gray by default. On hover: both the text and icon turn blue. One CSS rule (color) controls both. --> ``` Setting `stroke: currentColor` (or `fill: currentColor`) on the `<svg>` ties icon color to the button's text color. Hover, focus, and disabled states all work from a single CSS property on the button, with no changes to the SVG markup.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.