4

There are some single page applications where a user can carry on vertically scrolling -- but the page looks paused and scrolls horizontally - and then clears a section.

I am unsure though how they do this -- I've seen transform styles being applied but not really sure what happens to the elements that would have been there naturally if the user were to scroll normally.

I've added the jquery wayward function to detect when a nested spread is displayed.

Something like this:

enter image description here

Here is the HTML fragment. Slide 1 is a full page element, as is slide 5 and 6. These could be anchors to a menu. The behavior I am interested in creating here - is as the user approaches the nested unit - it locks at the top of slide 2, then transforms slides 3 and 4.

$win.on('scroll', function() {
  var top = $win.scrollTop() / 3;
  console.log("top", top);
  $nested.css('transform', 'translate(' + -top + 'px, 0)');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section">slide 1</div>
<div class="nested">
  <div class="section first">slide 2</div>
  <div class="section second">slide 3</div>
  <div class="section third">slide 4</div>
</div>
<div class="section">slide 5</div>
<div class="section">slide 6</div>

JSFiddle Example

double-beep
  • 5,031
  • 17
  • 33
  • 41
The Old County
  • 89
  • 13
  • 59
  • 129
  • I've tried to capture the necessary pieces of information nested section heights and widths, counts - the scroll works as you scroll down - and I've tried to now clear the sticky and horizontal scroll once the last section is cleared -- but its malfunctioning continuing on to slide 5 and reversing the feature - https://jsfiddle.net/zny0c8s6/ – The Old County Jun 23 '19 at 06:37

2 Answers2

7

This is just to give you an idea how it can be achieved. You need a placeholder container that retains the vertical space when your slides become fixed elements.

The following code can handle multiple slides in the same page, you can also implement your own once you get the idea.

$('.nested').each(function() {
  let $window = $(window), $body = $('body');
  let $nested = $(this), $nestedPlaceholder = $nested.parent();
  let verticalScrollRange, upperMargin, lowerMargin;
  $window.resize(function(){
    $nested.removeClass("sticky").css({left: 0});
    let placeholderHeight = $nestedPlaceholder.css({height: ''}).height();
    verticalScrollRange = placeholderHeight - $window.height();
    upperMargin = $nestedPlaceholder.offset().top;
    lowerMargin = upperMargin + verticalScrollRange;
    $nestedPlaceholder.height(placeholderHeight);
  });
  $window.scroll(function() {
    let scrollTop = $window.scrollTop();
    if (scrollTop > upperMargin && scrollTop < lowerMargin) {
      $nested.addClass("sticky");
      let horizontalScrollRange = $nested.width() - $body.width();
      let verticalScrollPosition = scrollTop - upperMargin;
      let horizontalScrollPosition = verticalScrollPosition / verticalScrollRange * horizontalScrollRange;
      $nested.css({left: -horizontalScrollPosition});
    } else {
      $nested.removeClass("sticky");
    }
  });
  $window.resize();
});
body {
  background: linear-gradient(to bottom, #ffcb77 0%, #deaaff 100%);
}

.section {
  height: 100vh;
  font-size: 5em;
  text-align: center;
  position: relative;
  border: 1px solid red;
}

.nested .section {
  width: 100vw;
}

.nested-placeholder {
  overflow: hidden;
}

.sticky {
  position: fixed;
  z-index: 1;
  top: 0;
  height: 100vh;
  white-space: nowrap;
}

.sticky .section {
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section">Start scrolling down!</div>
<div class="section">slide 1</div>
<div class="nested-placeholder">
  <div class="nested">
    <div class="section first">slide 2</div>
    <div class="section second">slide 3</div>
    <div class="section third">slide 4</div>
  </div>
</div>
<div class="section">slide 5</div>
<div class="section">slide 6</div>
Munim Munna
  • 17,178
  • 6
  • 29
  • 58
  • yours has a weird jolt when it gets to the end of slide 4. Would this work in a responsive setting too - like if the user flipped an ipad orientation? – The Old County Jun 25 '19 at 02:17
  • could you fix the bug to make it a smoother transition - tidy the code up a bit more – The Old County Jun 27 '19 at 00:54
  • What part do you want to tidy up? The transition is due to the show/hide of fixed `.nested` elements, can't get rid of it anyways. You can reduce the jolt removing borders, margins, paddings from the slide and making the slide exactly same size of the window. Try it, I will help if you get stuck. – Munim Munna Jun 27 '19 at 01:08
  • cheers - I got another scrolling problem that needs solving -- https://stackoverflow.com/questions/56799635/banana-sprite-js-bespoke-forward-and-backward-animations-with-json-data – The Old County Jun 28 '19 at 21:58
0

I've come up with this solution that will activate the horizontal scroll sticky - when the slide hits the top of the page.

https://jsfiddle.net/zny0c8s6/

When the nested slide hits the top of the page, a sticky class is added to the nest. This fixes the batch position fixed and converts the nest into a loose carousel. As the user continues to scroll down the nest is translated horizontally. After the last nested slide is cleared then I've removed the sticky class - and to have the user appear on the normal journey tried to fix the nest to the height of a slide and the count. Although reversing direction needs to be tackled - also if there are multiple nests.

$nested.waypoint(function(direction) {    
  var distance = $nested.offset().top;
  var $nestedHeight = $nested.height();
  var $nestedCount = $nested.find(" > .section").length;
  var $nestedSectionWidth = $nested.next(".section").eq(0).width();

  var clearNestedWidth = $nestedSectionWidth * $nestedCount;
  var $window = $(window);

  $window.scroll(function() {
    if ($window.scrollTop() >= distance) {
      // Your div has reached the top        
      $nested.addClass("sticky");

      var $nestedCompactWidth = $nested.width();    
      var $win = $(window);

      $win.on('scroll', function() {
        var top = $win.scrollTop() / 3;   
        $nested.css('transform', 'translate(' + -top + 'px, 0)');

        if (top >= clearNestedWidth) {
          console.log("cleared slides - now clear sticky")
          $nested.removeClass("sticky");              
          $nested.css('height', $nestedHeight);
          //set scroll to end of slide 2
        }
      });

    } else {
      //$nested.removeClass("sticky");
    }
  });


}, {
  offset: '50%'
});
The Old County
  • 89
  • 13
  • 59
  • 129
  • The translation maybe needs to be revaluated var newDistance = top - distance; $nested.css('transform', 'translate(' + ($nestedSectionWidth-newDistance) + 'px, 0)'); – The Old County Jun 23 '19 at 06:53
  • what if ALL panels are nested - but some contain just 1 slide so the horizontal slide doesn't show -- that way the functionality could be more dynamic to make it work if new slides are added to different solo areas – The Old County Jun 23 '19 at 19:27