Change text color black to white on overlap of bg
Asked Answered
K

3

13

I have a div that is positioned absolute with a background color gradient. I have this text on it that I want to change to the color white as I scroll the text up.

I'm using the 'mix-blend-mode' property to achieve this currently but I can't find any setting that will turn the text from black to white. Has anyone done this before or can think of a trick I can do?

image text change on scroll

.bg-container {
  position: fixed;
  top: -30px;
  left: 0;
  width: 100px;
  height: 100px;
}

.gradient-background {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 200px;
  background-image: linear-gradient(to bottom, rgb(100, 182, 240) 15%, rgb(81, 155, 244));
  transform: skewY(-15deg);
}

.scroll-content {
  position: absolute;
  top: 50px;
}

.scroll-content p {
  color: #000;
  mix-blend-mode: overlay;
}

/*hack for iOS*/
.scroll-content p:after{
    content: '\200c'
}
<div class="bg-container">
  <div class="gradient-background">
    &nbsp;
  </div>
</div>
<div class="scroll-content">
  <p> abc 1 </p>
  <p> abc 2 </p>
  <p> abc 3 </p>
  <p> abc 4 </p>
  <p> abc 5 </p>
  <p> abc 6 </p>
  <p> abc 7 </p>
  <p> abc 8 </p>
  <p> abc 9 </p>
  <p> abc 10 </p>
  <p> abc 11 </p>
  <p> abc 12 </p>
  <p> abc 13 </p>
  <p> abc 14 </p>
  <p> abc 15 </p>
  <p> abc 16 </p>
  <p> abc 17 </p>
  <p> abc 18 </p>
  <p> abc 19 </p>
</div>

*edit 1: Changed my example snipet code. The background gradient isn't just a rectangular div. It's slanted a bit and that's what makes it so difficult. So the text becomes two-toned at the boundary.

