Kasper Gram-Jensen
Kasper Gram-Jensen

Reputation: 11

Sliding reveal opacity text effect

I'm trying to create a sliding opacity reveal effect on text and I can't figure out how to do it. So far I've done a gradient effect with background and text clip - but I would really like to have the effect like the on section 3 from this website.

My code is looking this for now:

h3 {
  text-align: center;
  display: inline-block;
  color: black;
  font-size: 400%;
  text-transform: uppercase;
  -webkit-background-clip: text;
  background-clip: text;
  -moz-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-fill-color: transparent;
  -moz-text-fill-color: transparent;
  margin-bottom: 0;
}

.content {
  text-align: center;
  display: inline-block;
  color: black;
  background: -webkit-linear-gradient( black, grey, grey);
  background: -moz-linear-gradient( black, grey, grey);
  -webkit-background-clip: text;
  background-clip: text;
  -moz-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-fill-color: transparent;
  -moz-text-fill-color: transparent;
  background-attachment: fixed;
}

article {
  fixed;
  background: conic-gradient( hsl(700 100% 10%), hsl(200 100% 10%), hsl(700 100% 10%)) fixed;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-align: center;
}

body {
  padding: 5vmin;
  box-sizing: border-box;
  display: grid;
}

h1 {
  font-size: 10vmin;
  line-height: 1.1;
  max-inline-size: 15ch;
  margin: auto;
}

p {
  margin-top: 1ch;
  line-height: 1.35;
  max-inline-size: 40ch;
  margin: auto;
  font-size: 40px;
}

article {
  background: radial-gradient( hsl(100 100% 60%), hsl(200 100% 60%)) fixed;
  background: conic-gradient( hsl(100 100% 60%), hsl(200 100% 60%), hsl(100 100% 60%)) fixed;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-align: center;
}

body {
  min-block-size: 200vh;
  min-inline-size: 100%;
  padding: 5vmin;
  box-sizing: border-box;
  display: grid;
  place-content: center;
}

p {
  margin-top: 1ch;
  line-height: 1.35;
  max-inline-size: 40ch;
  margin: auto;
}
<article>
  <h1>Scroll Contextual Conic Gradient Text</h1>
  <p>orem Ipsum is simply dummy text of the printing and typesetting industry.</p>
  <p>orem Ipsum is simply dummy text of the printing and typesetting industry.</p>
  <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</article>

<div class="container">
  <div class="content">
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
    <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>
  </div>

  <h3> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </h3>

</div>

Upvotes: 1

Views: 146

Answers (1)

InspectorGadget
InspectorGadget

Reputation: 1000

Here is an example:

window.addEventListener('load', load);
window.addEventListener('resize', resize);
window.addEventListener('scroll', scroll);

// Global variables
const container = document.querySelector('.scrollTextContainer');
const text = document.querySelector('.scrollText');
const maskText = document.querySelector('.maskText');

let windowheight = window.innerHeight;

let lineCount; // Number of lines
let pointCount; // Number of points in polygon
let textLineHeight = 30; // Height of lines (pixels)

let points = []; // Points of polygon

let oldScroll = 0; // Required in order to determine if user is scrolling up or down
let scrollUpdate = false; // Required in order to avoid unnecessary updates

function scroll() {
    const top = container.getBoundingClientRect().top; // Distance from text element's top edge to the viewport's top edge
    const bottom = container.getBoundingClientRect().bottom; // Distance from text element's bottom edge to the viewport's top edge

    const distTop = -top + windowheight/2; // Distance from text element's top edge to the viewport's center
    const distBottom = -bottom + windowheight/2; // Distance from text element's bottom edge to the viewport's center

    if(distTop > 0 && distBottom < 0) scrollUpdate = true;

    if(scrollUpdate) {
        const lineNum = Math.floor(distTop / textLineHeight); // Line number that is on the center of the screen (0 based)
        const linePer = ((distTop - lineNum * textLineHeight) * 100) / textLineHeight; // How much percent of the line is visible

        // Scrolling down - set visible percent of all the lines that is above the current line to 100
        if(window.scrollY - oldScroll > 0) {
            for(let i = 1; i < Math.min(2*lineNum+1, pointCount-1); i++) {
                points[i] = `100% ${points[i].split(' ')[1]}`;
            }
        }
        // Scrolling up - set visible percent of all the lines that is below the current line to 0
        else {
            for(let i = Math.max(2*lineNum+1, 0); i < points.length; i++) {
                points[i] = `0% ${points[i].split(' ')[1]}`;
            }
        }
        // Set the current line's visible percent
        if(distTop > 0 && distBottom < 0) {
            points[1 + 2*lineNum] = `${linePer}% ${(100 / lineCount) * lineNum}%`;
            points[2 + 2*lineNum] = `${linePer}% ${(100 / lineCount) * (lineNum + 1)}%`;
        }

        if(lineNum < 0 || lineNum > lineCount-1) scrollUpdate = false;

        maskText.style.clipPath = `polygon(${points.join(', ')})`;
        oldScroll = window.scrollY;
    }
}

function resize() {
    windowheight = window.innerHeight;

    lineCount = text.clientHeight / textLineHeight;
    pointCount = 2 * lineCount + 2;

    points = [];

    for(let i = 0; i < pointCount; i++) {
        if(i % 2) points[i] = `0% ${Math.floor(i / 2) * (100 / lineCount)}%`;
        else points[i] = `0% ${(i / 2) * (100 / lineCount)}%`;
    }

    maskText.style.clipPath = `polygon(${points.join(', ')})`;
}

function load() {
    text.style.lineHeight = `${textLineHeight}px`;
    maskText.style.lineHeight = `${textLineHeight}px`;

    lineCount = text.clientHeight / textLineHeight;
    pointCount = 2 * lineCount + 2;

    for(let i = 0; i < pointCount; i++) {
        if(i % 2) points[i] = `0% ${Math.floor(i / 2) * (100 / lineCount)}%`;
        else points[i] = `0% ${(i / 2) * (100 / lineCount)}%`;
    }

    maskText.style.clipPath = `polygon(${points.join(', ')})`;
}
body {
  margin: 0;
  padding: 0;
  background-color: #333;
}
.scrollTextContainer {
  width: 70%;
  text-align: center;
  color: white;
  margin: 300px auto;
  position: relative;
  display: block;
}

.scrollText {
  position: relative;
  opacity: .5;
}

.maskText {
  position: absolute !important;
  top: 0;
  left: 0;
  opacity: 1;
  will-change: clip-path;
  transition: clip-path .4s cubic-bezier(0,.77,.79,.79);
}

.scrollText, .maskText {
  font-size: 20px;
  display: block;
}
<div class="scrollTextContainer">
  <div class="scrollText">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis deleniti quia nostrum beatae suscipit, optio odio, facilis commodi. Cum, temporibus adipisci. Totam temporibus qui est animi, esse eaque asperiores obcaecati. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi aspernatur quis incidunt illo velit voluptates quisquam soluta debitis delectus, eveniet odio minima culpa ab, consectetur recusandae tempore itaque laborum corporis.</div>
  <div class="maskText">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis deleniti quia nostrum beatae suscipit, optio odio, facilis commodi. Cum, temporibus adipisci. Totam temporibus qui est animi, esse eaque asperiores obcaecati. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi aspernatur quis incidunt illo velit voluptates quisquam soluta debitis delectus, eveniet odio minima culpa ab, consectetur recusandae tempore itaque laborum corporis.</div>
</div>

Upvotes: 1

Related Questions