Home > Mobile >  SVG Invert stroke colour based on background
SVG Invert stroke colour based on background

Time:06-22

I have an SVG with a stroke which I want to invert to white when the background underneath it is blue.

Here's the effect I'm aiming for

The grey is a set colour from a CSS variable.

SVG:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="25px" viewBox="0 0 25 210">
   <g>
     <path d="M -678 692 L 702 692" fill="none" stroke-width="5" stroke-miterlimit="10" stroke-dasharray="15 15" transform="rotate(270,12,692)" pointer-events="all"/>
   </g>
</svg>

I've already attempted to add two separate SVGs; one having a white stroke for the blue section and another being grey for the body however the gap between the SVGs changes on different screen sizes which I do not want.

Using two SVGs

I've also attempted to use a combination of the CSS filter, backdrop-filter and mix-blend-mode properties however I was unable to get the correct effect, as filter affects the whole SVG and backdrop-filter does not modify the path's stroke colour.

header {
    display: block;
}

.header__nav-wrapper {
    background: -webkit-gradient(linear, left top, right top, from(#122F76), to(#1941A2));
    background: linear-gradient(0.25turn, #122F76, #1941A2);
    padding: 2.5rem 8rem 0 8rem;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
        height: 150px;
}

.header__wave {
    display: block;
    position: relative;
    width: 100%;
}

.top-line {
      position: relative;
    width: 100%;
    height: 100px;
}

.top-line__line--left {
    left: 200px;
    top: -200px;
}

.top-line__line {
    position: absolute;
    stroke: #999;
    z-index: 999;
}
<header >
  <div ></div>
  <!-- Include svg wave -->
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.1" viewBox="0 0 1920 80">
    <defs>
      <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="mx-gradient-122f76-1-1941a2-1-e-0">
        <stop offset="0%" style="stop-color: rgb(18, 47, 118); stop-opacity: 1;" />
        <stop offset="100%" style="stop-color: rgb(25, 65, 162); stop-opacity: 1;" />
      </linearGradient>
    </defs>
    <g>
      <path d="M 0 0 L 1920 0 L 1920 68 Q 1440 46.4 960 68 Q 480 89.6 0 68 L 0 12 Z" fill="url(#mx-gradient-122f76-1-1941a2-1-e-0)" pointer-events="all" />
    </g>
  </svg>
</header>
<div >
  <div >
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="25px" viewBox="0 0 25 400">
      <g>
        <path d="M -678 692 L 702 692" fill="none" stroke-width="5" stroke-miterlimit="10" stroke-dasharray="15 15" transform="rotate(270,12,692)" pointer-events="all"/>
      </g>
    </svg>
  </div>
</div>

Here's a CodePen link if you need to look at the code.

If possible I'd really appreciate a CSS-only approach however I'm more than happy to use JavaScript if need be.

Thanks!

CodePudding user response:

In this example I use the dotted line as a mask on two <rect>. Beneath (defined first) are two <rect> that has the color that the dotted line is supposed to have.

The wave is also define as a mask and can be reused on the two <rect> that define the upper part of the SVG.

<svg xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 200 80">
  <defs>
    <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="g1">
      <stop offset="0%" stop-color="navy" stop-opacity="1" />
      <stop offset="100%" stop-color="navy" stop-opacity=".2" />
    </linearGradient>
    <mask id="line">
      <rect x="0" y="0" width="200" height="80" fill="white" />
      <line x1="100" y1="0" x2="100" y2="80" stroke="black" stroke-width="2" stroke-dasharray="5 2" />
    </mask>
    <mask id="wave">
      <rect width="200" height="31" fill="white" />
      <path transform="translate(0 30)" fill="white" d="M 0 0 L 200 0 L 200 7 Q 150 5 100 7 Q 50 9 0 7 Z" />
    </mask>
  </defs>
  <rect fill="gray" width="200" height="79" />
  <rect fill="white" width="200" height="80" mask="url(#wave)" />
  <g mask="url(#line)">
    <rect fill="white" width="200" height="80" />
    <rect fill="url(#g1)" width="200" height="80" mask="url(#wave)" />
  </g>
</svg>

CodePudding user response:

You should add and change the stroke property to be in the <g> element instead of <path>, and then change it match the currentColor, which means it will take the current assigned color property from css.

Here is an example of how you can do it:

.icons {
  width: 25px;
  height: 100%;
}

div {
  position: relative;
  width: 100%;
  height: 100px;
}

div svg {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

div.blue {
  background: blue;
}

div.blue svg {
  color: white;
}

div.white svg {
  color: black;
}
<body>

  <svg style="display: none;">
     <g id="mySvg" viewBox="0 0 25 210" fill="none" stroke="currentColor" stroke-width="5" stroke-miterlimit="10" stroke-dasharray="15 15">
       <path d="M -678 692 L 702 692" transform="rotate(270,12,692)" pointer-events="all"/>
     </g>
  </svg>
  
  <div >
      <svg ><use href="#mySvg"/></svg>
  </div>
  <div >
      <svg ><use href="#mySvg"/></svg>
  </div>

</body>

  • Related