Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                  <div class="horizontal-scroll-section">
    <div class="scene">
      <div class="horizontal-scroll-section__content-wrapper wrapper">
        <div class="horizontal-scroll-section__content-section">
          <img src="https://www.apple.com/v/ipad-pro/t/images/overview/hero__b2q87exx6cfm_medium_2x.jpg" class="horizontal-scroll-section__image-one" alt="">
        </div>
        <div class="horizontal-scroll-section__content-section">
          <h2>Content Testing 1</h2>
        </div>
        <div class="horizontal-scroll-section__content-section">
          <div class="trigger trigger--one" data-class="horizontal-scroll-section--animation-one" data-offset="0.7"></div>
          <div class="horizontal-scroll-section__image horizontal-scroll-section__image--two">
<img src="https://www.apple.com/v/ipad-pro/t/images/overview/hero__b2q87exx6cfm_medium_2x.jpg" alt="">
            <h2>Here's a title in the animated section!</h2>
            </div>
        </div>
        <div class="horizontal-scroll-section__content-section">
          <h2>Content Testing 2</h2>
        </div>
        <div class="horizontal-scroll-section__content-section">
<img src="https://www.apple.com/v/ipad-pro/t/images/overview/hero__b2q87exx6cfm_medium_2x.jpg" alt="">
        </div>
        <div class="horizontal-scroll-section__content-section">
          <h2>Content Testing 3</h2>
        </div>
        
        <div class="horizontal-scroll-section__content-section">
          <div class="horizontal-scroll-section__image horizontal-scroll-section__image--four">
          <img src="https://www.apple.com/v/ipad-pro/t/images/overview/hero__b2q87exx6cfm_medium_2x.jpg" alt="">
          <h2>Content Testing 4</h2>
            </div>
        </div>
      </div>
    </div>
</div>

<div class="wrapper">
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
  <h2>Here's some content!</h2>
</div>




              
            
!

CSS

              
                body {
  margin: 0;
}

body, html {
  overflow-x: hidden;
}

img {
  max-width: 100%;
  height: auto;
}

.wrapper {
  // max-width: calc(100% - 100px);
  margin: 0 auto;
}

.trigger {
  position: absolute;
  &--one {
    left: 0;
  }
}

 .scene {
    position: absolute;
    height: 100vh;
    top: 0;
    left: 0;
    right: 0;
    &--active {
      position: fixed;
    }
    &--ended {
      position: absolute;
      bottom: 0;
      top: auto;
    }
  }

.horizontal-scroll-section {
  $root: &;
  position: relative;
  min-height: 100vh;
  opacity: 0;
  transition: 0.2s opacity;
  img {
    display: block;
    max-height: 80%;
    width: auto;
  }
  &--init {
    opacity: 1;
  }
  &__content {
    display: flex;
    align-items: center;
    &-wrapper {
      display: flex;
      height: 100%;
      align-items: center;
      position: relative;
    }
    &-section {
      position: relative;
      min-width: 60vw;
      text-align: center;
      padding:  0 40px;
      height: 100%;
      display: flex;
      align-items: center;
    }
  }
  &__image {
    display: flex;
    align-items: center;
    h2 {
      margin-left: 20px;
      width: 250px;
      text-align: left;
      flex-shrink: 0;
    }
  }
  &__image--two {
     // opacity: 0;
     // transform: translateX(30vw);
     // transition: 800ms transform ease-out, 400ms opacity;
    img {
      max-width: 400px;
    }
  }
  &__image--four {
    img {
      max-width: 400px;
    }
  }
  &--animation-one {
    #{$root}__image--two {
      opacity: 1;
      transform: translateX(0);
    }
  }
}
              
            
!

