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. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ 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 id="horizontal-menu-head">
  <section>
  <h1 class="fixed">HALLO</h1>
</section>

<section class="sec02">
  <div class="wrap">
    <h1 class="top">HALLO</h1>  
  </div>
</section>
</div>

<div class="horizontal-scroll" id="h-container">
  <section class="h-slide blue" id="h-item1">
    <div class="slide-content">SLIDE 1
    </div>
  </section>
  <section class="h-slide white" id="h-item2">
    <div class="slide-content">SLIDE 2
    </div>
  </section>
  <section class="h-slide red" id="h-item3">
    <div class="slide-content">SLIDE 3
    </div>
  </section>
  <section class="h-slide white" id="h-item4">
    <div class="slide-content">SLIDE 4
    </div>
  </section>
  <section class="h-slide blue" id="h-item5">
    <div class="slide-content">SLIDE 5
    </div>
  </section>

</div>
<div class="scrub_container">
  <div class="scrub_bar scrubber" id="js-scrub">
    <div class="empty"></div>
    <div class="scrub_bar progress scrub_white" id="js-scrub-component"></div>
  </div>
</div>
              
            
!

CSS

              
                :root{ 
  --scrubWidth:300px;
  --indicatorWidth:20vw;
}

body { 
  margin: 0; 
  padding:0;
  overflow-x: hidden;
}
ul{
  margin:0;
  padding:0;
}
ul li{
  cursor:pointer;
}
#horizontal-menu-head{
  position:fixed;
  top:20px;
  left:20px;
  color:#fff;
  z-index:1000;
}
.h-menu-head{
  list-style:none;
  display:flex;
}
.h-menu-head li {
  padding:10px;
}
.h-menu-head li a {
  color:#fff;
}

.h-slide .char.visible{
  color:red;
}

.horizontal-scroll{
    display: inline-block;
  white-space: nowrap;
  font-size:0;
/*   overflow-x:scroll; */
}

.h-slide{
/*   padding-top:50px; */
  width:100vw;
  height:100vh;
  display:inline-block;
  font-size:50px;
}

.h-slide.white{
  background-color:#ccc;
  color:#4D4D4F;
}

.h-slide.blue{
  background-color:#00597C;
  color:#fff;
}

.slide-content{
  padding:50px;
}

.red{
    background-color: #cf3535;
  background-image: none;
}

.scrub_container{
    position:fixed;
  bottom:20px;
  left:0;
}

.scrub_bar {
  width:100vw;
  width:var(--scrubWidth);
  height:20px;
  position:absolute;  
}

.scrubber {
/*   left:20px;
  bottom:20px; */
  background:red;
}

.scrub_red {
  background:red;
}

.scrub_white {
  background:white;
}

.scrub_trigger {
  background:blue;
  opacity:0.3;
}

.empty {
  width:20vw;
  width:var(--indicatorWidth);
  height:20px;
  top:0px;
  background:green;
  position:absolute;
}


              
            
!

JS

              
                

