Search code examples
htmlcssbackground-image

how to create knockout text on a background image so that text can animate over the image


I'd like to have a background image that only shows through knockout text and then have that text animate from the top of the page to the bottom of the page, showing the different parts of the background image as the text moves.

I know how to make knockout text:

#screen1 h1 {
    display:block;
    margin: auto;
    font-family: 'proxima-nova', sans-serif;
    background-image: url('../img/my-image.jpg');
    background-clip: text;
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    font-size: 12rem;
    font-weight: 800;
}

But what I want is more like a background image on #screen1 that only shows through on the knockout text. So when you animate the knockout text, it shows different parts of the background image.

html:

<div id="screen1" >
<div style="">
<h1>MY TEXT</h1>
</div>  
</div>

CSS :

#screen1 {
    background: url(../img/my-image.jpg) no-repeat; 
    background-size: cover;
    overflow: hidden;
}
#screen1 h1 {
    display:block;
    margin: auto;
    font-family: 'proxima-nova', sans-serif;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    font-size: 12rem;
    font-weight: 800;
}

But this just shows the background image. I sense I'm close.


Solution

  • I'd like to have a background image that only shows through knockout text and then have that text animate from the top of the page to the bottom of the page, showing the different parts of the background image as the text moves.

    You can animate the text while revealing the background image:

    body {
     margin: 0;
     background-color: lightblue;
     overflow: hidden;
    }
    
    h1 {
      display: flex;
      justify-content: center;
      height: 100vh;
      margin: auto;
      font-family: 'proxima-nova', sans-serif;
      background: url('https://placekitten.com/g/200/300') no-repeat;
      background-size: cover;
      background-clip: text;
      -webkit-text-fill-color: transparent;
      -webkit-background-clip: text;
      font-size: 5rem;
      line-height: 5rem;
      font-weight: 800;
      padding-top: 0;
      animation: animate 5s linear infinite;
    }
    
    @keyframes animate {
      to {
        padding-top: calc(100vh - 6rem);
      }
    }
    <h1>Text</h1>


    You can do the same thing with the markup that has the #screen1 and the h1 nested within by inheriting the background to the h1 and then having the clip background effect - see demo below:

    body {
      margin: 0;
    }
    
    * {
      box-sizing: border-box;
    }
    
    #screen1 {
      background: url('https://placekitten.com/g/200/300') no-repeat, lightblue;
      background-size: 0; /* don't show the background yet */
      height: 100vh;
      overflow: hidden;
    }
    
    #screen1>div {
      background: inherit;
      /* background size is still zero */
      height: 100%;
    }
    
    #screen1 h1 {
      display: flex;
      justify-content: center;
      margin: 0;
      background: inherit;
      /* now show the background */
      background-size: cover;
      font-family: 'proxima-nova', sans-serif;
      background-clip: text;
      -webkit-text-fill-color: transparent;
      -webkit-background-clip: text;
      font-size: 5rem;
      line-height: 5rem;
      font-weight: 800;
      padding-top: 0;
      animation: animate 5s linear infinite;
      height: 100%;
    }
    
    @keyframes animate {
      to {
        padding-top: calc(100vh - 5rem);
      }
    }
    <div id="screen1">
      <div>
        <h1>MY TEXT</h1>
      </div>
    </div>