JS

              
                $(function () {

    // Define window variables

    var winScrollTop = $(window).scrollTop();
    var winHeight = window.innerHeight;
    var winWidth = window.innerWidth;

    // Define scene classes.
    var sceneClass = 'scene';
    var sceneActiveClass = sceneClass + '--active';
    var sceneEndedClass = sceneClass + '--ended';

    $(window).on('resize', function () {
        winHeight = window.innerHeight;
        winWidth = window.innerWidth;
    });

    // Scene classes function.
    function setScene($el) {

        // Get bounding values from section.
        var bounding = $el.data('elDom').getBoundingClientRect();

        if (bounding.top > winHeight) {

            // Section is below the viewport.
            // Section has not ended or started, therefore remove classes.
            $el.find('.scene').removeClass(sceneActiveClass);
            $el.find('.scene').removeClass(sceneEndedClass);

        } else if (bounding.bottom < 0) {

            // Section is above the viewport.
            // Section has ended, therefore remove classes.
            $el.find('.scene').addClass(sceneEndedClass);
            $el.find('.scene').removeClass(sceneActiveClass);

        } else {

            // We're now inside the section, not below or above.
            // If top of section is at top of viewport, add class active.
            if (bounding.top <= 0) {
                $el.find('.scene').addClass(sceneActiveClass);
            }

            // If top of section is below top of viewport, remove class active.
            if (bounding.top > 0) {
                $el.find('.scene').removeClass(sceneActiveClass);
            }

            // If bottom of section is at bottom of viewport, add class ended.
            if (bounding.bottom <= (winHeight)) {
                $el.find('.scene').addClass(sceneEndedClass);
            }

            // If bottom of section is not at bottom of viewport, remove class ended.
            if (bounding.bottom > (winHeight)) {
                $el.find('.scene').removeClass(sceneEndedClass);
            }
        }
    }

    // This function sets up the horizontal scroll. This applies data attributes to the section for later use.
    function setUpHorizontalScroll($el) {

        var sectionClass = $el.attr('class');

        // Set content wrapper variables & data attributes.
        var $contentWrapper = $el.find('.' + sectionClass + '__content-wrapper');
        var contentWrapperDom = $contentWrapper.get(0);
        $el.data('contentWrapper', $contentWrapper);
        $el.data('contentWrapperDom', contentWrapperDom);

        // Set content wrapper scroll width variables & data attributes.
        var contentWrapperScrollWidth = $el.data('contentWrapperDom').scrollWidth;
        $el.data('contentWrapperScrollWidth', contentWrapperScrollWidth);

        // Set right max variables & data attributes.
        var rightMax = $el.data('contentWrapperScrollWidth') - winWidth;
        var rightMaxMinus = -(rightMax);
        $el.data('rightMax', Number(rightMaxMinus));

        // Set initialized data variable to false do incidate scrolling functionality doesn't work yet.
        $el.data('initalized', false);

        // Set height of section to the scroll width of content wrapper.
        $el.css('height', $el.data('contentWrapperScrollWidth'));

        // Set data attribute for outerHeight.
        $el.data('outerHeight', $el.outerHeight());

        // Set data attribute for offset top.
        $el.data('offsetTop', $el.offset().top);

        // Set data initialized data variable to true to indicate ready for functionality.
        $el.data('initalized', true);

        // Set data variable for transform X (0 by default)
        $el.data('transformX', '0');

        // Add class of init
        $el.addClass($el.attr('class') + '--init');
    }

    function resetHorizontalScroll($el) {
      
      
        // Update data attribute for content wrapper scroll width.
    
      var contentWrapperScrollWidth = $el.data('contentWrapperDom').scrollWidth;
        $el.data('contentWrapperScrollWidth', contentWrapperScrollWidth);
      

        // Update rightMax variables & data attributes.
        rightMax = $el.data('contentWrapperScrollWidth') - winWidth;
        rightMaxMinus = -(rightMax);
        $el.data('rightMax', Number(rightMaxMinus));

        // Update height of section to the scroll width of content wrapper.
        $el.css('height', $el.data('contentWrapperScrollWidth'));

        // Update data attribute for outerHeight.
        $el.data('outerHeight', $el.outerHeight());

        // Update data attribute for offset top.
        $el.data('offsetTop', $el.offset().top);

        // If transform is smaller than rightmax, make it rightmax.
        if ($el.data('transformX') <= $el.data('rightMax')) {
            $el.data('contentWrapper').css({
                'transform': 'translate3d(' + $el.data('rightMax') + 'px, 0, 0)',
            });
        }
    }

    var $horizontalScrollSections = $('.horizontal-scroll-section');
    var $horizontalScrollSectionsTriggers = $horizontalScrollSections.find('.trigger');

    // Each function - set variables ready for scrolling functionality. Call horizontal scroll functions on load and resize.
    $horizontalScrollSections.each(function (i, el) {
      
        var $thisSection = $(this);

        $(this).data('elDom', $(this).get(0));

        // Set up horizontal scrolling data attributes and show section all have been computed.
        setUpHorizontalScroll($(this));

        // Now we're ready, call setScene on load that adds classes based on scroll position.
        setScene($(this));

        // Resize function
        $(window).on('resize', function () {
            // Reset horizontal scrolling data attributes and transform content wrapper if transform is bigger than scroll width.
            resetHorizontalScroll($thisSection);
            // Reset scene positioning.
            setScene($thisSection);
        });

    });

    function setupHorizontalTriggers($el, section) {
        var parent = $el.parent();
        var positionLeft = parent.position().left;
        var positionLeftMinus = -(positionLeft);
        var triggerOffset = $el.data('triggerOffset');
        triggerOffset = !triggerOffset ? 0.5 : triggerOffset = triggerOffset;
        $el.data('triggerOffset', triggerOffset);
        $el.data('triggerPositionLeft', positionLeftMinus);
        $el.data('triggerSection', section);
    }

    function useHorizontalTriggers($el) {
        if ($el.data('triggerSection').data('transformX') <= ($el.data('triggerPositionLeft') * $el.data('triggerOffset'))) {
            $el.data('triggerSection').addClass($el.data('class'));
        } else {
            if ($el.data('remove-class') !== false) {
                $el.data('triggerSection').removeClass($el.data('class'));
            }
        }
    }

    $horizontalScrollSectionsTriggers.each(function (i, el) {
        setupHorizontalTriggers($(this), $(this).closest('.horizontal-scroll-section'));
    });

    function transformBasedOnScrollHorizontalScroll($el) {

        // Get amount scrolled variables.
        var amountScrolledContainer = winScrollTop - $el.data('offsetTop');
        var amountScrolledThrough = (amountScrolledContainer / ($el.data('outerHeight') - (winHeight - winWidth)));

        // Add transform value variable based on amount scrolled through multiplied by scroll width of content.
        var toTransform = (amountScrolledThrough * $el.data('contentWrapperScrollWidth'));

        // Add transform value for minus (as we're transforming opposite direction).
        var toTransformMinus = -(toTransform);

        // If transform value is bigger or equal than 0, set value to 0.
        toTransformMinus = Math.min(0, toTransformMinus);

        // If transform value is smaller or equal than rightMax, set value to rightMax.
        toTransformMinus = Math.max(toTransformMinus, $el.data('rightMax'));

        // Update transformX data variable for section.
        $el.data('transformX', Number(toTransformMinus));

        // If section has been initalized, apply transform.
        if ($el.data('initalized') == true) {
            $el.data('contentWrapper').css({
                'transform': 'translate3d(' + $el.data('transformX') + 'px, 0, 0)'
            });
        }
    }

    // 
    $(window).on('scroll', function(){
     
        // Get window scroll top.
        winScrollTop = $(window).scrollTop();

        // Each function in horizontal scroll sections.
        $horizontalScrollSections.each(function (i, el) {
            transformBasedOnScrollHorizontalScroll($(this));
            setScene($(this));
        });

        // Each function for horizontal scroll section triggers.
        $horizontalScrollSectionsTriggers.each(function (i, el) {
            useHorizontalTriggers($(this));
        });
                 
    });

});
              
            
!
999px

Console