Question
I want to change the color of an SVG using CSS, but it is not working. I tried applying a fill style, yet the image always stays black.
Here is my code:
<style>
.change-my-color {
fill: green;
}
</style>
<svg>
<image
class="change-my-color"
xlink:href="https://svgur.com/i/AFM.svg"
width="96"
height="96"
src="ppngfallback.png"
/>
</svg>
Why does the SVG remain black, and how can I correctly change its color?
Short Answer
By the end of this page, you will understand why fill does not affect an externally loaded SVG inside an <image> element, and how to correctly style SVG colors using inline SVG, SVG paths, and currentColor. You will also learn common patterns developers use when they need recolorable icons in real projects.
Concept
In SVG, color is often controlled with properties such as fill and stroke.
fillchanges the inside color of shapes.strokechanges the outline color.
However, where the SVG comes from matters.
In your example, the SVG file is loaded through an <image> element:
<svg>
<image xlink:href="icon.svg" />
</svg>
This behaves more like placing an image file inside SVG, not like exposing the internal SVG shapes to CSS. Your CSS can style the <image> element itself, but it cannot reach inside the external SVG file and change the path, circle, or other shape colors.
That is why fill: green; does not recolor the external SVG content.
To change SVG color with CSS, the most common solution is to use inline SVG:
<svg viewBox="0 0 24 24" class="icon">
<path d="..." />
</svg>
Now CSS can target the actual SVG shapes:
.icon {
fill: green;
}
This matters in real programming because SVG icons are everywhere:
- navigation menus
- buttons
- status badges
- charts
- logos
- dark mode themes
If you want flexible styling, hover effects, theme colors, or dynamic states, inline SVG is usually the best choice.
Mental Model
Think of an external SVG file inside <image> like a photo in a picture frame.
- You can move the frame.
- You can resize the frame.
- But you cannot repaint the shapes inside the photo with normal CSS.
Inline SVG is like having the actual drawing instructions on the page.
- You can target the shapes directly.
- You can change their color.
- You can animate them.
- You can respond to hover, active, or theme changes.
So the key idea is:
- External SVG in
<image>or<img>= mostly not directly colorable withfill - Inline SVG = directly colorable with CSS
Syntax and Examples
1. Styling inline SVG with fill
<svg class="icon" viewBox="0 0 24 24" width="96" height="96">
<circle cx="12" cy="12" r="10" />
</svg>
.icon {
fill: green;
}
This works because the SVG markup is directly in the HTML.
2. Styling a specific shape inside SVG
<svg viewBox="0 0 24 24" width="96" height="96">
<circle class="icon-shape" cx="12" cy="12" r="10" />
</svg>
.icon-shape {
fill: green;
}
This is useful when an SVG contains multiple parts with different colors.
3. Using currentColor
A common pattern is to make the SVG follow the text color of its parent.
<button class="icon-button">
<svg class="icon" viewBox="0 0 24 24" width="24" height="24">
<path d="M5 12h14" stroke="currentColor" stroke-width="2" />
</svg>
Save
</button>
.icon-button {
color: blue;
}
Because the SVG uses currentColor, the icon becomes blue automatically.
4. What does not work for external SVG in <image>
<svg>
<image class="change-my-color" href="icon.svg" width="96" height="96" />
</svg>
.change-my-color {
fill: green;
}
This does not recolor the shapes inside icon.svg.
5. Correct approach: paste the SVG inline
If the external file contains something like this:
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 22h20z" />
</svg>
Put it directly in your HTML:
<svg class="warning-icon" viewBox="0 0 24 24" width="96" height="96">
<path d="M12 2L2 22h20z" />
</svg>
.warning-icon {
fill: orange;
}
Now the color can change.
Step by Step Execution
Consider this inline SVG example:
<svg class="icon" viewBox="0 0 24 24" width="50" height="50">
<rect x="4" y="4" width="16" height="16" />
</svg>
.icon {
fill: green;
}
Here is what happens step by step:
- The browser reads the HTML and creates an
<svg>element. - Inside that SVG, it finds a
<rect>shape. - The browser reads the CSS rule for
.icon. - The
<svg>element has classicon, so the rule matches. - The
fill: greenproperty is applied to the SVG. - The
<rect>uses that fill value, so the rectangle is drawn in green.
Now compare that with this external image version:
<svg>
<image class="icon" href="icon.svg" width="50" height="50" />
</svg>
.icon {
fill: green;
}
What happens here:
- The browser reads the outer
<svg>. - It finds an
<image>element that references an external file. - The CSS rule matches the
<image>element. - But the actual drawing inside
icon.svgstays separate. fill: greendoes not reach the shapes inside that external file.- The image displays using its own internal colors, often black if the source SVG is black.
That is the core reason your original code does not work.
Real World Use Cases
Recolorable UI icons
Applications often need icons that change color based on state:
- gray when disabled
- blue when active
- red for errors
- green for success
Inline SVG makes this easy.
Dark mode support
A site may switch from light mode to dark mode. Icons should follow the theme color automatically.
Using currentColor lets icons inherit color from surrounding text or components.
Hover and interaction states
Buttons and links often change icon color on hover:
.button {
color: #444;
}
.button:hover {
color: #0a84ff;
}
If the SVG uses currentColor, the icon changes too.
Status indicators
Dashboards often use SVG for:
- warning triangles
- success checkmarks
- error symbols
- loading shapes
These need dynamic coloring based on data.
Data visualizations
Charts and diagrams built with SVG often rely on fill and stroke to show categories, trends, or thresholds.
Real Codebase Usage
In real projects, developers usually choose one of these patterns:
Inline SVG for icons
This is the most common option when icons need to be styled.
<svg class="icon icon-success" viewBox="0 0 24 24">
<path d="M20 6L9 17l-5-5" fill="none" stroke="currentColor" stroke-width="2" />
</svg>
.icon-success {
color: green;
}
currentColor for theme-friendly icons
This pattern avoids hardcoding colors in the SVG.
.nav-link {
color: #555;
}
.nav-link.active {
color: #1d4ed8;
}
The icon follows automatically if it uses fill="currentColor" or stroke="currentColor".
Component-based apps
In React, Vue, or similar frameworks, developers often store icons as components so they can pass color, size, or class names.
Guarding against hardcoded SVG colors
Many downloaded SVG files contain fixed values like:
<path fill="#000000" d="..." />
This blocks flexible styling. Developers often replace it with:
<path fill="currentColor" d="..." />
or remove the inline fill and style it in CSS.
Validation and cleanup
Before using SVGs in a codebase, developers often:
- remove unnecessary metadata
- simplify paths
- replace fixed fills
- make sizing consistent with
viewBox
This makes icons easier to maintain.
Common Mistakes
1. Trying to style an external SVG loaded with <img> or <image>
Broken example:
<img class="icon" src="icon.svg" alt="icon">
.icon {
fill: red;
}
Why it fails:
filldoes not recolor the internal shapes of the external file.
How to avoid it:
- use inline SVG when you need CSS-based color changes
2. The SVG file has hardcoded fill values
Broken example:
<svg class="icon" viewBox="0 0 24 24">
<path fill="#000000" d="M12 2L2 22h20z" />
</svg>
.icon {
fill: green;
}
Why it may fail:
- the path already has its own fill value
Fix:
<svg class="icon" viewBox="0 0 24 24">
<path d="M12 2L2 22h20z" />
</svg>
or:
<path fill="currentColor" d="M12 2L2 22h20z" />
3. Using fill when the shape is drawn with stroke
Broken example:
<svg class="icon" viewBox="0 0 24 24">
<path d="M5 12h14" stroke="black" stroke-width="2" fill="none" />
</svg>
.icon {
fill: green;
}
Why it fails:
- the visible line uses
stroke, notfill
Fix:
.icon {
stroke: green;
}
or use stroke="currentColor".
4. Forgetting viewBox
Without viewBox, scaling can behave strangely.
Better example:
<svg class="icon" viewBox="0 0 24 24" width="24" height="24">
<circle cx="12" cy="12" r="10" />
</svg>
5. Using outdated xlink:href unnecessarily
Older SVG examples use xlink:href. Modern SVG usually supports href.
Example:
<image href="icon.svg" width="96" height="96" />
If you maintain older code, you may still see xlink:href, but for new code href is usually simpler.
Comparisons
| Approach | Can CSS change SVG color? | Best for | Notes |
|---|---|---|---|
| Inline SVG | Yes | Icons, interactive graphics, themed UI | Most flexible option |
<img src="icon.svg"> | Usually no | Simple display-only images | Easy to use, not good for recoloring |
<svg><image href="icon.svg"></image></svg> | Usually no | Embedding external image content inside SVG | Does not expose inner shapes to CSS |
SVG with currentColor | Yes | Buttons, nav items, text-linked icons | Great for theme and state changes |
Hardcoded fill="#000" inside SVG | Limited | Fixed-color artwork | Harder to reuse |
fill vs stroke
| Property | What it colors | Common use |
|---|---|---|
fill | Inside of shapes | Solid icons, circles, rectangles, paths |
stroke | Outline of shapes | Line icons, borders, checkmarks, arrows |
currentColor vs fixed color
| Option | Benefit | Drawback |
|---|---|---|
currentColor | Inherits from parent text color, easy theming | Requires understanding inheritance |
Fixed color like fill="red" | Simple for one-off graphics | Harder to reuse across themes and states |
Cheat Sheet
Quick rules
- Use inline SVG if you want to style color with CSS.
fillcolors the inside of a shape.strokecolors the outline.- External SVGs loaded via
<img>or<image>are usually not recolorable with CSSfill. currentColormakes an SVG follow the element's text color.
Common patterns
Inline SVG with fill:
<svg class="icon" viewBox="0 0 24 24">
<path d="..." />
</svg>
.icon {
fill: green;
}
Inline SVG with currentColor:
<svg class="icon" viewBox="0 0 24 24">
<path d="..." fill="currentColor" />
</svg>
.icon-wrapper {
color: purple;
}
Stroke-based icon:
<svg class="icon" viewBox="0 0 24 24">
<path d="M5 12h14" stroke="currentColor" stroke-width="2" fill="none" />
</svg>
If color is not changing, check:
- Is the SVG inline?
- Is the visible part using
fillorstroke? - Does the path have a hardcoded
fillorstroke? - Are you targeting the correct element?
- Does the SVG have a proper
viewBox?
Best practice
For reusable UI icons:
- keep SVG inline or as a component
- use
fill="currentColor"orstroke="currentColor" - control color through the parent with CSS
FAQ
Why does fill not work on my SVG image?
Because your SVG is being loaded as an external image. CSS cannot usually style the internal shapes of that file.
Can I change the color of an SVG loaded with <img>?
Not directly with normal fill styling. For easy recoloring, use inline SVG instead.
What is the difference between fill and stroke in SVG?
fill colors the inside of shapes, while stroke colors the outline.
What does currentColor do in SVG?
It tells the SVG to use the current text color of its parent or element, which is very useful for theming.
Why is my inline SVG still black?
The SVG may have hardcoded fill="#000" or stroke="#000" attributes that override your CSS.
Should I use href or xlink:href for SVG images?
For modern code, href is generally preferred. Older examples may still use xlink:href.
What is the best way to build color-changing icons?
Use inline SVG with fill="currentColor" or stroke="currentColor", then control color with CSS.
Mini Project
Description
Build a small status icon panel that displays three SVG icons: success, warning, and error. The goal is to practice using inline SVG and currentColor so each icon can be recolored with simple CSS classes. This mirrors how many real interfaces style icons for alerts, forms, dashboards, and notifications.
Goal
Create a set of inline SVG icons whose colors are controlled entirely through CSS classes.
Requirements
- Display three status items: success, warning, and error.
- Each item must include an inline SVG icon and a text label.
- Use
currentColorso the icon color follows the parent element. - Give each status item a different CSS color.
- Keep the SVG markup valid and scalable with
viewBox.
Keep learning
Related questions
Angular ngClass Conditional Class Binding Explained
Learn how to use Angular ngClass for conditional classes, fix common binding mistakes, and understand why this template error happens.
CSS :not() Selector for Elements Without a Class or Attribute
Learn how to use the CSS :not() selector to target elements that do not have a specific class or attribute, with examples and common pitfalls.
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.