Il suffit de désactiver le défilement pour ne pas le cacher?

198

J'essaie de désactiver la barre de défilement html / body du parent pendant que j'utilise une lightbox. Le mot principal ici est désactiver . Je ne pas envie de le cacher avec overflow: hidden;.

La raison en est que overflow: hiddenle site saute et occupe la zone où se trouvait le parchemin.

Je veux savoir s'il est possible de désactiver une barre de défilement tout en l'affichant.

Dejan.S
la source
1
Un défilement doit-il être possible? (La lightbox a-t-elle des barres de défilement?)
Šime Vidas
le site a défilé mais je veux juste le désactiver pendant que la lightbox est ouverte. je veux juste savoir s'il est possible de désactiver une barre de défilement tout en la montrant. rien d'autre n'est nécessaire comme comment le faire dans une lightbox ou autre chose.
Dejan.S
quel est le problème avec lightbox avec barre de défilement?
manny
1
@Dejan Parce que je sais comment désactiver tous les défilements - cela désactiverait la barre de défilement principale, mais aussi celle de la lightbox ...
Šime Vidas
1
Veuillez ne pas modifier la réponse dans cet article. La section des réponses ci-dessous est pour les réponses. Si vous avez une réponse à votre question différente de la réponse ci-dessous, vous pouvez ajouter votre propre solution dans la sélection de réponses.
intcreator

Réponses:

173

Si la page sous la superposition peut être "fixée" en haut, lorsque vous ouvrez la superposition, vous pouvez définir

body { position: fixed; overflow-y:scroll }

vous devriez toujours voir la barre de défilement de droite, mais le contenu ne peut pas défiler. Lorsque vous fermez la superposition, rétablissez simplement ces propriétés avec

body { position: static; overflow-y:auto }

Je viens de proposer cette méthode uniquement parce que vous n'auriez pas besoin de modifier un événement de défilement

Mettre à jour

Vous pouvez également faire une légère amélioration: si vous obtenez la document.documentElement.scrollToppropriété via javascript juste avant l'ouverture du calque, vous pouvez affecter dynamiquement cette valeur en tant que toppropriété de l'élément body: avec cette approche, la page restera à sa place, peu importe si vous '' re en haut ou si vous avez déjà fait défiler.

Css

.noscroll { position: fixed; overflow-y:scroll }

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');
Fabrizio Calderan
la source
2
ça dérange ma mise en page mais avec quelques modifications ça pourrait bien marcher. j'aime ça je vais l'essayer plus
Dejan.S
4
avec une petite modification, cela fonctionne. j'ai ajouté une largeur: 100%; je suis allé mettre à jour ma question avec la solution mais vous pouvez modifier votre avec la largeur: 100% ;? merci pour la suggestion
Dejan.S
3
Je ne sais pas pourquoi, mais cela fonctionne mieux pour moi: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII
4
@whitesiroi, vous avez raison. J'ai mis à jour le violon: jsfiddle.net/evpozdniakov/2m8km9wg Merci!
evpozdniakov
1
Pour ceux qui lisent les commentaires d'une solution, le dernier violon fournit une solution pour désactiver et réactiver la barre de défilement tout en conservant la position de la barre de défilement dans les deux cas. Merci!
user1063287
78

