Elementor Full Screen Horizontal Scroll Containers

Elementor Full Screen Horizontal Scroll Containers

Element.How also offers premium tutorials! Check them here:

Table of Contents

In this tutorial you are going to learn how to create horizontally scrolling Elementor containers without any plugin.

You will also learn how to create an horizontal scrolling gallery.

This tutorial uses the new containers element, as they are perfect for this.

See the demos here.

Horizontally scrolling Elementor containers:

Please purchase access and be logged in to access this template.

 

Horizontal Scrolling Gallery, Loop Grid, and Posts elements (scroll down all the way!) :

Please purchase access and be logged in to access this template.

 

Horizontal Scrolling Woo Products

Features:

  • Polyvalent: Make any content at all horizontally scrollable
  • Works with native features: Compatible with Elementor's entrance animations
  • Works everywhere: Works well and smoothly on desktop and mobile
  • Performance optimized: The scroll event is throttled and we are using requestAnimationFrame for optimal CPU performance.
  • No dependencies JavaScript: We aren't loading a large JS animation library like GSAP here. I coded the entire functionality in vanilla JS.
  • Lightweight: This is the most lightweight way to do this kind of design, loading in only a very few KBs of JS and CSS.
  • RTL compatible
  • No plugins required
  • New: Direct support for Gallery, Products and Loop Grid elements!
  • New: Anchor links support

Important note: You will need the feature "Container" to be enabled under WP > Elementor > Features > Container. This uses the container element.

Templates included: All three templates you see above are included.

Let's get started!

First, import the template to your page

This is a premium tutorial. Purchase access to unlock the full tutorial and download the template.

Access tutorial

$59/one time Purchase access

Includes

  • Gain Access to This TutorialUnlock complete access to the current tutorial: Elementor Full Screen Horizontal Scroll Containers
  • Future UpdatesYou will get access to all future updates to this tutorial.
  • Enjoy Unlimited UsageUse on as many of your own sites or your clients sites as you wish.

    Note that reselling or redistributing is not permitted.

Access everything

$299/one time Purchase All Access

Includes

  • Unlock every premium tutorial on Element.howGet access to the entire library of premium tutorials on Element.how
    Preview premium tutorials
  • Get access to the CSS course for Elementor usersAccess the complete 14 HTML chapters, 30 CSS chapters and 7 Elementor Projects.Learn more
  • Simple CSS Grid For ElementorAn Elementor Addon to Create Awesome Grid Layouts in a Single Click for Containers, Galleries and Loop Grid. Learn more
  • free extra: ShapeDividers.com Premium AccessLifetime Premium Access to ShapeDividers.comVisit ShapeDividers.com
  • 6 months money backNo questions asked money back. Not what you expected? Get a refund.
  • One-time payment of only $299No hidden fees or subscriptions.

    Sales taxes added where applicable.
  • Support not needed!Due to personal circumstances, I no longer offer support. The vast majority of customers never needed support to start with, so chances are you will be just fine, the tutorials and templates provided are complete.

    I also extended the refund window from 1 to 6 months, during which you can get a full refund for any reason.
  • Lifetime access to everything Element.howThe price reflects what is currently available on Element.how. All future updates are included, but none are promised. You pay for what is available now, and the rest is a sweet extra.
* All prices are USD. Applicable taxes will be charged at checkout. Have a question? See the FAQ or email me.

Element.how also provides premium tutorials showing awesome advanced designs, check them out here.

Looking for something else? Search across 2927 Elements right here:

Checkout the Elementor Addon Finder directly

