Please note that this code only works with one horizontal scrolling section per a page.

Updated Version

This updated version is better for accessibility because it doesn’t change the HTML font size. To use this version, follow the tutorial exactly but remove the Webflow interaction completely. This move interaction is handled with GSAP instead of Webflow’s while scrolling interaction.

<style>.horizontal-trigger {height: calc(100% - 100vh);}</style>
<script src="<https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js>"></script>
<script src="<https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/ScrollTrigger.min.js>"></script>
<script>
// © Code by T.RICKS, <https://www.timothyricks.com/>
// Copyright 2021, T.RICKS, All rights reserved.
// You have the license to use this code in your projects but not to redistribute it to others
gsap.registerPlugin(ScrollTrigger);
let horizontalItem = $(".horizontal-item");
let horizontalSection = $(".horizontal-section");
let moveDistance;
function calculateScroll() {
  // Desktop
  let itemsInView = 3;
  let scrollSpeed = 1.2;

  if (window.matchMedia("(max-width: 479px)").matches) {
    // Mobile Portrait
    itemsInView = 1;
    scrollSpeed = 1.2;
  } else if (window.matchMedia("(max-width: 767px)").matches) {
    // Mobile Landscape
    itemsInView = 1;
    scrollSpeed = 1.2;
  } else if (window.matchMedia("(max-width: 991px)").matches) {
    // Tablet
    itemsInView = 2;
    scrollSpeed = 1.2;
  }
  let moveAmount = horizontalItem.length - itemsInView;
  let minHeight =
    scrollSpeed * horizontalItem.outerWidth() * horizontalItem.length;
  if (moveAmount <= 0) {
    moveAmount = 0;
    minHeight = 0;
    // horizontalSection.css('height', '100vh');
  } else {
    horizontalSection.css("height", "200vh");
  }
  moveDistance = horizontalItem.outerWidth() * moveAmount;
  horizontalSection.css("min-height", minHeight + "px");
}
calculateScroll();
window.onresize = function () {
  calculateScroll();
};

let tl = gsap.timeline({
  scrollTrigger: {
    trigger: ".horizontal-trigger",
    // trigger element - viewport
    start: "top top",
    end: "bottom top",
    invalidateOnRefresh: true,
    scrub: 1
  }
});
tl.to(".horizontal-section .list", {
  x: () => -moveDistance,
  duration: 1
});
</script>

Original (Old Version)

<style>.horizontal-trigger {height: calc(100% - 100vh);}</style>
<script>
// © Code by T.RICKS, <https://www.timothyricks.com/>
// Copyright 2021, T.RICKS, All rights reserved.
// You have the license to use this code in your projects but not to redistribute it to others
function calculateScroll() {

	// Desktop
	let itemsInView = 3;
  let scrollSpeed = 1.2;
  
  if (window.matchMedia('(max-width: 479px)').matches) {
  
  	// Mobile Portrait
  	itemsInView = 1;
    scrollSpeed = 1.2;
    
  } else if (window.matchMedia('(max-width: 767px)').matches) {
  
  	// Mobile Landscape
    itemsInView = 1;
    scrollSpeed = 1.2;
    
  } else if (window.matchMedia('(max-width: 991px)').matches) {
  
  	// Tablet
    itemsInView = 2;
    scrollSpeed = 1.2;
    
  }
	let horizontalItem = $('.horizontal-item');
  let horizontalSection = $('.horizontal-section');
  let moveAmount = horizontalItem.length - itemsInView;
  let minHeight = (scrollSpeed * horizontalItem.outerWidth()) * horizontalItem.length;
  if (moveAmount <= 0) {
  	moveAmount = 0;
    minHeight = 0;
  } else {
  	horizontalSection.css('height', '200vh');
  }
  let moveDistance = horizontalItem.outerWidth() * moveAmount;
  $('html').css('font-size', moveDistance + 'px');
  horizontalSection.css('min-height', minHeight + 'px');
}
calculateScroll();
window.onresize = function(){ 
	calculateScroll();
}
</script>