skip to Main Content
:root {
  --logo-color: red;
  --text-color: blue;
}

* {
  color: var(--text-color)
}

.logo{
  color: var(--logo-color);
} 
<svg
 class="logo"
 xmlns="http://www.w3.org/2000/svg"
 width="24"
 height="24"
 viewBox="0 0 24 24"
 fill="none"
 stroke="currentColor"
 stroke-width="2"
 stroke-linecap="round"
 stroke-linejoin="round"
>
   <circle cx="12" cy="5" r="3" />
   <line x1="12" y1="22" x2="12" y2="8" />
   <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
</svg>         

I attempted to modify the color of an SVG using the color property in my CSS file. I selected the .logo class and anticipated the logo to appear in red. However, it ended up being displayed in blue, as if the generic CSS (0-0-0) had higher precedence than the class-specific styles (0-1-0). And if I remove the color property from the generic block, then it works normally.

2

Answers


  1. in SVG elements colors must be set by fill property.

    :root {
      --logo-color : red;
      --text-color : blue;
      }
    * {
      color : var(--text-color);
      }
    .logo{
      fill  : var(--logo-color);
      } 
    svg {
      width  : 150px; 
      height : 150px; 
      }
    <svg class="logo" viewBox="0 0 24 24"
     fill="none"
     stroke="currentColor"
     stroke-width="2"
     stroke-linecap="round"
     stroke-linejoin="round"
    >
       <circle cx="12" cy="5" r="3" />
       <line x1="12" y1="22" x2="12" y2="8" />
       <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>

    You can also use in CSS stroke : var(--text-color);
    instead of actual svg property stroke="currentColor"

    :root {
      --logo-color : red;
      --text-color : blue;
      }
    svg {
      width           : 150px; 
      height          : 150px;
      fill            : var(--logo-color);
      stroke          : var(--text-color);
      stroke-width    : 2;
      stroke-linecap  : round;
      stroke-linejoin : round;
      }
    svg path {
      stroke          : darkgreen;
      }
    <svg viewBox="0 0 24 24" >
     <circle cx="12" cy="5" r="3" />
     <line x1="12" y1="22" x2="12" y2="8" />
     <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>
    Login or Signup to reply.
  2. Beware asterisk (*)

    The culprit in your code is that even though * has the weakest specificity, it actually matches everything, not only the svg element (that by itself does not "draw" anything), but also all its descendants (that do the actual drawing). So basically your explicit

    svg  { color: red; }
    

    has no effect, because its children (circle, line and path) elements are all then again matched by the preceding

    * { color: blue; }
    

    so the color: red that would otherwise be inherited from the parent is there overridden to blue from *. In a simplified sample:

    * {
      color: blue;
    }
    
    svg {
      color: red;
    }
    
    html { color-scheme: light dark; }
    <svg
     width="24"
     height="24"
     viewBox="0 0 24 24"
     fill="none"
     stroke="currentColor"
     stroke-width="2"
     stroke-linecap="round"
     stroke-linejoin="round"
    >
       <circle cx="12" cy="5" r="3" />
       <line x1="12" y1="22" x2="12" y2="8" />
       <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>

    How to fix – even more force

    There are several ways how to cope with this. One could be overriding general child selector in the more specific selector: svg * (.logo *) into your CSS

    * {
      color: blue;
    }
    
    svg * {
      color: red;
    }
    
    html { color-scheme: light dark; }
    <svg
     width="24"
     height="24"
     viewBox="0 0 24 24"
     fill="none"
     stroke="currentColor"
     stroke-width="2"
     stroke-linecap="round"
     stroke-linejoin="round"
    >
       <circle cx="12" cy="5" r="3" />
       <line x1="12" y1="22" x2="12" y2="8" />
       <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>

    Why it works

    Fact that CSS color property affects your strokes is indeed set by SVG’s root node stroke="currentColor" attribute, that makes SVG and all its children copy the computed color value into stroke (unless explicitly told otherwise). It is usually a good practice to do this and not copy colour values to stroke and/or fill.

    Best practice (in general)

    Best practice would probably be not using * at all and let implicit color value inheritance do its work:

    html {
     background-color: darkslategray;
     color: tan;
    }
    
    .red {
      color: red;
    }
    
    /*
    Just for brevity.
    It is always better to keep SVG presentational attributes in the document
    rather than in CSS; *especially* dimensions and fills/strokes.
    */
    svg {
     width: 24px;
     height: 24px;
     fill: none;
     stroke: currentColor;
     stroke-width: 2;
     stroke-linecap: round;
     stroke-linejoin: round;
     vertical-align: text-bottom;
    }
    Text, normal SVG:
    
    <svg viewBox="0 0 24 24">
       <circle cx="12" cy="5" r="3" />
       <line x1="12" y1="22" x2="12" y2="8" />
       <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>,
    
    "red" SVG:
    
    <svg class="red" viewBox="0 0 24 24">
       <circle cx="12" cy="5" r="3" />
       <line x1="12" y1="22" x2="12" y2="8" />
       <path d="M5 12H2a10 10 0 0 0 20 0h-3" />
    </svg>.

    * in general is rarely optimal solution for any task. Besides introducing potential "footguns" like this one, it can even be slightly detrimental for performance.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search