3

I'm trying to achieve something with mix-blend-mode and I'm wondering if it's possible. I want to use mix-blend-mode to create a "multiply" effect, while keeping the text within it a solid white. I have seen similar issues discussed here, but slightly different than my situation, I believe...

My (simplified) HTML:

    <div class="box">
            
            <div class="content">
                
                <div class="container">
                    <h1 class="header">HEADLINE</h1>
                    <div class="description"><p>Subhead</p></div>
      </div>
      
        </div> <!-- .content -->
            
    </div>

...and my CSS:

.box {
  display: flex;
align-items: flex-end;
    height: 300px;
width: 700px;
    background-image: url(https://heroshockey.com/wp2021/wp-content/uploads/2021/07/program-billboards-future-stars.jpg);
background-size: cover;
background-repeat: no-repeat;
    }
    
    
.content {
  float: left;
  width: 100%;
}

.container {
background-color: red;
 mix-blend-mode: multiply;
}

h1, p {
  color: white;
  margin: 0;
  padding: 10px;
}

Here's a fiddle of the result:

https://jsfiddle.net/cosmocanuck/7zhwgo0s/55/

But I need the text to remain white, not "cut out".

I'm trying to follow Rashad's response here:

Remove mix-blend-mode from child element

But my situation, while very close, is somewhat different (including using flexbox to bottom-align the element containing the text), and so far I've failed to crack this one despite many attempts.

Can anyone point me in the right direction? Thanks!

Adam Abrams
  • 107
  • 1
  • 11

1 Answers1

3

Make sure the blended background and the text are in separate stacking contexts, and that the text is rendered over the background, not under it.

The reason your current code doesn’t work is that the text element is a child of the container element that sets the mix-blend-mode. mix-blend-mode will blend all of the content of the container, including the text — there’s no escaping that.

You need two things to make this work:

  1. Make sure that the text is not a child of the element that sets the background and the blend mode.
  2. Make sure the text is rendered over, and thus not affected by, the element that sets the background and the blend mode.

The challenge is that the size of the background must be dependent on the size of the content. One way to do this is with CSS Grid Layout:

  • define one auto-sized grid area
  • place both the background and the text into that one area (so that they overlap)
  • let the text dictate the size of the area
  • have the background stretch to the size of the area, which is dictated by the size of the text

Then, set isolation: isolate on the text element to ensure it gets rendered above, and not under the background element.

.container {
  display: grid;
  grid-template-areas: 'item';
  place-content: end stretch;
  height: 300px;
  width: 700px;
  background-image: url(https://heroshockey.com/wp2021/wp-content/uploads/2021/07/program-billboards-future-stars.jpg);
  background-size: cover;
  background-repeat: no-repeat;
}

.container::before {
  content: '';
  grid-area: item;
  background-color: red;
  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>
Andy Jakubowski
  • 474
  • 2
  • 4
  • Thanks so much! I've worked mainly with flexbox but will be digging into grid as well to better understand its workings. Quick followup: my intention is to have that red box (.item) rise to full height of the photo when one rolls over .container, turning it entirely red. I assume I'd just change the 'place-content' rule on hover to a value that makes it full height? – Adam Abrams Jul 26 '21 at 21:12
  • Never mind, I got it working, by adding ` .programbox:hover .title-info { height: 300px; transition: 1s; }` However, the transition is ignored. What might I be doing wrong? – Adam Abrams Jul 26 '21 at 21:57
  • If you’re okay with an immediate transition without animation, then setting something like `place-content: stretch` on your grid container should work. The reason `transition` seems to be ignored in your example is that `place-content` is not an animatable property. You can search for any CSS property on MDN and look for **Animation type**. If it says *discrete*, that won’t transition smoothly. – Andy Jakubowski Jul 27 '21 at 06:44
  • Right now the size of the red box depends on the “automatic” size of your headline and subheading. Unfortunately, it’s not easy to animate anything that’s automatically sized in CSS. Check out [Using CSS Transitions on Auto Dimensions](https://css-tricks.com/using-css-transitions-auto-dimensions) for details. If you can hardcode the total height of your headline and subheading, then you should be able to animate them smoothly. But yeah, that will require a change to your current setup. – Andy Jakubowski Jul 27 '21 at 06:50
  • Thanks for the followup Andy! I evolved this code in a later iteration: https://stackoverflow.com/questions/68536957/get-stacked-divs-to-stick-to-the-bottom-with-css-grid - and got an answer that works in the revised code. – Adam Abrams Jul 28 '21 at 04:11