1

The Goal:

A gradient background that extends the 100vh and changes as the user scrolls.

More specifically:

  • The page is divided into multiple sections each of them with a height of 100vh.
  • Each scroll scrolls a whole section.
  • The "main" background's height should be number of sections * 100vh.
  • Here's the catch: an overlay or mask that "shows" only a part of the "main" background but does not scroll as the section scrolls, all while keeping the sections' content on the front.


Example || CodePen:

:root {
      --background-def: #2f3542;
    }

    body {
      background: linear-gradient( to bottom, #b721ff, #2af598, #fec051, #fee140, #fa709a);
      background-size: 100%;
      background-repeat: no-repeat;
      margin: 0;
    }

    body:before {
      content: "";
      position: fixed;
      top: 0;
      bottom: 0;
      width: 100%;
      z-index: -1;
      
      /*Original CodePen*/
      // background: linear-gradient(to right bottom, rgba(255,0,0,0.2), #21D4FD );
      
      /*What I would like to achieve*/
      // background: radial-gradient(
      //  at 80vw 80vh,
      //  transparent,
      //  rgba(47, 53, 66, 0.1),
      //  rgba(47, 53, 66, 0.2),
      //  rgba(47, 53, 66, 0.3),
      //  rgba(47, 53, 66, 0.4),
      //  rgba(47, 53, 66, 0.5),
      //  rgba(47, 53, 66, 0.6),
      //  rgba(47, 53, 66, 0.7),
      //  rgba(47, 53, 66, 0.8),
      //  rgba(47, 53, 66, 0.9),
      //  #2f3542 60%
      // );
      
      /*OR using a mask*/
      -webkit-mask-image: radial-gradient( farthest-corner at 80vw 80vh, transparent, black 40%);
      background: var(--background-def);
    }

    // Not demo related
    html {
      margin: 0;
      font-family: "Muli", sans-serif;
      font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
    }

    #container {
      background-color: rgba(255, 255, 255, 0.5);
      margin: 80px 10%;
      padding: 30px 60px;
      border-radius: 20px;
      box-shadow: 0 3px 26px 0 rgba(0, 0, 0, 0.20);
    }
<div id="container">
  <header>
    <h1>Scrolling Gradient</h1>
    <p>I decided to adapt the <a target="_blank" href="https://codepen.io/MadeByMike/pen/ZOrEmr">CSS Only Scroll Indicator</a> technique to make a background gradient that canges with scroll position. The top right corner of the gradient changes while the
      bottom right remains the same. This works by overlaying 2 gradients, The first is a top-to-bottom gradient with a height of the content. This contains the colors you want to cycle through. The other is a top-left, to bottom-right gradient from transparent
      to a solid color. This gradient is fixed to the viewport dimensions and pulled behind text, similar to the scroll indicator.</p>
  </header>

  <main>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur.</p>
    <h3>Tristique Aenean Etiam Cras</h3>
    <p>Donec id elit non mi porta gravida at eget metus. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Donec sed odio dui. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel
      scelerisque nisl consectetur et.</p>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
    <ul>
      <li>Ullamcorper Aenean Ornare</li>
      <li>Ridiculus Lorem Malesuada Consectetur</li>
      <li>Aenean Tristique Sit Lorem Purus</li>
      <li>Vehicula Egestas Mollis Cursus Nibh</li>
    </ul>
    <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean
      lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p>
    <h3>Bibendum Aenean Dapibus Tristique</h3>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
    <ul>
      <li>Ullamcorper Aenean Ornare</li>
      <li>Ridiculus Lorem Malesuada Consectetur</li>
      <li>Aenean Tristique Sit Lorem Purus</li>
      <li>Vehicula Egestas Mollis Cursus Nibh</li>
    </ul>
    <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean
      lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p>
    <h2>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</h2>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur.</p>
    <h3>Tristique Aenean Etiam Cras</h3>
    <p>Donec id elit non mi porta gravida at eget metus. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Donec sed odio dui. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel
      scelerisque nisl consectetur et.</p>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
    <ul>
      <li>Ullamcorper Aenean Ornare</li>
      <li>Ridiculus Lorem Malesuada Consectetur</li>
      <li>Aenean Tristique Sit Lorem Purus</li>
      <li>Vehicula Egestas Mollis Cursus Nibh</li>
    </ul>
    <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean
      lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p>
    <h3>Bibendum Aenean Dapibus Tristique</h3>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
    <ul>
      <li>Ullamcorper Aenean Ornare</li>
      <li>Ridiculus Lorem Malesuada Consectetur</li>
      <li>Aenean Tristique Sit Lorem Purus</li>
      <li>Vehicula Egestas Mollis Cursus Nibh</li>
    </ul>
    <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean
      lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p>
    <h3>Tristique Aenean Etiam Cras</h3>
    <p>Donec id elit non mi porta gravida at eget metus. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Donec sed odio dui. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel
      scelerisque nisl consectetur et.</p>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
    <ul>
      <li>Ullamcorper Aenean Ornare</li>
      <li>Ridiculus Lorem Malesuada Consectetur</li>
      <li>Aenean Tristique Sit Lorem Purus</li>
      <li>Vehicula Egestas Mollis Cursus Nibh</li>
    </ul>
    <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean
      lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p>
    <h3>Bibendum Aenean Dapibus Tristique</h3>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et
      magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed
      posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>

  </main>
