Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS scroll-snap-type with Horizontal Scrolling

I made a website that makes use of Bootstrap 4, horizontal scrolling (via jquery.mousewheel.js) and native CSS Snapping. I am using Chrome 81, and don't care about old/unsupported browsers.

When I apply scroll-snap-type: x mandatory; to CSS, the horizontal scrolling stops working (no scrolling happens at all). If the CSS property is removed, the scrolling behaves normally. Here is my HTML structure:

<div class="portfolio_content container-fluid h-100">
  <div class="row h-100 flex-row flex-nowrap scrollx long_content">
    <div class="col-12 h-100 project d-table" id="project1">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 1
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project2">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 2
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project3">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 3
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project4">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 4
        </p>
      </div>
    </div>
  </div>
</div>

For CSS, the key entries are here:

html, body {
    height: 100%;
}
.portfolio_content .scrollx {
    overflow-x: scroll;
}

.portfolio_content .long_content {
    scroll-snap-type: x mandatory; /* Comment this to make scrolling works */
}
.portfolio_content .project {
    scroll-snap-align: start;
}
.portfolio_content .project_title {
    display: block;
    margin: auto;
    text-align: center;
}
.portfolio_content .project_title h1 {
    font-size: 96px;
    line-height: 0.8;
}

Last, here is the JSFiddle demo. If you comment line 9 in CSS, the demo will be able to scroll.

My aim is to allow the "project" DIV to be snapped when scrolling, i.e. one "project" DIV will be fully shown after scrolling.

How should I change the codes?

like image 949
Raptor Avatar asked May 14 '20 09:05

Raptor


People also ask

How do I use snap scroll in CSS?

The scroll container snaps to snap positions in both of its axes independently (potentially snapping to different elements in each axis). The visual viewport of this scroll container will rest on a snap point if it isn't currently scrolled. That means it snaps on that point when the scroll action finished, if possible.

How do I horizontally scroll in CSS?

To enable horizontal scrolling, we can use the CSS property overflow-x. If we assign the value scroll to the overflow-x property of the container element, the browser will hide horizontally overflowing content and make it accessible via horizontal scrolling.

How do I create a horizontal scrolling container?

For horizontal scrollable bar use the x and y-axis. Set the overflow-y: hidden; and overflow-x: auto; that will automatically hide the vertical scroll bar and present only the horizontal scrollbar. The white-space: nowrap; property is used to wrap text in a single line.


2 Answers

You dont need an external plugin when you can do it with a simple script.

$(".portfolio_content .project").on('wheel', function(e) {
    e.preventDefault();        
    if (e.originalEvent.wheelDelta >= 0) {
        if ($(this).prev().length) {
            var prev = "#" + $(this).prev().attr("id");
            document.querySelector(prev).scrollIntoView({behavior: 'smooth'});
        }
    } else {
        if ($(this).next().length) {
            var next = "#" + $(this).next().attr("id");
            document.querySelector(next).scrollIntoView({behavior: 'smooth'});
        }
    }
});
html, body {
    height: 100%;
}
.portfolio_content .scrollx {
    overflow-x: scroll;
}

.portfolio_content .project {
	scroll-snap-align: start;
}
.portfolio_content .project_title {
	display: block;
	margin: auto;
	text-align: center;
}
.portfolio_content .project_title h1 {
	font-size: 96px;
	line-height: 0.8;
}
#project1, #project3 {
    background-color: #EEE;
}
#project2, #project4 {
    background-color: #CCC;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

<div class="portfolio_content container-fluid h-100">
  <div class="row h-100 flex-row flex-nowrap scrollx long_content">
    <div class="col-12 h-100 project d-table" id="project1">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 1
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project2">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 2
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project3">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 3
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project4">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 4
        </p>
      </div>
    </div>
  </div>
</div>
like image 130
SilverSurfer Avatar answered Oct 08 '22 01:10

SilverSurfer


You need to convert the mousewheel delta from X to Y and apply it to the element which has the scrollbar, also prevent default on the vertical mousewheel interaction of the container, but you need it to set it to the width of the container or it won't be enough to push.

 // 'swipe' left or right with mouse wheel:
const container = document.querySelector('.long_content');

container.addEventListener('wheel', (evt) => {

evt.preventDefault(); 

//scroll deirection
 let delta = evt.deltaY;
 //take widht of container:
let contWidth = evt.target.offsetWidth;

// check direction and apply to contWidth
if(delta < 0){
contWidth = -contWidth;
}
     
  container.scrollLeft += contWidth;  

});

Here is the updated fiddle

like image 1
Plippie Avatar answered Oct 08 '22 01:10

Plippie