web-dev-qa-db-fra.com

CSS scroll-snap-type avec défilement horizontal

J'ai créé un site Web qui utilise Bootstrap 4, le défilement horizontal (via jquery.mousewheel.js ) et le snapping CSS natif. J'utilise Chrome 81, et ne vous souciez pas des navigateurs anciens/non pris en charge.

Quand je postule scroll-snap-type: x mandatory; en CSS, le défilement horizontal cesse de fonctionner (aucun défilement ne se produit). Si la propriété CSS est supprimée, le défilement se comporte normalement. Voici ma structure HTML:

<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>

Pour CSS, les entrées clés sont ici:

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;
}

Enfin, voici la démo JSFiddle . Si vous commentez la ligne 9 en CSS, la démo pourra défiler.

Mon but est de permettre au DIV "projet" d'être cassé lors du défilement, c'est-à-dire qu'un DIV "projet" sera entièrement affiché après le défilement.

Comment changer les codes?

10
Raptor

Réponse courte: supprimez le code javascript.

Réponse longue: mousewheel.js Est utile si vous voulez vérifier ou faire quelque chose sur les événements de roue. Dans ce cas, vous voulez simplement laisser le navigateur défiler. Vous prenez le contrôle de cet événement dans la fonction et empêchez la valeur par défaut, mais l'action par défaut est exactement ce que vous voulez.

Lorsque vous exécutez this.scrollLeft -= delta;, Il fait deux choses: scroll puis end scroll. le scroll-snap-type écoute end scroll et accroche l'élément. En fait, si vous ne supprimez que la ligne e.preventDefault();, une chose amusante se produit. L'élément vibre puis change. Dans ma compréhension, ce qui se passe est: 1) Événement de défilement par défaut, qui prend un certain temps. Pendant ce temps, 2) événement de roue, qui déclenche un événement de défilement beaucoup plus court. 3) snap. Puisque le deltaX de 2 est petit, vous arrivez à la position de départ. répétez 2 et 3 plusieurs fois. 4) L'événement de défilement par défaut se termine par un deltaX beaucoup plus grand. 5) snap.

En résumé, pour le comportement souhaité, il vaut mieux laisser le navigateur faire le défilement. Si vous voulez faire autre chose, vous devez éviter d'envoyer un signal end scroll À chaque fois qu'un événement mousewheel se déclenche. Pour ce faire, vous pouvez simplement éliminer les deux lignes de code à l'intérieur de la fonction molette de la souris et ajouter le code dont vous avez besoin.

EDIT après commentaire:

J'aurais dû deviner par le contexte, vous voulez transformer les événements de roue verticale en événements de roue horizontale. La première réponse fonctionne si vous envoyez un événement de roue horizontale (vous pouvez le faire avec un pavé tactile). La longue réponse tient toujours, donc la question est de savoir comment contourner le problème. J'ai pensé à quelques stratégies:

  • Annulez l'événement et créez un WheelEvent synthétique. De loin la solution la plus élégante, mais je ne pouvais pas la faire fonctionner. L'événement est distribué mais aucun défilement ne se produit:
 let lc = document.querySelector('.long_content');
 lc.addEventListener('wheel', function(e) {
   if (e.deltaY !== 0){
     e.preventDefault();
     let evt = new WheelEvent('wheel', {
       deltaX: e.deltaY
     });
     this.dispatchEvent(evt);
   }
   else{
     // The new event gets captured here
   }
  });

MODIFIER 2

Il existe de nombreuses stratégies pour que cela fonctionne, mais toutes ont leurs inconvénients. Le précédent a eu un impact minimal sur votre script, mais le changement a commencé après la fin de l'événement wheel. Ce paramètre et d'autres sont laissés au navigateur et ne seront pas sous votre contrôle.

J'ai ajouté un deuxième violon avec une autre stratégie qui donne le comportement que vous semblez vouloir ( https://jsfiddle.net/vhywmdb5/ ). J'espère que cela aide, mais chaque solution doit être peaufinée et il n'y a aucune garantie qu'elle fonctionnera avec tous les navigateurs. Malheureusement, la simulation d'événement dans mousewheel.js Est interrompue pour le moment.

0
vqf