</div>

The Challenge: replicating this effect with Fullpage.js.

Sidenote: I have already contacted the creator of fullpage.js, you can see the issue here.
In order to give basic knowledge needed to better understand the problem, I do go into detail here. But mainly as a brief introduction to fullpage.js.

Please, feel free to skip right to the heart of the challenge by scrolling down to the section titled "Second bump".

Basic structure:

<div id="fullpage">
    <div class="section">One</div>
    <div class="section">Two</div>
    <div class="section">Three</div>
    <div class="section">Four</div>
</div>

(required by fullpage.js)

  • First bump: achieving the "Long gradient background" effect.

    Since fullpage.js resizes each section to 100vh, it's only logical that the "long background" should be applied to a parent element or to an element with position: absolute || fixed; and the "correct" dimensions, i.e., 400vh.

    So I tried to apply it to the following elements:

    • html
    • body
    • wrapper div (that wraps the required <div id="fullpage"> element)
    • Even to the sections themselves

      I could list all the options I tried if needed but I think it is not that important.
      The gist is that all options resulted in a partial background that is fixed in place (no change on scroll) or a full background contained in 100vh (always visible).

    First bump solution:

    I noticed that when scrolling, fullpage.js alters the <div id="fullpage">'s transform: translate3d(0px, [height-offset]px, 0px);, and so although reluctant, I applied the background to it. This too resulted in the background contained in 100vh.

    Unless I do:
    html {
      height: auto !important;
    }
    

    OR

    <div class="wrapper">
      <div id="fullpage">
        <div class="section">One</div>
        <div class="section">Two</div>
        <div class="section">Three</div>
        <div class="section">Four</div>
      </div>
    </div>
    

    After reading up a little I found this answer which might explain the behavior.

    In short, if I understood correctly, both html and body have height: 100%;, the body takes the html's 100% and the html takes a 100% of the viewport, and since the <div id="fullpage"> gets height: 100% it "inherits" the 100% of the viewport. Thus, resulting in a background contained in 100vh.
    So the first option just overrides the html's 100% of the viewport with auto which effectively makes it a wrapper. While the second option, creating a wrapper which unlike body and html automatically gets the height by the size of its children, actually got us 400vh since each section is 100vh.


  • Second bump: inserting a mask between a section and its contents.

    What I tried:

    1. Applying a mask to the section class.
      It did not work because each section would get a mask and it would scroll away with it.
    2. Applying a mask to the <div id="fullpage">.
      Did not work because even when I got it fixed (using pseudo classes and position absolute or fixed), it created the mask with a height of 400vh while I want it to be only on the viewport (100vh).
    3. Changing the structure and adding an element before the <div id="fullpage"> so it would act as a mask, it works but I am unable to find a way to bring the sections' content to the front.

    What I have so far || CodePen:

new fullpage('#fullpage', {
  licenseKey: 'YOUR KEY HERE',
  autoScrolling: true,
});
:root {
  --background-def: #2f3542;
  --green: #5cd3ad;
  --orange: #f5c156;
  --red: #e6616b;
  --purple: #c678dd;
}

html {
  height: auto !important;
  min-height: 100% !important;
}

#fullpage {
  z-index: 2;
  background: linear-gradient( to bottom, var(--green), var(--orange), var(--red), var(--purple));
}