92 Responses

    1. Hey Paul!

      This is a bit complex, and above the scope of the tutorial. The tutorial is made to work with containers that are 100vw by 100vh, so that it's relatively simple and straightforward to use in the editor.

      Changing this, while possible, makes it wonky in the editor, so that's why I don't officially support it.

      However for adventurous users, both code snippets actually support this (varying containers sizes) out of the box.

      Here is how you can play with this:

      On the containers that are direct child of the horizontalScroll_translateContainer, in their advanced > custom CSS field, add this CSS, and adjust to your liking:

      selector {
      width: 70vw;
      max-width:70vw !important;
      min-width:70vw !important;
      }
      

      In the editor, it will be easier to edit things if you use values that are under 100vw, instead of above. In any case, both should work.

      Different containers can have different widths.

      Hope this helps!

  1. Hey,

    Not really no... not as it is at least. With extra work, it would be possible, however it is above the intended scope of this tutorial. It becomes quite specific and would rather be custom work.

    1. No problem Maxime, I've found that is possible to use fixed or absolute positioning placing that items in "horizontalScroll_innerWrapper".
      Even elementor motion effects works with GSAP setting the effect relative to "Entire Page".

    1. Sorry Mirko, this isn't possible.

      I had a good look at this and the problem with locomotive scroll is that it is very incompatible with Elementor. It breaks nearly every scroll related features of Elementor, such as entrance animations, scrolling effects, anchors smooth scroll, etc.

      To prevent adding smooth scroll, but creating a host of problems, I opted to go with stability instead.

    1. It's possible, however due to the all the DIVs generated, it's not a really good idea. That's why this tutorial is only about how to do it with the containers.

    1. Hey Louise!

      The problem is that your containers, for some reason, aren't display:flex; but they are display:block;

      It's the clear what the reason is... I suspect maybe your optimization plugin. It's as if some CSS is missing.

      Adding

      .e-container, .e-con { display: flex;}

      should fix the problem

      Cheers!

      1. That sorted it! Thank you 🙂 Was my caching plugin as well I suspect - minifying CSS maybe, taken that off

    1. Hey Nicholas!

      The "Shop now" button just has a "#" link that scrolls back up to the top of the page.

      Unfortunately with this design it's not easily possible to have a button to scroll to a specific scroll section. With extra JS this might be possible but it's out of the intended scope of the tutorial....

      Cheers!

  2. Hi, I've been using the horizontal scroll for some time and it worked great until the last version of Elementor.

    Since version 3.8.0 it doesn't work at all, is there an update coming soon to fix this?

    1. Hey Mounir!

      Indeed there has been class names changes with 3.8 that breaks the code slightly. Please replace "e-container" with "e-con" in these two lines of code:

      let scrollSectionsAmount = parentOfStickySection.querySelectorAll('.horizontalScroll_translateContainer > .e-container').length;
      
      .horizontalScroll_innerWrapper>.horizontalScroll_translateContainer>.e-container {
      

      To work with Elementor 3.8 and above, they should be:

      let scrollSectionsAmount = parentOfStickySection.querySelectorAll('.horizontalScroll_translateContainer > .e-con').length;
      
      .horizontalScroll_innerWrapper>.horizontalScroll_translateContainer>.e-con {
      

      You can simply copy paste the code from the tutorial, it's updated to work with 3.8. Writing here the changes needed for reference.

      Also note that the "horizontalScroll_parent", "horizontalScroll_innerWrapper" and "horizontalScroll_translateContainer" containers needs to be set to "full width" layout, and not boxed.

      1. Hi Maxime,

        Thanks a lot for your answer. I'm going to put it in place right away.

  3. Thank you Steffen! I'll try that out.

    Have you been able to make it work on mobile? I've tried but it was way too jumpy and jittery so I decided to disable in on mobile for now.

  4. Hey Steffen,

    Yes indeed performance on mobile can be a challenge with this design. It will depend a lot on what's on your page, what's part of the content, and also simply the specs of the smartphone being used to view the page.

    Older smartphones in particular won't have a good UX. This is one of the con of this horizontal scrolling design. Use the straight JS version for optimal mobile performance (then you don't have easing though).

    That's one of the reason I explain how to disable this on mobile. Generally speaking, while it works there, it might not be ideal. Mostly if you have a heavy page already.

    Cheers!

    EDIT: I actually greatly improved performance for mobile, and it should be 100% usable there in most cases.

  5. Hi Maxime,

    How can I make the next non-sticky, non-horizontal scrolling row show up faster?

    The way it is now, there is a big white space before the next section/container shows up (which isn't a horizontal scrolling section).

    I hope that makes sense, happy to provide further details!!

    Love the template, it's perfect for what I need it for. 🙂

    1. To readers: Daniel sent me his URL and I could have a look. The issue in this particular case was that he had changed, in the CSS provided, the "100vh" to "75vh", leaving 25vh of empty space at the bottom.

      Going back to 100vh fixed the issue.

  6. Hi Maxime, All working ok, but my website has a sticky nav, which disappears on the page where the horizontal code / feature is installed. I go live this thurs and really need the nav to show. Is there a fix you can help with?
    Thanks, Andrew

  7. Hey there!

    How to eliminate the whitespace between last black container and first "section after" container?

    Greetings

    Stefan

      1. Hey Stefan!

        That's simply some bottom margin on the wrapper container. Remove through the Elementor UI.

      2. WTF. Sometimes you stand too close. Sorry and thank you at the same time!

  8. Hello,

    very nice template!

    Unfortunately I am not a programmer. Is it possible to have something like a "snap"? This means the following:

    1. when I scroll through the horizontal slider, that when it is fully visible, it "snaps" for about 1 second before the scroll continues.

    2. if I have the next slide 90% in view when scrolling and stop scrolling, it will automatically finish scrolling until it is 100% in view.

    Is this possible?

    Greetings
    Oliver

    1. Hey Oliver!

      An earlier version of this tutorial provided a 'snap' version. I removed it, for several reasons:

      It looks and sounds like a good idea at first, but in practice, it gets really annoying, really quickly for users. It becomes a kind of 'scroll jacking', degrading UX.

      It was dependant on GSAP, making it heavier. Now the current code is vanilla JS, with no dependencies, so it's as lightweight as possible.

      The GSAP code was also less performant, CPU wise. The current code is as performant as can be, so can be used on mobile fine, in most cases.

      I won't add the snapping version back. People almost always ended up reverting to the normal, non-snapping version anyway, when the UX flaws became obvious.

      Hope you understand!

      Cheers

  9. Hi
    i was wondering how can i make anchor link work on the horintal tetorial
    ive purchase it which is great
    but can make menu scroll to # tag

    any clues how it can be done
    thanks in adnvanced

    1. Greetings eytan,

      Add this code. It will add support for anchor links, while on the same page.

      Your IDs will need to be given to a direct children of the horizontalScrollTranslate container.

      So, give your IDs to the containers that are direct descendent of it.

      const anchorLinks = document.querySelectorAll('a[href*="#"]');
      
      anchorLinks.forEach((link) => {
        link.addEventListener('click', function (event) {
          const href = this.getAttribute('href');
          const anchorIndex = href.lastIndexOf('#');
          const targetID = anchorIndex !== -1 ? href.substring(anchorIndex + 1) : '';
      
          const targetElement = document.getElementById(targetID);
      
          if (targetElement) {
            const translateContainer = targetElement.closest('.horizontalScrollTranslate');
      
            if (translateContainer) {
              event.preventDefault();
      
              let scrollParent = translateContainer.closest('.horizontalScrollWrapper');
      
              let scrollHeight = scrollParent.offsetHeight;
      
              let targetIndex = Array.prototype.indexOf.call(translateContainer.children, targetElement);
      
              let scrollDistance = (scrollHeight - translateContainer.parentElement.offsetHeight - 100) * ( targetIndex / (translateContainer.children.length - 1) );
      
              scrollDistance += scrollParent.getBoundingClientRect().top + window.scrollY;
      
              setTimeout(function () {
                jQuery('html,body').animate({ scrollTop: scrollDistance }, 1300);
              }, 100);
            }
          }
        });
      });
      

      Copy paste it directly below this line:

      /* END OF preload the images after the first image gets in the viewport */

      Cheers!

  10. Hi thanks
    it doesnt work for some reason
    im using your template to check if it works

    ive added id the each direct descendent container doesnt work
    any clues why
    thanks

  11. thanks it did the job
    if you can please take a look of what idid

    im doing a one page which combines container and aslo loop grid
    basicly ive i have 2 html in the same page to make it work

    is it ok to do it like that?

    another question my scroll doesnt reach to the posint of the anchor

    thanks again

    1. Hey Eytan!

      Sorry my code works for the default setup of each container having 100vw per 100vh.

      I'd need more work to get it functioning in every scenario... like what you have here.

    2. Hey Eytan!

      I improved the code to get it working in all scenarios, and added the instructions in the tutorial.

      Cheers!

      1. Hey Caco!

        While in tablet and mobile mode, go in your horizontalScrollTranslate containers, and set the Flex Direction to "column".

        Let me know if that works!

        Cheers!

  12. Hi,
    Had been looking for something exactly alike this.
    Haven't had to chance to play around with it as of yet but was wondering if it would be possible to make something along the lines of this with it: https://www.pieaerts.com/personal-work/umoja/
    on mobile and laptop up until around 1920x1080 it will show the flex container in grid form, so the photos will be shown in grid form which in my opinion gives a very sleek look as you minimize your monitor, if you have a large monitor it jumps smoothly from scroll to grid as you downsize browser tab, I presume this is also possible with this adaption of this particular scroll container? Any ideas on how I could set this up? So the goal is on smaller monitors + mobile + tablet for it to not show as scroll container but as grid.

    1. Hey Alex!

      I have instructions to enable the horizontal scroll on desktop only in the tutorial.

      https://element.how/elementor-horizontal-scroll-containers/#table-of-content-7

      If you want it to be above 1920 instead of 1024, just change the value here:

      if (window.innerWidth > 1024){

      to

      if (window.innerWidth > 1919){

      This won't get you exactly what you have on the example site though, as that one is made differently... but it should get you started.

      Cheers!

  13. Hi
    i was wondering does the anchor link
    support link from external url
    right now when i go to # from external url i get only the 1 section of the selected id

    is theres a way to solve it
    thanks

    1. Greetings Eytan!

      Try this code for the anchor links, let me know if it works!

      /* anchor links support */
      const anchorLinks = document.querySelectorAll('a[href*="#"]');
      
      function scrollToTarget(targetID) {
          const targetElement = document.getElementById(targetID);
      
          if (!targetElement) return;
      
          const translateContainer = targetElement.closest('.horizontalScrollTranslate');
      
          if (!translateContainer) return;
      
          let scrollParent = translateContainer.closest('.horizontalScrollWrapper');
          let scrollHeight = scrollParent.offsetHeight;
          let scrollDistance = targetElement.offsetLeft / (translateContainer.offsetWidth - window.innerWidth) * (scrollHeight - translateContainer.parentElement.offsetHeight - 100);
          scrollDistance += scrollParent.getBoundingClientRect().top + window.scrollY;
      
          setTimeout(function () {
              jQuery('html, body').animate({ scrollTop: scrollDistance }, 1300);
          }, 100);
      
      }
      
      anchorLinks.forEach((link) => {
          link.addEventListener('click', function (event) {
              event.preventDefault();
              const href = this.getAttribute('href');
              const match = href.match(/#([^?]+)/);
              const targetID = match ? match[1] : '';
      
              scrollToTarget(targetID);
          });
      });
      
      /* From another page with a anchorID in the URL */
      window.addEventListener('load', () => {
          const anchorID = window.location.href.match(/#([^?]+)/);
          if (anchorID) {
              scrollToTarget(anchorID[1]);
          }
      });
      /* END OF anchor links support */
      

      Cheers!

      1. Hi thanks for replaying
        look i have allready anchorlink support from the same page
        do i have to add it to the code
        or do i need to replace it

        when i add it it doesnt work
        thanks

      2. Yes, please try replacing it with what I sent in the comment...

  14. hi thanks
    it did the work partily
    here is an actual link of the live website i did

    when you will enter you will see the about but you wont see oter section in the layout

    when you reresh again you will see all of the website like it should
    any clues what is wrong

    thanks

    1. Greetings,

      I see what the problem is... the default browser behaviour on page load is creating problems.

      Instead, let's try this:

      Replace the /* anchor links support */ code with this:

      /* anchor links support */
      const anchorLinks = document.querySelectorAll('a[href*="#"]');
      
      function scrollToTarget(targetID) {
          const targetElement = document.getElementById(targetID);
      
          if (!targetElement) return;
      
          const translateContainer = targetElement.closest('.horizontalScrollTranslate');
      
          if (!translateContainer) return;
      
          let scrollParent = translateContainer.closest('.horizontalScrollWrapper');
          let scrollHeight = scrollParent.offsetHeight;
          let scrollDistance = targetElement.offsetLeft / (translateContainer.offsetWidth - window.innerWidth) * (scrollHeight - translateContainer.parentElement.offsetHeight - 100);
          scrollDistance += scrollParent.getBoundingClientRect().top + window.scrollY;
      
          setTimeout(function () {
              jQuery('html, body').animate({ scrollTop: scrollDistance }, 1300);
          }, 100);
      
      }
      
      anchorLinks.forEach((link) => {
          link.addEventListener('click', function (event) {
              event.preventDefault();
              const href = this.getAttribute('href');
              const match = href.match(/#([^?]+)/);
              const targetID = match ? 'hr-' + match[1] : '';
              scrollToTarget(targetID);
          });
      });
      
      /* From another page with a anchorID in the URL */
      window.addEventListener('load', () => {
          let anchorID = window.location.href.match(/#([^?]+)/);
          if (anchorID) {
              anchorID = 'hr-' + anchorID[1];
              scrollToTarget(anchorID);
          }
      });
      /* END OF anchor links support */
      

      Then (important):

      Go in each of your containers where you have IDs, and rewrite them like this instead: hr-anchortexthere

      So if you had "about", it becomes "hr-about", etc.

      Only do this on the containers CSS ID field!

      Don't change the links, they should still be #about (and not #hr-about)

      Let me know if that works and thanks for your patience.

      Cheers!

  15. Hi C - any chance you can elaborate on how you made this work? I can't see "horizontalScroll_innerWrapper" in the template? Thanks!

  16. question when going mobiel ive disabled the horizontal scroll
    make all containers in 100%row
    in vertcial format
    does the anchors suppoese to work?

    thanks

    1. Greetings Eytan,

      No indeed you are right, the anchors won't work on mobile...

      To fix this, add

      if (window.innerWidth < 768) {
              /* scroll normally on mobile */
              targetElement.scrollIntoView({ behavior: 'smooth' });
              return;
          }
      

      directly below the line:

      if (!targetElement) return;

      Let me know if that works!

  17. thanks
    sorry it doesnt work
    heres the website

    the probelm is with mobile only

    inside the home page and when i go back from a project

    thanks i advanced

    1. Hey Eytan!

      Try this instead , replace everything in between the <script> tags with this:

      /* Code from https://element.how/elementor-horizontal-scroll-containers/
      * Copyright 2023 Element.How
      * Licensed for personal and commercial use for customers who purchased access
      * No redistribution or resale allowed
      */
      
      document.addEventListener('DOMContentLoaded', function () {
      
          if (window.innerWidth > 1024) {
      
      
              let horizontalScrollContainers = document.querySelectorAll('.horizontalScrollContainer');
              horizontalScrollContainers.forEach((horizontalScrollContainer) => {
      
                  let speedMultipliers = {
                      desktop: 1.4,
                      tablet: 1.2,
                      mobile: 1,
                  } /* greater value = faster, 1 = default */
      
                  let horizontalScrollTranslate = horizontalScrollContainer.querySelector('.horizontalScrollTranslate');
                  let horizontalScrollParent = horizontalScrollContainer.parentElement;
                  let scrolledRatio = 0;
                  let horizontalScrollContainerTop, horizontalScrollHeight, horizontalScrollTranslateWidth, widthToScroll, windowWidth, mult;
      
                  function updateValues() {
                      windowWidth = window.innerWidth;
                      windowWidth > 1024 ? mult = speedMultipliers.desktop : windowWidth > 767 ? mult = speedMultipliers.tablet : mult = speedMultipliers.mobile;
                      horizontalScrollTranslateWidth = horizontalScrollTranslate.offsetWidth;
                      horizontalScrollParent.style.height = window.innerHeight + horizontalScrollTranslateWidth / mult + 'px';
                      horizontalScrollHeight = horizontalScrollParent.offsetHeight;
                      widthToScroll = horizontalScrollTranslateWidth - windowWidth;
                      horizontalScrollContainerTop = (window.innerHeight - horizontalScrollContainer.offsetHeight) / 2;
                      horizontalScrollContainer.style.top = `${horizontalScrollContainerTop}px`;
                  }
                  updateValues();
      
                  /* update values on resize event */
                  window.addEventListener('resize', () => {
                      if (windowWidth !== window.innerWidth) updateValues();
                  });
      
                  let isUpdateScheduled = false;
      
                  function manageScroll() {
                      let horizontalScrollTop = horizontalScrollParent.getBoundingClientRect().top;
                      let windowHeight = window.innerHeight;
                      scrolledRatio = (horizontalScrollTop - horizontalScrollContainerTop) / (horizontalScrollHeight - horizontalScrollContainer.offsetHeight - 100) * -1; /* removing 100px to make it sticky a bit longer after it reaches the end, for better UX */
                      /* clamp scrolledRatio in between 0 and 1 */
                      scrolledRatio = Math.min(Math.max(scrolledRatio, 0), 1);
                      horizontalScrollTranslate.style.transform = `translateX(${scrolledRatio * widthToScroll * -1}px)`;
                      isUpdateScheduled = false;
                  };
      
                  /* Listen to the scroll event on the window object and schedule the update function using throttling */
                  window.addEventListener('scroll', () => {
                      if (!isUpdateScheduled) {
                          isUpdateScheduled = true;
                          requestAnimationFrame(manageScroll);
                      }
                  });
      
              });
      
          }
      
      
          /* preload the images after the first image gets in the viewport */
          (function () {
              let images = document.querySelectorAll('.horizontalScrollContainer img');
              let firstImage = images[0];
      
              let options = {
                  root: null,
                  rootMargin: '0px',
                  threshold: 0.3
              };
      
              let observer = new IntersectionObserver((entries, observer) => {
                  entries.forEach(entry => {
                      if (entry.isIntersecting) {
                          images.forEach(img => {
                              addPreloadLink(img);
                          });
                          observer.unobserve(firstImage);
                      }
                  });
              }, options);
      
              observer.observe(firstImage);
          })();
      
      
          function addPreloadLink(img) {
              let link = document.createElement('link');
              link.rel = 'preload';
              link.href = img.src || img.dataset.src;
              link.as = 'image';
              if (img.srcset) link.setAttribute('imagesrcset', img.srcset);
              if (img.sizes) link.setAttribute('imagesizes', img.sizes);
              document.head.appendChild(link);
          }
          /* END OF preload the images after the first image gets in the viewport */
      
          /* anchor links support */
          const anchorLinks = document.querySelectorAll('a[href*="#"]');
      
          function scrollToTarget(targetID) {
              const targetElement = document.getElementById(targetID);
      
              if (!targetElement) return;
      
              if (window.innerWidth < 1025) {
                  /* scroll normally on mobile */
                  targetElement.scrollIntoView({ behavior: 'smooth' });
                  return;
              }
      
              const translateContainer = targetElement.closest('.horizontalScrollTranslate');
      
              if (!translateContainer) return;
      
              let scrollParent = translateContainer.closest('.horizontalScrollWrapper');
              let scrollHeight = scrollParent.offsetHeight;
              let scrollDistance = targetElement.offsetLeft / (translateContainer.offsetWidth - window.innerWidth) * (scrollHeight - translateContainer.parentElement.offsetHeight - 100);
              scrollDistance += scrollParent.getBoundingClientRect().top + window.scrollY;
      
              setTimeout(function () {
                  jQuery('html, body').animate({ scrollTop: scrollDistance }, 1300);
              }, 100);
      
          }
      
          anchorLinks.forEach((link) => {
              link.addEventListener('click', function (event) {
                  event.preventDefault();
                  const href = this.getAttribute('href');
                  const match = href.match(/#([^?]+)/);
                  const targetID = match ? 'hr-' + match[1] : '';
                  scrollToTarget(targetID);
              });
          });
      
          /* From another page with a anchorID in the URL */
          window.addEventListener('load', () => {
              let anchorID = window.location.href.match(/#([^?]+)/);
              if (anchorID) {
                  anchorID = 'hr-' + anchorID[1];
                  scrollToTarget(anchorID);
              }
          });
          /* END OF anchor links support */
      
      
      
      });
      

      Cheers!

  18. Hi, installed the script/code etc which is superb on desktop however we are experiencing a very glitchy effect on tablet and mobile. I'm hoping it's something simple, are you able to help please?

    1. Hey Westbrook!

      Hmmm, this is probably just the browser having difficulty. This design is a bit taxing for mobile browsers in particular (that includes iPad), that's one reason why I have instructions on how to disable it for mobile devices only, in case it's just not smooth enough.

      Otherwise the only thing we can do is try to make the DOM as shallow as possible: all containers on the page that can be (where it won't change the layout), should be set to "full width" layout instead of "boxed". Usually that means all inner containers. That will save 1 DIV depth per container... Sometimes it makes enough of a difference to make it better, depending on where we started from!

      Having said that I'd be glad to have a look at your page to check if I can find anything else that could be improved...

      Hope this helps!

      Cheers!

      1. Thanks Maxime, we'll give that a try and if all else fails try an alternative layout for mobile devices. If I get stuck I'll come back to you. Cheers.

    2. Hey Westbrook!

      I think I found a fix for this. Please add this CSS:

      @media (max-width: 1024px) {
      .horizontalScrollTranslate.e-con.e-con {
          transition: transform 0s;
      }
      }
      

      This should make it work really well on mobile. If you try it, let me know how it works for you!

      Cheers!

  19. Hey Maxime, that worked really well thanks, the glitchy experience has stopped. Much appreciate you sticking with this. I'll come back with any further issues if we encounter any. Cheers.

  20. Hi Maxime,
    Thanks for the previous response and help. I've gotten pretty far to where i wanted the page to be, but ran into some problems. For some reason the page is not acting fully responsive and doesn't preload the cache of the lower viewports, this results in no transition between the scrolled viewport and the ones below 1024 unless the site is reloaded. I've tried turning off all my caching plugins and server based caching but it didn't change much.
    test page in question: https://www.alexwhelan.art/rr-test
    2 short 5 second clips that show the problem:
    https://gyazo.com/119e5805cea5f1a4e56dc5d99713b1e0
    https://gyazo.com/351e90f11ace530a27399d23cc85cf59
    2 short 5 second clips that show it working correctly after reloading the website while on a smaller viewport:
    https://gyazo.com/071245aedbf1422187169d9ebd0806b3
    https://gyazo.com/fe2d0068f6adfefd703d3e8510ac4d23

    So question is would there be a way to forcefully pre load those viewports so it transitions smoothly and works responsive instead of having to F5? When the site is opened in smaller viewport it transitions fine to anything >1024.
    So problem only persists when moving from from full screen browser to <1024.

    Was looking at other peoples sites that were linked in the comments and nobody seems to have an alike problem so figured i'd add some more info:
    Caching: Flyingpress + Cloudflare
    Hosting:Siteground
    Theme:Oceanwp

    Appreciate the insights,
    Alex

    1. Greetings Alex!

      Actually this is partly by design. I can't think of any real world use case where the user would first open a page with <1024 viewport, and then expand it... and vice versa. Only use web designers do this when we are inspecting a website for errors / etc.

      So sometimes when the JS gets complex, instead of trying to update everything across mobile to desktop viewports, I don't, to have leaner, more simple code.

      If you have a use case where you would need this though, I could offer a few solutions... first I'd like to know if you have any data that shows real world user are running across this scenario on your site?

      Let me know!

      Cheers!

      1. Hi Maxime!
        Thanks for the rapid response, yeah was showing several people some new pages to kind of gage their responses between several potential designs for the new portfolio sections. Most of them noticed this particular issue.
        I also personally tend to do this rather often just scrolling through the web having multiple windows open on bigger monitors resulting in multiple lower viewport windows.
        I was looking through older comments to look for potential solutions to save you the effort but couldn't really find much.
        I found someone that linked this website though: https://blancheandco.co.uk/
        Where the slider does act responsively. And switches smoothly as you decrease the size of your browser window into the new viewport.
        Would you know what the particular difference in implementation is between this website and mine? I couldn't really figure it out.

        Regards,
        Alex

  21. Hey Alex!

    I understand... Thank you for the information. So the issue would be with people who open windows NOT in full screen. Fair enough!

    I had a good look at your page and I can see the problem clearly:

    The code is meant for desktop only ( it was wrapped with if (window.innerWidth > 1024){ as instructed in the tutorial)

    So when the window opens at 1000px, and goes to >1024px, then the JS isn't in place.

    Conversely, if the window opens at 1100px, and goes down to <1025px, then the JS IS in place, but should not be.

    Solution? A page refresh when that breakpoint crosses over.

    Add this in the code, just before the closing </script> tag :

    window.matchMedia('(max-width: 1024px)').addEventListener('change', (e) => {
        location.reload();
    });
    

    Cheers!

  22. Perfect, thanks for the rapid response. Was hesitant to purchase a tutorial that didn't include a plugin and focused on code particular but the extra support has been all worth it. Kudos Maxime
    Thanks again

    Cheers!

  23. Is there a way to have have the scrolling stop once the final image in a gallery is shown. Currently, it continues scrolling to the left until about half of the page is just blank whitespace.

    I have a gallery of 3 images, and want the scrolling to pretty much stop once all 3 are visible, even if the first image is getting cut off a little on the left thats fine...

    Is it possible? i tried playing with the "width: fit-content;" setting with no luck. Thanks in advance!

    1. Greetings!

      Yes this is possible. Go on the Image Gallery element > Advanced > Padding, and adjust what you will find there to what you need.

      In the template I have 44vw left and right padding, to get the result that you see in the demo. It's optional however and you can have as little or as much padding as you wish!

      Cheers!

      1. Thank you so much for the prompt reply!!! That didn't seem to give me the desired effect - it added white space to both the left and right.

        And example of what I am going for is towards the middle of this page: https://www.canyonranch.com/

        When i adjust the padding in advanced of the gallery, the gallery images just continue to scroll into the white space.. my example is at https://mountainsofhope.com/ towards the middle of the page.

    2. For this, just lower the padding down a lot, maybe 60px each side.

      Or (depending on what you want) on the left side, keep ~30vw , and on the right, 100px.

      Keep in mind though that if all three of your cards fit in the viewport already, then there just won't be much of any horizontal scrolling... the code snippet is really made for when there are offscreen elements

      Cheers!

    1. Greetings Caco!

      The issue seems to be an error earlier in the code. I see that you have these two lines:

      let images = document.querySelectorAll('.horizontalScrollContainer img');
      let firstImage = images[0];

      It should be this instead:

      let images = document.querySelectorAll('.horizontalScrollContainer img');
      if (!images.length) return;
      let firstImage = images[0];

      Let me know if making this changes fixes it.

      Cheers!

      1. Oh Gosh!!

        Only that line... I'll would never notice. Now works beautiful seamlessly. Thanks a lot!

  24. Hi,

    Thanks for the reply, it's working, amazing service of you again!

    Do you also have a trick to make the images full screen, like this effect?
    When you scroll down to the end of the page, you see this slider in like full screen effect.

    https://balo.be/nl

    1. Greetings!

      In the custom CSS, you will see this:

      .horizontalScrollContainer .elementor-image-gallery .gallery-item img {
      max-width: initial;
      width: auto;
      height: 48vh;
      }

      Just change to

      .horizontalScrollContainer .elementor-image-gallery .gallery-item img {
      max-width: initial;
      width: auto;
      height: 100vh;
      }

      Cheers!

Leave a Reply