$(window).on('load resize', function () {
  // STEP 1  ***************************
  // Set the scrubber width to the window width
  let root = document.documentElement;
  root.style.setProperty('--scrubWidth', innerWidth + "px");
  let scrubberWidth = innerWidth;
  // Get all slides and dimensions to work with
  let hcontainer = document.getElementById("h-container");
  let hsections = gsap.utils.toArray(".h-slide");
  let secCount = hsections.length;
  let secWidth = innerWidth / secCount;
  let containerBounds = getBounds(hcontainer);
  let containerWidth = containerBounds.width;
  let scrollWidth = hcontainer.offsetWidth - innerWidth;


  // STEP 2  -set up the draggable div - from https://codepen.io/GreenSock/pen/WNxRKae 

  const proxy = document.createElement("div");
  var draggable = Draggable.create(proxy, {
    trigger: "#h-container",
    type: "x",
    inertia: true,
    autoScroll: 1,
    onDrag: function() {
      trigger.scroll(-this.x);
    }
  })[0];
  draggable.applyBounds({ minX: -scrollWidth, maxX: 0 });
  
  //STEP 3 - create anim for horizontal pages 
  var animhere = gsap.to(hsections, {
    // xPercent: -100 * (hsections.length - 1),
    x: () => -scrollWidth,
    ease: "none",
  });

  //STEP 4 - create scrolltrigger for left right scrolling with scrollwheel or vertical scrubber in browser
  var trigger;
  trigger = ScrollTrigger.create({
    animation: animhere,
    id: 'tlScroller',
    trigger: "#h-container",
    pin: true,
    scrub: 1,
    snap: 1 / (hsections.length - 1),
    // markers:true,
    // base vertical scrolling on how wide the container is so it feels more natural.
    end: () => "+=" + (document.querySelector(".horizontal-scroll").offsetWidth - innerWidth),
    invalidateOnRefresh: true,
    //this may not work??? 
    onUpdate: updateProxy(this)
  });

    //update draggable when scrolling with mouse **** DONT THINK THIS WORKS
  function updateProxy(el) {
    // move the handler to the corresponding ratio according to the page's scroll position.
    gsap.set(proxy, { x: -el.scroll() });
  };
  
  //STEP 5 - wait till all scroll updates have taken place and then correct the scrubber visually
  ScrollTrigger.addEventListener("scrollEnd", updateProgressBarCosmetic);

  //update the scrubber without scrolling the window (because it already has)
  function updateProgressBarCosmetic(){
    var top = window.pageYOffset;
    var newProgBarWidth = top / containerWidth;
    var newIndicatorPos = scrubberWidth * newProgBarWidth;

    console.log("scrolling ended! " + newProgBarWidth + " " + top);

    TweenLite.set(".progress", {scaleX:newProgBarWidth});
    TweenLite.set(".empty", {x:newIndicatorPos});
  }



  
  // STEP 7 top menu ***************************
  // make slides nav at top clickable
  document.querySelectorAll("li.h-link").forEach((btn, index) => {
    btn.addEventListener("click", () => {
      gsap.to(window, {duration: 1, scrollTo:{y:(index * innerWidth), offsetY:0}});
    });
  });  




  // STEP 8 Scrubber ***************************
  // offset left just tells the functions where the scrubber sits on the page eg 20px from left
  var offsetLeft = $('.scrubber').offset().left;
  // scrubberWidth is the total width of the div scrubber 

  // console.log("Scrubbers offset from left " + offsetLeft)

  // progress is the (white) div that covers the scrubber from the left to show the area before where the current point is.  This is shown by the empty class (green line)
  TweenLite.set(".progress", {scaleX:0, transformOrigin:"left"});
  Draggable.create(".empty", {
    type:"x",
    trigger:".scrubber",
    bounds:".scrubber",
    onPress:function(e) {

      //move the target (".empty") based on where you clicked
      TweenLite.set(this.target, {x:this.pointerX- offsetLeft});
      //update Draggable's internal recording of where ".empty" is
      this.update();
      //stretch the progress bar
      updateProgressBarScale(this);
    },
    onDrag:function() {
      updateProgressBarScale(this); 
    }
  })

  //this updates the visual css of the scrubber and then makes the page scroll to the right location
  function updateProgressBarScale(theDraggable) {
    //   get the xpoint and turn into a percentage
    console.log("updateProgressBarScale - drag X is " + theDraggable.x )
    var progress = theDraggable.x / scrubberWidth;
    //   set the width of the .progress div
    TweenLite.set(".progress", {scaleX:progress});
    console.log(theDraggable.x + " / " + progress);
    //  console.log(slidesWidth + "width");
    var slidesSet = containerWidth * progress;

    console.log("updateProgressBarScale - NEW X" + slidesSet);
    //   set the scroll width
    gsap.to(window, {duration: 2, scrollTo: slidesSet});
  }

  //this gets dimensions of dom objects
  function getBounds(el) {
    var rect = el.getBoundingClientRect();
    return {
      x: rect.left,
      y: rect.top,
      width: rect.width,
      height: rect.height
    };
  };
});





// function updateProgressBarScaleExternal(theDraggable) {
//   var progress = theDraggable.x / scrubberWidth;
//   TweenLite.set(".progress", {scaleX:progress});
//   console.log("updateProgressBarScaleExternal" + theDraggable.x + " / " + progress);
// }

// function getCurrentPosition() {
//   //update the window scroll position
//   var mainSection = document.getElementById("h-container");
//   var mainDimensions = getBounds(mainSection);
//   var mainWidth = mainDimensions.width;
//   var mainX = mainDimensions.x;
//   var doc = document.body;//document.body.scrollTop,
// var top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
//   console.log("getCurrentPosition - TOP " + top)
//   var newPos = 300 / mainX;
//   console.log("getCurrentPosition - NEW POS" + newPos)
//   // return {
//   //   newPos: 1,
//   // };

// };



//*************************** IGNORE FROM HERE ***************************


// // Get all the slides that have section.white 
// var slideSelect=document.querySelectorAll("section.white");
// // Consloe log all slides that are section.white
// slideSelect.forEach((slide, index) => {
//  // console.log("SLIDE " + slide.offsetLeft + " NUMBER " +index);
// });	

// Get all the slides
// var headSelectors=document.querySelectorAll("section .slide-content");
// //FIRST LOOP - Get all teh headings and break into words and characters, add classes
// headSelectors.forEach((header, index) => {
//   //console.log("hs " + header.offsetLeft + " index " +index);
//   //const splitThis = header.querySelector(".slide-content");
//   const split = new SplitText(header,{type: "words,chars", wordsClass: index+"-word word word++", charsClass: "char char++"});
// });	

// // get all teh individual characters that have had .char added then add a scroll trigger to them that changes their look (toggle class .visible)
// var colorChars=document.querySelectorAll(".char");

// colorChars.forEach((letter, count) => {
//   //console.log("letter " + letter.offsetLeft + " index " +count);
//   var bounds=getBounds(letter);
//   var boundsX=bounds.x;
//   // console.log("letter " +count+ " X="+  boundsX );
//   // console.log("letter " +count+ " y="+  bounds.y );
//   // console.log("letter " +count+ " WIDTH="+  bounds.width );
//   // console.log("letter " +count+ " HEIGHT="+  bounds.height );
//   // gsap.to(letter, {
//   //   scrollTrigger: {
//   //     start: () => boundsX-500,
//   //     end: () => boundsX + 500,
//   //     id:"startheader"+count,
//   //     toggleClass: 'visible',
//   //     //  animation:anim,   
//   //     scrub:1,
//   //     markers: true
//   //   } 
//   // })
//   ScrollTrigger.create({
//     trigger:letter,
//     start: () => boundsX-1000,
//     end: () => boundsX,// - 100,
//     id:"startheader"+count,
//     toggleClass: 'visible',
//     //  animation:anim,   
//     scrub:1,
//     // markers: true
//   });
// });	

              
            
!
999px

Console