.mask {
  position: fixed;
  height: 100vh;
  width: 100vw;
  background: radial-gradient( at 80vw 80vh, transparent, rgba(47, 53, 66, 0.1), rgba(47, 53, 66, 0.2), rgba(47, 53, 66, 0.3), rgba(47, 53, 66, 0.4), rgba(47, 53, 66, 0.5), rgba(47, 53, 66, 0.6), rgba(47, 53, 66, 0.7), rgba(47, 53, 66, 0.8), rgba(47, 53, 66, 0.9), #2f3542 60%);
  
  /*OR a mask*/
  /*   -webkit-mask-image: radial-gradient(
    farthest-corner at 80vw 80vh,
    transparent,
    black 40%
  );
  background: var(--background-def); */
  z-index: 3;
}

.section {
  text-align: center;
  font-size: 3em;
  
  /*Initially I had the mask here or in an after/before psuedo class but it stuck to the section and scrolled with it for the obvious reasons*/
  z-index: 5;
}
<link href="https://rawgit.com/alvarotrigo/fullPage.js/dev/src/fullpage.css" rel="stylesheet" />
<script src="https://rawgit.com/alvarotrigo/fullPage.js/dev/src/fullpage.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div class="mask"></div>
<div id="fullpage">
  <div class="section">One</div>
  <div class="section">Two</div>
  <div class="section">Three</div>
  <div class="section">Four</div>
</div>

As you can see, the sections' contents (currently, the titles) appear behind the background although the z-index is altered as it should be. What am I missing?

Is it possible to achieve what I have in mind?


Thank you in advance.

P.S., If it makes any difference, eventually, I would like to have a canvas rendered on the sections' background. Something like this, but that's not the main issue.

Julian Broudy
  • 320
  • 3
  • 15
  • it would be tricky with only CSS, with JS it can be doable – Temani Afif May 05 '20 at 23:20
  • @TemaniAfif Would you mind pointing me in the right direction? Although I don't mind tricky :). – Julian Broudy May 05 '20 at 23:21
  • you have to deal with complex stacking context and as you have noticed the transform applied to the container is the culprit making everything difficult. I would point you to this: https://stackoverflow.com/a/54903621/8620333 to understand why but I didn't find an easy way to have the stacking you want. I was thinking about JS to adjust the position of mask that you make fixed inside the fullpage container – Temani Afif May 05 '20 at 23:25
  • @TemaniAfif I followed your advice and found a solution. Thank you. – Julian Broudy Jul 12 '20 at 12:14

1 Answers1

1

Following Temani Afif's advice.

I found a way to accomplish what I had in mind. Truth be told it is somewhat a workaround that "breaks" FullPage's required structure but without consequences.

The solution is:

1. Add a div inside <div id="fullpage"> that will act as an overlay:

<div id="fullpage">
  <div id="overlay"></div>
  <div class="section">One</div>
  <div class="section">Two</div>
  <div class="section">Three</div>
  <div class="section">Four</div>
</div>

2. Define a CSS variable:

--overlay-position: 0px;

3. Style your overlay:

#overlay {
  position: fixed;
  height: 100vh;
  width: 100vw;
  -webkit-mask-image: radial-gradient(
    farthest-corner at 80vw 80vh,
    transparent,
    black 40%
  );
  background: var(--background-def); /* is defined at :root */
  transition: all 1200ms ease 0s;    /* 1200 is what I chose for FullPage's scrolling speed */
  transform: translate3d(0px, var(--overlay-position), 0px);
}

4. Make use of FullPage's callback method onLeave:

const docStyle = document.documentElement.style;
new fullpage("#fullpage", {
  licenseKey: "YOUR KEY HERE",
  autoScrolling: true,
  scrollingSpeed: 1200,
  onLeave: function (origin, destination, direction) {
    let newPosition = destination.item.offsetTop;
    docStyle.setProperty("--overlay-position", Math.round(newPosition) + "px");
  }
});

Working sample followed by an explanation:

const docStyle = document.documentElement.style;
new fullpage("#fullpage", {
  licenseKey: "YOUR KEY HERE",
  autoScrolling: true,
  scrollingSpeed: 1200,
  onLeave: function(origin, destination, direction) {
    let newPosition = destination.item.offsetTop;
    docStyle.setProperty("--overlay-position", Math.round(newPosition) + "px");
  },
});
:root {
  --background-def: #2f3542;
  --green: #5cd3ad;
  --orange: #f5c156;
  --red: #e6616b;
  --purple: #c678dd;
  --overlay-position: 0px;
}

html {
  height: auto !important;
}

#overlay {
  position: fixed;
  height: 100vh;
  width: 100vw;
  -webkit-mask-image: radial-gradient( farthest-corner at 80vw 80vh, transparent, black 40%);
  background: var(--background-def);
  transition: all 1200ms ease 0s;
  transform: translate3d(0px, var(--overlay-position), 0px);
}

#fullpage {
  background: linear-gradient( to bottom, var(--green), var(--orange), var(--red), var(--purple));
}

.section {
  text-align: center;
  font-size: 3em;
  color: white;
  width: 100%;
  height: 100%;
  z-index: 5;
}
<link href="https://rawgit.com/alvarotrigo/fullPage.js/dev/src/fullpage.css" rel="stylesheet" />
<script src="https://rawgit.com/alvarotrigo/fullPage.js/dev/src/fullpage.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="fullpage">
  <div id="overlay"></div>
  <div class="section">One</div>
  <div class="section">Two</div>
  <div class="section">Three</div>
  <div class="section">Four</div>
</div>
OR CodePen

Explanation:

Since fullpage.js does not actually scroll the page, but alters the <div id="fullpage"> transform: translate3d(0px, [height-offset]px, 0px);, we cannot add a scroll event listener.
So instead, I apply the same transform to the overlay. It is inserted as <div id="fullpage">'s child because I was not able to correctly stack the elements if the overlay was outside it.

An existing problem is with resizing, sometimes the overlay does not resize correctly. I will update this answer as soon as I get to it.

Julian Broudy
  • 320
  • 3
  • 15