Quatre petits ajouts à la solution sélectionnée:

  1. Appliquer «noscroll» au html au lieu du corps pour éviter les doubles barres de défilement dans IE
  2. Pour vérifier s'il existe réellement une barre de défilement avant d'ajouter la classe «noscroll». Sinon, le site sautera également poussé par la nouvelle barre de défilement sans défilement.
  3. Pour conserver tout scrollTop possible afin que la page entière ne remonte pas en haut (comme la mise à jour de Fabrizio, mais vous devez saisir la valeur avant d'ajouter la classe 'noscroll')
  4. Tous les navigateurs ne gèrent pas scrollTop de la même manière que celle décrite sur http://help.dottoro.com/ljnvjiow.php

Solution complète qui semble fonctionner pour la plupart des navigateurs:

CSS

html.noscroll {
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

Désactiver le défilement

if ($(document).height() > $(window).height()) {
     var scrollTop = ($('html').scrollTop()) ? $('html').scrollTop() : $('body').scrollTop(); // Works for Chrome, Firefox, IE...
     $('html').addClass('noscroll').css('top',-scrollTop);         
}

Activer le défilement

var scrollTop = parseInt($('html').css('top'));
$('html').removeClass('noscroll');
$('html,body').scrollTop(-scrollTop);

Merci à Fabrizio et Dejan de m'avoir mis sur la bonne voie et à Brodingo pour la solution à la double barre de défilement

Mike Garcia
la source
1
Cela a bien fonctionné sur le bureau, mais sur l'iPhone, il a créé un écran blanc vierge jusqu'à ce que le lecteur tente de faire défiler la page. Une fois que le lecteur a tenté d'interagir avec la page, l'écran prévu est devenu visible avec le défilement verrouillé.
Michael Khalili
Cela fonctionnait parfaitement avec Fancybox sur iPad pour désactiver le défilement de l'image lightbox avec afterLoad()et les afterCloserappels. Peut être utile pour les autres personnes qui recherchent cette question.
Tomanow
Dans la partie "activer le défilement", vous souhaiterez peut-être supprimer l'attribut style placé sur l'élément html après un appel à "désactiver le défilement"; n'est-ce pas?
Ben
3
jQuery standardise les DOM natifs de scrollToptelle sorte que la ligne 2 du code «Désactiver le défilement» peut être exprimée sous la forme $( window ).scrollTop().
Barney
Je pense qu'une autre chose doit être ajoutée à cela. Sur Chrome dans OSX, il est possible que le navigateur "survole", donnant au défilement une sensation élastique. Avec ce code si vous êtes dans la zone grise au-dessus ou en dessous de la page et que vous survolez un endroit où vous désactivez le défilement. Il collera à un endroit au-dessus / en dessous de la fenêtre du navigateur. Pour cette raison , vous devez ajouter un chèque d'une valeur de défilement négative: if (scrollTop < 0) { scrollTop = 0; }. Voici le code complet pour désactiver gist.github.com/jayd3e/2eefbbc571cd1668544b .
JayD3e
34

Avec jQuery inclus:


désactiver

$.fn.disableScroll = function() {
    window.oldScrollPos = $(window).scrollTop();

    $(window).on('scroll.scrolldisabler',function ( event ) {
       $(window).scrollTop( window.oldScrollPos );
       event.preventDefault();
    });
};

activer

$.fn.enableScroll = function() {
    $(window).off('scroll.scrolldisabler');
};

usage

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();
ceed
la source
1
c'était parfait pour moi, la réponse précédente a fait rebondir ma page, celle-ci ne le fait pas
Bogdan Tomi
heureux d' avoir pu aider, vous pourriez avoir besoin de vérifier « touchmove » aussi, pour les appareils mobiles, hourras
Ceed
Eh bien, cela a presque fonctionné pour moi. Cela a fait des merveilles sur Windows (Firefox, Chrome) et MacOS dans Firefox ... mais je suis ensuite passé à Windows IE et Edge, ainsi qu'à MacOS dans Chrome et Safari. Le problème ne concernait plus le saut de page d'un côté à l'autre, mais la barre de défilement sautait du haut vers la position actuelle ou la page clignotait en haut. Mec, c'était tellement , si proche. Peut-être que nous pouvons encore le faire fonctionner.
Steven Ventimiglia
Cela a parfaitement fonctionné pour moi, merci! Utilisation idéale sur un site Web où le menu de superposition est également en bas de la page!
SauriolJf
12

Je suis l'OP

Avec l'aide de la réponse de fcalderan, j'ai pu trouver une solution. Je laisse ma solution ici car elle clarifie la façon de l'utiliser et ajoute un détail très crucial,width: 100%;

J'ajoute cette classe

body.noscroll
{
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

cela a fonctionné pour moi et j'utilisais Fancyapp.

Dejan.S
la source
11

Cela a très bien fonctionné pour moi ....

// disable scrolling
$('body').bind('mousewheel touchmove', lockScroll);

// enable scrolling
$('body').unbind('mousewheel touchmove', lockScroll);


// lock window scrolling
function lockScroll(e) {
    e.preventDefault();
}

enveloppez simplement ces deux lignes de code avec tout ce qui décide quand vous allez verrouiller le défilement.

par exemple

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});
dmackenz
la source
C'est la meilleure réponse de tous
Jafo
7

Vous ne pouvez pas désactiver l'événement de défilement, mais vous pouvez désactiver les actions associées qui mènent à un défilement, comme la molette de la souris et le déplacement tactile:

$('body').on('mousewheel touchmove', function(e) {
      e.preventDefault();
});
tocqueville
la source
4

Vous pouvez masquer la barre de défilement du corps avec overflow: hiddenet définir une marge en même temps afin que le contenu ne saute pas:

let marginRightPx = 0;
if(window.getComputedStyle) {
    let bodyStyle = window.getComputedStyle(document.body);
    if(bodyStyle) {
        marginRightPx = parseInt(bodyStyle.marginRight, 10);
    }
}

let scrollbarWidthPx = window.innerWidth - document.body.clientWidth;
Object.assign(document.body.style, {
    overflow: 'hidden',
    marginRight: `${marginRightPx + scrollbarWidthPx}px`
});

Et puis vous pouvez ajouter une barre de défilement désactivée à la page pour combler l'écart:

textarea {
  overflow-y: scroll;
  overflow-x: hidden;
  width: 11px;
  outline: none;
  resize: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  border: 0;
}
<textarea></textarea>

J'ai fait exactement cela pour ma propre implémentation de lightbox. Semble bien fonctionner jusqu'à présent.

mpen
la source
1
En fait, j'aime le mieux cette méthode. Très simple et fonctionne très bien. Merci!
dericcain
2

C'est la solution que nous avons choisie. Enregistrez simplement la position de défilement lorsque la superposition est ouverte, revenez à la position enregistrée chaque fois que l'utilisateur tente de faire défiler la page et désactivez l'écouteur lorsque la superposition est fermée.

C'est un peu nerveux sur IE, mais fonctionne comme un charme sur Firefox / Chrome.

var body = $("body"),
  overlay = $("#overlay"),
  overlayShown = false,
  overlayScrollListener = null,
  overlaySavedScrollTop = 0,
  overlaySavedScrollLeft = 0;

function showOverlay() {
  overlayShown = true;

  // Show overlay
  overlay.addClass("overlay-shown");

  // Save scroll position
  overlaySavedScrollTop = body.scrollTop();
  overlaySavedScrollLeft = body.scrollLeft();

  // Listen for scroll event
  overlayScrollListener = body.scroll(function() {
    // Scroll back to saved position
    body.scrollTop(overlaySavedScrollTop);
    body.scrollLeft(overlaySavedScrollLeft);
  });
}

function hideOverlay() {
  overlayShown = false;

  // Hide overlay
  overlay.removeClass("overlay-shown");

  // Turn scroll listener off
  if (overlayScrollListener) {
    overlayScrollListener.off();
    overlayScrollListener = null;
  }
}

// Click toggles overlay
$(window).click(function() {
  if (!overlayShown) {
    showOverlay();
  } else {
    hideOverlay();
  }
});
/* Required */
html, body { margin: 0; padding: 0; height: 100%; background: #fff; }
html { overflow: hidden; }
body { overflow-y: scroll; }

/* Just for looks */
.spacer { height: 300%; background: orange; background: linear-gradient(#ff0, #f0f); }
.overlay { position: fixed; top: 20px; bottom: 20px; left: 20px; right: 20px; z-index: -1; background: #fff; box-shadow: 0 0 5px rgba(0, 0, 0, .3); overflow: auto; }
.overlay .spacer { background: linear-gradient(#88f, #0ff); }
.overlay-shown { z-index: 1; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<h1>Top of page</h1>
<p>Click to toggle overlay. (This is only scrollable when overlay is <em>not</em> open.)</p>
<div class="spacer"></div>
<h1>Bottom of page</h1>
<div id="overlay" class="overlay">
  <h1>Top of overlay</h1>
  <p>Click to toggle overlay. (Containing page is no longer scrollable, but this is.)</p>
  <div class="spacer"></div>
  <h1>Bottom of overlay</h1>
</div>

0b10011
la source
Fonctionne en effet, mais altère la conception en cas d'en-tête fixe, car la barre de défilement plonge sous elle.
Leon Willens
@LeonWillens Je ne sais pas ce que tu veux dire. Si vous êtes préoccupé par la superposition apparaissant sous une rubrique fixe, vous devrez régler le z-indexde .overlay-shownpour être supérieur à l' en- tête fixe. (J'ai ce code en cours de production sur un site avec un en-tête fixe et cela fonctionne très bien.)
0b10011
Non, je parlais de la barre de défilement de la bodybalise. J'ai testé votre code hier et j'ai un en-tête fixe en haut de ma page. Si je gère le défilement via la bodybalise, la barre de défilement sera sous l'en-tête fixe.
Leon Willens
1
@LeonWillens Oups, on dirait que j'ai corrigé cela en production à un moment donné et oublié de le mettre à jour. Il semble qu'au lieu de $("body"), nous utilisons $(window). Et au lieu de z-index: -1sur la superposition pour le cacher, vous pouvez utiliser visibility: hiddenou similaire. Voir jsfiddle.net/8p2gfeha pour un test rapide pour voir si cela fonctionne. L'en-tête fixe n'apparaît plus en haut de la barre de défilement. J'essaierai éventuellement d'intégrer ces changements dans la réponse.
0b10011
Fonctionne comme un charme! Merci :)
Leon Willens
1

J'ai eu un problème similaire: un menu de gauche qui, lorsqu'il apparaît, empêche le défilement. Dès que la hauteur a été fixée à 100vh, la barre de défilement a disparu et le contenu a basculé vers la droite.

Donc, si cela ne vous dérange pas de garder la barre de défilement activée (mais de régler la fenêtre sur toute sa hauteur pour qu'elle ne défile pas n'importe où), une autre possibilité consiste à définir une petite marge inférieure, qui gardera les barres de défilement montrant:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}
dhc
la source
Cela overflow:hiddenn'empêche- t-il pas la marge d'avoir un effet?
Koja
0

vous pouvez garder le débordement: caché mais gérer la position de défilement manuellement:

avant d'afficher la trace de la position réelle du défilement:

var scroll = [$(document).scrollTop(),$(document).scrollLeft()];
//show your lightbox and then reapply scroll position
$(document).scrollTop(scroll[0]).scrollLeft(scroll[1]);

ça devrait marcher

malko
la source
0

Le moyen grossier mais fonctionnel sera de forcer le défilement vers le haut, désactivant ainsi efficacement le défilement:

var _stopScroll = false;
window.onload = function(event) {
    document.onscroll = function(ev) {
        if (_stopScroll) {
            document.body.scrollTop = "0px";
        }
    }
};

Lorsque vous ouvrez la lightbox, soulevez le drapeau et lorsque vous le fermez, abaissez le drapeau.

Cas de test en direct .

L'assistant de l'ombre est à votre écoute
la source
0

J'aime m'en tenir à la méthode "overflow: hidden" et simplement ajouter un padding-right égal à la largeur de la barre de défilement.

Obtenez la fonction de largeur de la barre de défilement, par lostsource .

function getScrollbarWidth() {
    var outer = document.createElement("div");
    outer.style.visibility = "hidden";
    outer.style.width = "100px";
    outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps

    document.body.appendChild(outer);

    var widthNoScroll = outer.offsetWidth;
    // force scrollbars
    outer.style.overflow = "scroll";

    // add innerdiv
    var inner = document.createElement("div");
    inner.style.width = "100%";
    outer.appendChild(inner);        

    var widthWithScroll = inner.offsetWidth;

    // remove divs
    outer.parentNode.removeChild(outer);

    return widthNoScroll - widthWithScroll;
}

Lors de l'affichage de la superposition, ajoutez la classe "noscroll" au html et ajoutez padding-right au corps:

$(html).addClass("noscroll");
$(body).css("paddingRight", getScrollbarWidth() + "px");

Lorsque vous vous cachez, supprimez la classe et le rembourrage:

$(html).removeClass("noscroll");
$(body).css("paddingRight", 0);

Le style noscroll est juste ceci:

.noscroll { overflow: hidden; }

Notez que si vous avez des éléments avec position: fixed, vous devez également ajouter le remplissage à ces éléments.

Janne Annala
la source
J'ai utilisé cette solution. Cela m'a aidé à éviter les doubles barres de défilement (une «vierge» pour le corps et une seconde pour le contenu de la superposition). Il fonctionne également très bien sur OSX qui peut ou non afficher les barres de défilement.
Novazembla
0

<div id="lightbox">est à l'intérieur de l' <body>élément, donc lorsque vous faites défiler la lightbox, vous faites également défiler le corps. La solution consiste à ne pas étendre l' <body>élément à plus de 100%, à placer le contenu long à l'intérieur d'un autre divélément et à ajouter une barre de défilement si nécessaire à cet divélément avec overflow: auto.

html {
  height: 100%
}
body {
  margin: 0;
  height: 100%
}
#content {
  height: 100%;
  overflow: auto;
}
#lightbox {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
<html>
  <body>
    <div id="content">much content</div>
    <div id="lightbox">lightbox<div>
  </body>
</html>

Maintenant, faire défiler la lightbox (et le bodyaussi) n'a aucun effet, car le corps ne dépasse pas 100% de la hauteur de l'écran.

Marek C
la source
0

Tous les systèmes basés sur javascript modal / lightbox utilisent un débordement lors de l'affichage du modal / lightbox, sur la balise html ou la balise body.

Lorsque la lightbox est affichée, le js pousse un débordement caché sur le html ou la balise body. Lorsque la lightbox est masquée, certaines suppriment les autres masquées poussent un débordement automatique sur le html ou la balise body.

Les développeurs qui travaillent sur Mac, ne voient pas le problème de la barre de défilement.

Il suffit de remplacer le caché par un unset pour ne pas voir le contenu glisser sous le modal de la suppression de la barre de défilement.

Lightbox ouvert / montrer:

<html style="overflow: unset;"></html>

Fermer / masquer la visionneuse:

<html style="overflow: auto;"></html>
Visière
la source
0

Si la page sous la superposition peut être "fixée" en haut, lorsque vous ouvrez la superposition, vous pouvez définir

.disableScroll { position: fixed; overflow-y:scroll }

fournissez cette classe au corps défilant, vous devriez toujours voir la barre de défilement droite mais le contenu n'est pas défilable.

Pour conserver la position de la page, faites ceci en jquery

$('body').css('top', - ($(window).scrollTop()) + 'px').addClass('disableScroll');

Lorsque vous fermez la superposition, rétablissez simplement ces propriétés avec

var top = $('body').position().top;
$('body').removeClass('disableScroll').css('top', 0).scrollTop(Math.abs(top));

Je viens de proposer cette méthode uniquement parce que vous n'auriez pas besoin de modifier un événement de défilement

Bhuvan Arora
la source
0

Cela empêchera la fenêtre de sauter vers le haut en enregistrant la position de défilement et en la restaurant en activant le défilement.

CSS

.no-scroll{
  position: fixed; 
  width:100%;
  min-height:100vh;
  top:0;
  left:0;
  overflow-y:scroll!important;
}

JS

var scrollTopPostion = 0;

function scroll_pause(){
  scrollTopPostion = $(window).scrollTop();
  $("body").addClass("no-scroll").css({"top":-1*scrollTopPostion+"px"});
}

function scroll_resume(){
  $("body").removeClass("no-scroll").removeAttr("style");
  $(window).scrollTop(scrollTopPostion);
}

Il ne vous reste plus qu'à appeler les fonctions

$(document).on("click","#DISABLEelementID",function(){
   scroll_pause();
});

$(document).on("click","#ENABLEelementID",function(){
   scroll_resume();
});
Kareem
la source
-1

Vous pouvez le faire avec Javascript:

// Classic JS
window.onscroll = function(ev) {
  ev.preventDefault();
}

// jQuery
$(window).scroll(function(ev) {
  ev.preventDefault();
}

Et puis désactivez-le lorsque votre lightbox est fermée.

Mais si votre lightbox contient une barre de défilement, vous ne pourrez pas faire défiler pendant qu'elle est ouverte. En effet, windowcontient à la fois bodyet #lightbox. Il faut donc utiliser une architecture comme la suivante:

<body>
  <div id="global"></div>
  <div id="lightbox"></div>
</body>

Et puis appliquez l' onscrollévénement uniquement sur #global.

ldiqual
la source