Search code examples
htmlcssreactjsframer-motion

Change text color where the background image moves behind


The background planet moves in a circular area and changes the text color to orange if the image moves behind.

<div>
   <div className={styles.content}>
     <div className={styles.content__title}>
          <h1>
            Explore Your own planet <br /> In{" "}
            <span>our New </span>
            metaverse
         </h1>
      </div>
      <div className={styles.content__description}>
         <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing
          elit, sed do eiusmod tempor incididunt ut labore et
          dolore magna aliqua. Ut enim ad minim veniam
         </p>
      </div>
  </div>
  <div>
     <Planet />
  </div>
</div>

Planet component:

const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);

const handleMouseMove = (e: React.MouseEvent<SVGCircleElement, MouseEvent>) => {
    const rect = e.currentTarget.getBoundingClientRect();
    animate(mouseX, e.clientX - rect.left - rect.width / 2);
    animate(mouseY, e.clientY - rect.top - rect.height / 2);
}

<div className="circle">
            <motion.svg
                width="526"
                height="526"
                viewBox="0 0 526 526"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
            >
                ...
                <motion.circle
                    cx="263"
                    cy="263"
                    r="263"
                    fill="transparent"
                    onMouseMove={handleMouseMove}
                    onMouseEnter={handleMouseMove}
                    onMouseLeave={(e) => {
                        animate(mouseX, 0);
                        animate(mouseY, 0);
                    }}
                    className="circle_detector"
                />
            </motion.svg>
            <motion.div
                className="image"
                style={{
                    translateX: mouseX,
                    translateY: mouseY,
                    transition: "all 3s linear",
                }}
            />
</div>

And background image style:

.image {
        position: absolute;
        width: 320px;
        height: 322px;
        top: calc(526px / 2 - 322px / 2);
        left: calc(526px / 2 - 320px / 2);
        background-image: url("../src/widgets/planet/assets/planet.webp");
        background-position: center;
        background-size: contain;
        background-repeat: no-repeat;
    }

Image what i want The text should change color as the planet moves. To move planet i use framer-motion library. Also video for better understanding: video Is it even possible to do this? I tried this another solution but nothing changed

UPDATE

When I try the blend mode, I get something like this: blend-mode Can I change this bluish color to a specific color?

UPDATE

Here is a link to the website so you can see what I mean Site


Solution

  • You can use mix-blend-mode: multiply to give you something like you are looking for. I've put a layer over the top of the image with mix-blend mode which colors the image and the text have a play about with it. There are a lot of modes you can use, it's worth experimenting with them.

    .container {
      display: flex;
      background: #111;
      color:white;
      position:relative;
    }
    
    .text {
      font-size: 3rem;
      font-weight:bold;
      position: absolute;
      left:3rem;
      top: 2rem;
      z-index:2;
    }
    
    .image {
      position: relative;
      margin: 0 auto;
      display: block;
    }
    
    .image::after {
      position: absolute;
      content:"";
      inset: 0;
      background: darkorange;
      mix-blend-mode: multiply;
      z-index: 3;
    }
    <div class='container'>
      <div class='text'>
      Lorem Ipsum yadda yadda
      </div>
      <div class='image'>
        <img src='https://picsum.photos/id/58/200/300'>
      </div>
    </div>

    MDN reference for mix-blend-mode

    Edited to add background-clip: text example I've created and SVG that's the same size as the container and made it white with a circle of the planet's radius in orange. If you position the SVG over the parent image and use background-clip: text you can make the text appear like you asked.

    See below

    body {
      background-color: #171719
    }
    
    .text {
      font-family: 'Bebas Neue', cursive;
      font-size: 120px;
      
      /* make the div the same size as the parent container */
      height: 640px;
      
      /*We've created an SVG and encoded it (see here https://yoksel.github.io/url-encoder/ for a tool to do that) The SVG is a whie background with an orange circle that we position to overlay on top of the planet image*/  
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1280' height='644'%3E%3Crect x='0' y='0' width='1280' height='644' fill='white' /%3E%3Cellipse cx='960' cy='322' rx='320' ry='322' fill='orange' /%3E%3C/svg%3E");
      
      /*Make the background appear under the text*/
      background-clip: text;
      -webkit-background-clip: text;
      color: transparent;
    }
    
    .image-holder {
      position: relative;
      width: 1280px;
      height: 640px;
    }
    
    img {
      position: relative;
      
      /* push the image 640px across so it appears under the text svg */
      left: 640px;
    }
    
    .text {
      /* just position the text where we want */
      position: absolute;
      display: grid;
      place-items:center;
      inset: 0;
    }
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap" rel="stylesheet">
    
    <div class='image-holder'>
      <img src='https://i.ibb.co/QPdRCgN/planet-1fef4106.webp'>
      <div class='text'>
        <div>Explore Your own Planet</div>
      </div>
    </div>