Rule 1: Know Whether Your Icon Is Stroke-Based or Fill-Based
Applying svg { fill: currentColor; } globally in a stylesheet is a classic mistake: on outline libraries like Lucide, Tabler, or Heroicons Outline (which depend on fill="none" stroke="currentColor"), forcing a fill floods the open interior of circles and folders solid! Instead, let each SVG declare currentColor on whichever channel it actually uses, and set only CSS color on the parent button or link.
Rule 2: Two-Color Duotone Icons with CSS Custom Properties
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" class="text-blue-600 dark:text-blue-400">
<!-- Secondary tone reads --icon-tone or falls back to 20% opacity currentColor -->
<circle cx="12" cy="12" r="9" fill="var(--icon-secondary, currentColor)" fill-opacity="0.18" />
<path d="m9 12 2 2 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>Rule 3: Why <img src="icon.svg"> Ignores Page CSS (and Two Workarounds)
For security and caching isolation, browsers treat <img src="icon.svg"> as an external image document—host stylesheets cannot reach inside it. When you need hover or dark-mode color changes:
- Render inline
<svg>/ JSX components (or a same-origin<symbol>sprite) withcurrentColor. - Or convert monochrome icons into a CSS
mask-imagerule via SVG Nexus's CSS & Mask converter sobackground-color: currentColortints the alpha mask.