You can do it in one single step, using luminosity as the blend mode.
In this mode, luminosity is taken from the front layer(the image), and the hue and saturation are taken from the background (here, a solid color)
The following demo gives you also the posibility to asign the color filter thru the class
.test {
width: 400px;
height: 200px;
margin: 10px;
background-size: cover;
background-image: url(http://placekitten.com/1000/750);
}
.test:hover {
background-blend-mode: luminosity;
}
.red {
background-color: red;
}
.green {
background-color: greenyellow;
}
<div class="test red"></div>
<div class="test green"></div>
Another solution, where black in the image gives full saturated color (instead of black). A little bit more complex to set up, but achievable.
.test {
width: 400px;
height: 200px;
background-size: cover;
background-color: white;
background-image: linear-gradient(red, red), url(http://placekitten.com/1000/750);
background-blend-mode: screen, luminosity;
}
<div class="test"></div>
A way to have this effect as a reusable class. The image is already on the element, and we just set the class to set the effect and a separate class for the color.
So the sequence needs to be:
- first layer = white
- second layer the image, with blend set to luminosity. This way, the luminosity of the image is combined with white, giving white for high luminosity and black for low luminosity (i.e. a grayscale filter)
- third layer, a solid color, with blend set to screen. this keeps the white as white, but changes black to the color.
We need to use a pseudo element for the final blend, to make it easy to set all this with an independent class. this will be set with mix-blend instead of background-blend :
#cat {
width: 760px;
height: 560px;
background-image: url(http://placekitten.com/1000/750);
}
.test {
background-color: white;
background-position: 0px 0px;
background-size: cover;
background-blend-mode: luminosity;
position: relative;
}
.test:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
mix-blend-mode: screen;
pointer-events: none;
}
.blue:after {
background-color: blue;
}
<div class="test blue" id="cat"></div>