JSFiddle - React, Tailwind, and code Playground

by Pedro Pinto

HTML

<script src="https://rawgit.com/Doist/ICE/master/ICE.js"></script>
<section>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nihil quod mollitia aut, modi, ea eaque, non libero iste ipsam fugiat rem ut asperiores hic quisquam harum repudiandae possimus accusantium consequuntur.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet consectetur voluptatum earum officiis in enim libero. Sapiente repudiandae commodi obcaecati eum voluptas, quasi facilis veniam asperiores, est, ipsum ad suscipit.</p>
</section>

<section>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima, soluta autem illum quia ea debitis quae adipisci, eligendi nobis voluptas libero placeat ut explicabo, quibusdam et eos porro vero. Eligendi.</p>
</section>

<section class="js-dimmer">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo ut, veritatis nihil nam, excepturi natus dignissimos, ratione consequuntur quaerat voluptatibus debitis quas vel mollitia voluptas hic quis modi, corporis? Doloribus.</p>
</section>

<section class="js-dimmer">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem assumenda ipsam alias excepturi. Doloribus nobis eum maiores, voluptatum sapiente cupiditate quod tempora voluptate repellat temporibus officia dolores reprehenderit dolorem animi?</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur officiis dignissimos numquam aperiam quaerat necessitatibus commodi deserunt possimus rem adipisci placeat labore ipsum, blanditiis earum libero, sequi non. Ratione, debitis.</p>
   <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Corporis mollitia earum rem et culpa dolore vitae quibusdam! Molestiae iusto labore vel excepturi velit voluptatibus debitis omnis mollitia! Labore, voluptate voluptates.</p>
</section>

<section>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Mollitia atque nam quam vero quibusdam perspiciatis, sapiente possimus numquam...

CSS

body { background-color: #ffffff; }
section {
  padding: 2rem;
  position: relative;
}

section.js-dimmer { /* just so we know which ones */
  color: #3333aa;
  background-color: #ABCDEF;
}

Babel + JSX

const Dimmer = ((sections) => {

		const settings = {
    	viewportMarginPercentage: 5, // 5 means it will start dimming the sections as soon as 5% of the height of the section has left the viewport
      backgroundBrightness: 3, // The higher the value, the lighter the sections are when leaving the viewport
      dimmerLayerStyles: [
        'background-color: #000000;',
        'position: absolute;',
        'top: 0;',
        'left: 0;',
        'height: 100%;',
        'width: 100%;',
        'opacity: 0;',
        'z-index: 1;',
        'pointer-events: none;',
        'transition: opacity 0.2s ease-out;'
      ]
    };
    
    const elements = {
    	sections: sections
    };
    

		// Setup events
    const setUpEvents = () => {
    	// Scroll
      window.addEventListener('scroll', () => {
        throttle(() => {
          dimSections(elements.sections);
         }, settings.scrollFPS);
      });	
    };

		// Dim sections
    const dimSections = (sections) => {
      const scrollPosition = window.pageYOffset;

      for (const section of sections) {
        const sectionPosition = section.getBoundingClientRect();
        const margin = settings.viewportMarginPercentage / 100 * sectionPosition.height || 0;
        const magicNumber = (sectionPosition.top / settings.backgroundBrightness + margin) / sectionPosition.height;
        const opacity = getOpacityValue(magicNumber);
        const background = $$('.js-dimmer-background', section);
        const sectionIsVisible = sectionPosition.top + sectionPosition.height > 0;

        if (opacity >= 0 && opacity <= 1 && sectionIsVisible) {
          $setStyle(background, { opacity: opacity });
        } else {
          $setStyle(background, { opacity: 0 });
        }
      }
    };

		// Throttle events
    const throttle = (callback, fps) => {
      let isUpdating = false;

      if(isUpdating) {
        return;
      }

      isUpdating = true;

      setTimeout(() => {
        requestAnimationFrame(() =>...