*edit 2 for clarity: I want the text to be black (#000 solid) when it is over the white background and white (#FFF solid) when it is over the gradient/image. My content is scroll-able text as in the code example.

*edit 3: iOS Safari incompatible unless you do the following hack. Add the zero width space &#8203 ; to every text element in order to make it work. This can be done easily with a CSS property as i show added in the CSS markup.

Kuhlman answered 23/2, 2019 at 4:57 Comment(2)
you should be able to transform solid color to gradient (like this one for example : https://mcmap.net/q/871407/-splitting-text-color-with-css-when-compared-to-the-background) .. in case you face issues, tell meJackshaft
Hey Temani, Yes I could do that if that was the affect I wanted to achieve but it isn't. I want the text to be black (#000 solid) when it is over the white background and white (#FFF solid) when it is over the gradient/image. My content is scroll able too so any solution that just assumes an absolute position won't work.Kuhlman
J
6

You can use gradient to color the text. The trick is to have this gradient similar to your shape (same degree and coloration change at the edge of the shape). Since your skewed element is fixed, you need to make the gradient to also be fixed to create the magic effect of text scrolling:

.gradient-background {
  position: fixed;
  top: 0;
  left: 0;
  width: 100px;
  height: 200px;
  background-image: linear-gradient(to bottom, rgb(100, 182, 240) 15%, rgb(81, 155, 244));
  transform: skewY(-15deg);
  transform-origin:left;
}

.scroll-content {
  position: absolute;
  top: 50px;
  /* 165deg = 180deg - 15deg   */
  background: linear-gradient(165deg, #fff 195px,#000 195px) fixed;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
<div class="gradient-background">
</div>
<div class="scroll-content">
  <p> abc 1 </p>
  <p> abc 2 </p>
  <p> abc 3 </p>
  <p> abc 4 </p>
  <p> abc 5 </p>
  <p> abc 6 </p>
  <p> abc 7 </p>
  <p> abc 8 </p>
  <p> abc 9 </p>
  <p> abc 10 </p>
  <p> abc 11 </p>
  <p> abc 12 </p>
  <p> abc 13 </p>
  <p> abc 14 </p>
  <p> abc 15 </p>
  <p> abc 16 </p>
  <p> abc 17 </p>
  <p> abc 18 </p>
  <p> abc 19 </p>
</div>
Jackshaft answered 23/2, 2019 at 20:16 Comment(6)
Ahh when you said color the text gradient in the comment I thought you meant like the gradient of my background and then use the invert mix blend mode property which would get the white but make the black text my gradient color. This is a great solution! thank you! Now that you say it sounds so obviousKuhlman
@Kuhlman yes exactly ;) but I admit it's not trivial especially that there is the fixed feature also so I reopened and added an answerJackshaft
You're a life saver. This was driving me crazy! I was almost going to just change the style of the page at this pointKuhlman
@Kuhlman by the way pay attention to the suport: developer.mozilla.org/en-US/docs/Web/CSS/… .. I will probably add another way later ;)Jackshaft
WOW, great idea my friendClannish
Just an extra note. This does not work on IOS safari. That is unless you look at this thread: #44964478 You have to add a zero width space '&#8203;' to all p elements to make it work for iOS safari...Kuhlman
C
2

You could do this with some javascript:

$(document).ready(function() {
  $(window).scroll(function() {
    var bgHeight = $('.bg-container').height();
    var scroll = $(window).scrollTop();
    $('.scroll-content p').each((i, el) => {
      var pPos = $(el).offset().top;
      var pHeight = $(el).height();

      if (pPos < (scroll - pHeight + bgHeight)) {
        $(el).removeClass('black');
        $(el).addClass('white');
      } else {
        $(el).addClass('black');
        $(el).removeClass('white');
      }
    });
  })
})
.bg-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
}

.gradient-background {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  background-image: linear-gradient(to bottom, rgb(1, 55, 124) 15%, rgb(81, 155, 244));
}

.scroll-content {
  position: relative;
  z-index: 99999;
  font-family: neuzeit-grotesk, sans-serif;
  font-weight: 700;
}

.white {
  color: #fff;
}

.black {
  color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="bg-container">
  <div class="gradient-background">
    &nbsp;
  </div>
</div>
<br/><br/><br/><br/><br/><br/>
<div class="scroll-content menu_black">
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
  <p>asdf</p>
</div>
Counterwork answered 23/2, 2019 at 6:53 Comment(3)
Sorry, I re-did my example to match my picture. The boundary isn't horizontal its actually diagonal so the text becomes two-toned at the boundary. If it was horizontal this would definitely workKuhlman
can you please explain what this code does? (pPos < (scroll - pHeight + bgHeight))Siderolite
@BearNithi The <p/> position is less than (current scroll in px - <p/> height + the gradient height)Counterwork
B
1

You can measure with JavaScript and apply styles to tags that fall inside the range you want, but you can also do something very simple to make the text readable (this falls under “some other trick I can do”):

.scroll-content {
  text-shadow: 0 0 3px white;
}

This will only show up when it’s over the blue background, and disappear over the white background. This does depend on the effect you want to achieve, though.

Even with a JavaScript implementation, you might consider this for progressive enhancement (for JS-less users).

Bickering answered 23/2, 2019 at 5:46 Comment(5)
The text won't change to white though, which is what the OP asks for. It'll only become visible under the gradient.Cephalometer
Right, which is I why I note it’s just under the broad category of a related trick—if he is worried primarily about readability, etc.Bickering
Added a JS implementation, but flying blind on mobile. Will test ASAP.Bickering
Don't have time to test JS, and it's barely more than pseudocode, so deleting that part--but it's in the edit history if anyone wants to try it out or use it as a starter.Bickering
Appreciate the idea, but not the affect I want to achieve. I wouldn't mind a JS solution but I dont think one will exist. I think the solution will be some kind of series of filters and mix-background-modes. Maybe I'll have to duplicate the text content and overlay it. Maybe i have to apply the isolation: isolate property to some divs. Still haven't figured it out :(Kuhlman

© 2022 - 2024 — McMap. All rights reserved.