How to Invert Stroke Text Color Depending on Background

How to invert stroke text color depending on background

One idea is to duplicate the text and use CSS variable to define the color so you can easily change them in one place. I used clip-path to hide half of one text and show the other half:

body {

margin: 0;

--c1:#510035;

--c2:#E8E8E8;

}

body:hover {

--c1:red;

--c2:blue;

}

h1 {

font-size: 4.7em;

text-transform: uppercase;

margin: 0;

}

.first {

background:var(--c1);

-webkit-text-stroke: 3px var(--c2);

}

.second {

background:var(--c2);

-webkit-text-stroke: 3px var(--c1);

clip-path:polygon(0% 0%, 50% 0%, 50% 100%,0% 100%);

}

.lp-header {

position:absolute;

top:0;

left:0;

right:0;

min-height:100vh;

box-sizing:border-box;

color: transparent;

z-index: 1;

padding: 50px;

text-align: center;

transition:0.5s;

}
<h1 class="lp-header first">left or right</h1>

<h1 class="lp-header second">left or right</h1>

Invert CSS font-color depending on background-color

There is a CSS property called mix-blend-mode, but it's not supported by IE. I recommend using pseudo elements. If you like to support IE6 and IE7 you can also use two DIVs instead of pseudo elements.

Sample Image

.inverted-bar {

position: relative;

}

.inverted-bar:before,

.inverted-bar:after {

padding: 10px 0;

text-indent: 10px;

position: absolute;

white-space: nowrap;

overflow: hidden;

content: attr(data-content);

}

.inverted-bar:before {

background-color: aqua;

color: red;

width: 100%;

}

.inverted-bar:after {

background-color: red;

color: aqua;

width: 20%;

}
<div class="inverted-bar" data-content="Lorem ipsum dolor sit amet"></div>

SVG Invert stroke colour based on background

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" class="header__wave" 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>

Invert colors inside selection

I cannot see how to do this in a complex case, where the selection contains several HTML elements that might be setting color and background color individually (though of course some complex HTML/CSS parsing must be able to do that but I'm not capable).

However, we can fairly simply deal with the straightforward case where the color and background color are consistent across the parent div of the selection.

On a selection event this snippet reads the computed style of the parent element, calculates the inverse of the color and backgroundColor and sets CSS variables to these which are picked up and used in the selection pseudo element.

document.addEventListener('selectionchange', (e) => {
function invert(color) {
color = color.replace('rgb(', '');
color = color.replace(')', '');
color = color.replace('rgba(', '');
let colors = color.split(',');
let r = colors[0].replace(' ', '');
let g = colors[1].replace(' ', '');
let b = colors[2].replace(' ', '');
let a = (colors.length > 3) ? colors[3].replace(' ', '') : 1;
r = ~r & 255;
g = ~g & 255;
b = ~b & 255;
return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
}
selection = window.getSelection();
if (selection.anchorNode) {
const parent = selection.anchorNode.parentElement;
const style = window.getComputedStyle(parent);
parent.style.setProperty('--color', invert(style.color));
parent.style.setProperty('--background-color', invert(style.backgroundColor));
}
});
.invertSelectionColors::selection {
color: var(--color);
background-color: var(--background-color);
}
<div class="invertSelectionColors" style="background-color: cyan;color:#000000;">
here is some text originally background color cyan and color #000000
</div>
<div class="invertSelectionColors" style="background-color: rgba(255, 0, 0, 0.5);color:#0000ffff;">
here is some text originally background color rgba(255, 0, 0, 0.5) and color #0000ffff
</div>

How to set text overlapping background to be white while overflowing outside to be in different color?

It's not exactly elegant, and you have to be conscious of your margins and padding to make sure the :after element lines up with the base element - but you can then use clip-path and mess with the numbers based on your exact needs to get a polygon shape. For this example I just removed the margins from everything and did a 50% circle for the clip path.

There's probably a better solution, but this should at least get you started. Unfortunately, using blending modes will be tough to get true pure colors, so clip-path with a cloned or pseudo element is a decent bet:

body {

margin: 0;

}

h1 {

font-size: 72px;

font-weight: 800;

max-width: 200px;

color: #2f78e1;

position: relative;

margin: 0;

}

h1:after {

content: "Lorem ipsum dolor sit";

position: absolute;

top: 0;

left: 0;

clip-path: circle(50%);

color: #fff;

height: 200px;

width: 200px;

}

#box {

height: 200px;

position: absolute;

top: 0;

left: 0;

width: 200px;

background: #2f78e1;

z-index: -1;

background-blend-mode: lighten;

border-radius: 50%;

color: blue;

}
<div class="container">

<svg id="box">

<circle></circle>

</svg>

<h1>Lorem ipsum dolor sit</h1>

</div>

Substitute to css outline-color: invert

Perhaps this does the trick for you?

.background {

display: inline-block;

margin: 10px;

padding: 20px;

}

.box {

border: 3px solid white;

height: 100px;

width: 160px;

}

.invert {

mix-blend-mode: difference;

}
<div class="background" style="background: #ff0000">

<div class="box invert"></div>

</div>

<div class="background" style="background: #000000">

<div class="box invert"></div>

</div>

<div class="background" style="background: #ffffff">

<div class="box invert"></div>

</div>

SVG text color with correspond to background

The approach to use clip paths has already been described by squeamish ossifrage's answer. I have put together a working snippet doing it the d3 way:

var svg = d3.select("body")

.append("svg")

.attr({

width: 400,

height: 400

});

var textOut = svg.append("text")

.attr({

x: 120,

y: 66

})

.style({

fill: "black",

stroke: "none"

})

.text("Description");

var rect = svg.append("rect")

.attr({

id: "rect",

x: 50,

y: 50,

width: 100,

height: 20

})

.style({

fill: "limegreen",

stroke: "darkgreen"

});

svg.append("clipPath")

.attr("id", "clip")

.append("use")

.attr("xlink:href", "#rect");

var textIn = svg.append("text")

.attr({

x: 120,

y: 66

})

.style({

fill: "white",

stroke: "none",

"clip-path": "url(#clip)"

})

.text("Description");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


Related Topics



Leave a reply



Submit