htmlcsssvgpseudo-element

How to style an inline SVG within a pseudo-element ::before & ::after?


I am trying to style an SVG within a pseudo-element.

p::before {
  content: url("data:image/svg+xml;charset=UTF-8,<svg xmlns='http://www.w3.org/2000/svg' class='svg-check' viewBox='0 0 20 20'><path fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z' clip-rule='evenodd' /></svg>");
  display: inline-block;
  height: 2rem;
  width: 2rem;
}

.svg-check {
  fill: green;
}
<div>
  <p>First</p>
  <p>Second</p>
</div>

CodePen Sample

My question is :

  1. Is this possible?
  2. If yes, how?
  3. If no, is there any other way to achieve same?

Solution

  • The following are three ways to color SVG in pseudo-elements:

    1. As per this comment, the mask property can be assigned the url() function instead of content or background. The background-color is then assigned the desired color.
      Reference

    2. If the url() function is assigned to the content property, filter functions can determine the SVG color.
      Reference
      Tool

    3. If background (specifically background-image) has the url() function, certain steps can be done manually or by JavaScript to hardcode a [fill] attribute into the url() by encoding it into base64 ASCII.
      Reference
      Tool

    Details are commented in the example. Also refer to this article about SVG data URI.

    /* #1 
    || Define SVG elements as a string. Include a [fill] 
    || attribute and assign it a color. This example
    || has [fill='#D22578'] on <path>.
    */
    const svgString = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='#D22578' fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z' clip-rule='evenodd' /></svg>`;
    
    /* #2
    || Next, encode the string into base64 ASCII.
    */
    const bin2ASCII = btoa(svgString);
    
    /* #3
    || Then interpolate the base64 encoding into a CSS url()
    || function as a string.
    */
    const base64 = `url("data:image/svg+xml;base64,${bin2ASCII}")`;
    
    /* #4
    || Finally, assign the value to a CSS property on
    || the :root (aka <html>). Make sure the CSS property is
    || assigned to the element/pseudo-element as a background.
    || ex. .icon::before { background: var(--base64) }
    */
    document.documentElement.style.setProperty("--base64", base64);
    
    /*
    || This is the value of variable base64:
    
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyMCAyMCc+PHBhdGggZmlsbD0nI0QyMjU3OCcgZmlsbC1ydWxlPSdldmVub2RkJyBkPSdNMTAgMThhOCA4IDAgMTAwLTE2IDggOCAwIDAwMCAxNnptMy43MDctOS4yOTNhMSAxIDAgMDAtMS40MTQtMS40MTRMOSAxMC41ODYgNy43MDcgOS4yOTNhMSAxIDAgMDAtMS40MTQgMS40MTRsMiAyYTEgMSAwIDAwMS40MTQgMGw0LTR6JyBjbGlwLXJ1bGU9J2V2ZW5vZGQnIC8+PC9zdmc+")
    
    || Rather than use JavaScript, we can paste SVG into 
    || an online tool like:
    || https://www.base64encode.org/
    || and paste the results to our CSS. 
    || Set the first <select> form control to: "ASCII".
    */
    :root {
      --base64;
      --utf8: url("data:image/svg+xml;charset=UTF-8,<svg xmlns='http://www.w3.org/2000/svg' class='svg-check' viewBox='0 0 20 20'><path fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z' clip-rule='evenodd' /></svg>");
      font: small-caps 2ch/1.5 "Segoe UI";
    }
    
    code {
      padding: 0.25rem 0.5rem;
      font-family: "Source Code Pro";
      font-variant: normal;
      color: #FFB41F;
      background: #000;
    }
    
    dd+dt,
    dd {
      margin-top: 0.5rem;
    }
    
    dd::before {
      content: '';
      display: inline-block;
      height: 2rem;
      width: 2rem;
      margin: -0.25rem 0.25rem 0 0;
      vertical-align: middle;
      background-size: contain;
    }
    
    /*
    || Assign url() function to mask. Assign color to
    || background-color
    */
    .mask::before {
      mask: var(--utf8) no-repeat;
      mask-size: contain;
      background-color: #FE0000;
    }
    
    /*
    || Use the online tool to get the filter values:
    || https://isotropic.co/tool/hex-color-to-css-filter/
    || Assign the url() function to content
    */
    .filter::before {
      content: var(--utf8);
      filter: invert(7%) sepia(96%) saturate(7103%) hue-rotate(248deg) brightness(111%) contrast(144%);
    }
    
    /*
    || Assign url() function to background.
    */
    .base64::before {
      background: var(--base64) no-repeat;
    }
    <dl>
      <dt><code>mask</code> Shorthand</dt>
      <dd class="mask">Alpha</dd>
      <dt><code>filter</code> Functions</dt>
      <dd class="filter">Beta</dd>
      <dt>Base64 Encoding</dt>
      <dd class="base64">Gamma</dd>
    </dl>