How can I set mix-blend-mode on an element, but not it's children? Setting the children to the default value of normal
does not seem to work:
The solution on how to avoid mix-blend-mode
affects children:
- Make child element position relative, give it a width and height;
- Create some real or pseudo element inside the child with absolute position, and apply
mix-blend-mode
to it; - Create
inner
element inside the child for your content. Make it's position absolute, and put it on top of other elements;
html
<div class="bkdg">
<div class="blend">
<div class="inner">
<h1>Header</h1>
</div>
</div>
</div>
css
.blend {
position: relative; /* Make position relative */
width: 100%;
height: 100%;
}
.blend::before { /* Apply blend mode to this pseudo element */
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 1;
background-color: green;
mix-blend-mode: multiply;
}
.inner { /* This is our content, must have absolute position */
position: absolute;
z-index: 2;
}
h1 {
color: white;
}
I know this was asked over two years ago, but it could be useful in the future as it could be a better solution than creating pseudo-elements.
There is the CSS isolation
property that allows to choose wether the child element should be rendered in its parent's context (auto
) or as part of a new context, thus without any blend mode applied to it (isolate
).
Check out this page for examples
someone commented that the the whole block is rendered with the effect and that is why you're having the issue. I am able to accomplish what you're are trying to do by removing the h1 from the block, position absolute, and a z-index of 1. here is a jsfiddle to show the effect.
html
<div class="bkdg">
<h1>Header</h1>
<div class="blend">
</div>
</div>
css
.blend {
background-color: green;
mix-blend-mode: multiply;
width: 700px;
height: 35px;
}
h1 {
color: white;
position: absolute;
top: -15px; left: 10px;
z-index: 1;
}
It’s impossible to remove an element’s mix-blend-mode
from its children.
MDN says that mix-blend-mode
:
sets how an element's content should blend with the content of the element's parent and the element's background
To achieve the desired effect, place the child in a separate stacking context and make sure it renders on top of the element with mix-blend-mode
set.
You need two things to make this work:
- Make sure that your opaque content (your text) is not a child of the element that sets the background and the blend mode. For example, with CSS Grid Layout.
- Make sure the text is rendered over, and thus not affected by, the element that sets the background and the blend mode. Setting
mix-blend-mode
on your background will create a stacking context for it, and you may need to give your content its own stacking context to ensure it gets rendered above it.
Position your elements with CSS Grid:
- define a grid container with one auto-sized grid area
- place both the background element and the text element into that one grid area (so that they overlap)
- let the text element dictate the size of the grid area
- have the background element stretch to the size of the grid area, which is dictated by the size of the text element
Then, set isolation: isolate
on the text element to ensure it gets rendered above, and not under the background element.
A working example
.container {
display: grid;
grid-template-areas: 'item';
place-content: end stretch;
height: 200px;
width: 400px;
background-image: url(https://picsum.photos/id/237/400/200);
background-size: cover;
background-repeat: no-repeat;
}
.container::before {
content: '';
grid-area: item;
background-color: seagreen;
mix-blend-mode: multiply;
}
.item {
grid-area: item;
isolation: isolate;
color: white;
}
h1,
p {
margin: 0;
padding: 10px;
}
<div class="container">
<div class="item">
<h1>HEADLINE</h1>
<p>Subhead</p>
</div>
</div>
An important note if you're using the excellent pseudoelement ::before/::after solution posted by Rashad Ibrahimov.
I found that I had to remove z-index from the parent element and apply it only to the pseudoelements and child elements before mix-blend-mode: multiply
would work.
For example
#wrapper {
position: relative;
}
#wrapper .hoverlabel {
position: absolute;
bottom: 0;
left: 0;
right: 0;
/* z-index: 90; Uncomment this to break mix-blend-mode. Tested in Firefox 75 and Chrome 81. */
}
#wrapper .hoverlabel::before {
position: absolute;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
mix-blend-mode: multiply;
z-index: 90;
background-color: rgba(147, 213, 0, 0.95);
}
© 2022 - 2024 — McMap. All rights reserved.