Basta desativar a rolagem para não ocultá-la?

198

Estou tentando desativar a barra de rolagem html / body do pai enquanto estou usando uma mesa de luz. A palavra principal aqui é desativar . Eu não quero esconder isso overflow: hidden;.

A razão para isso é que overflow: hiddenfaz o site pular e ocupar a área onde estava o pergaminho.

Quero saber se é possível desativar uma barra de rolagem enquanto a mostra.

Dejan.S
fonte
1
Qualquer rolagem deve ser possível? (Será que o lightbox tem nenhum barras de rolagem?)
Šime Vidas
o site ficou rolando, mas eu só quero desativá-lo enquanto a mesa de luz estiver aberta. Eu só quero saber se é possível desativar uma barra de rolagem enquanto mostra. nada mais é necessário, como fazê-lo em uma mesa de luz ou qualquer outra coisa.
Dejan.S
qual é o problema ao usar o lightbox com a barra de rolagem?
Manny
1
@Dejan Porque eu sei como desativar todos rolagem - que iria desativar a barra de rolagem principal, mas também a da Luz ...
Šime Vidas
1
Por favor, não edite a resposta novamente nesta postagem. A seção de respostas abaixo é para respostas. Se você tiver uma resposta para sua pergunta diferente da resposta abaixo, adicione sua própria solução na seleção de respostas.
Intcreator 21/07

Respostas:

173

Se a página sob a camada superior puder ser "fixa" na parte superior, quando você abrir a sobreposição, poderá definir

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

você ainda deverá ver a barra de rolagem correta, mas o conteúdo não pode ser rolado. Ao fechar a sobreposição, basta reverter essas propriedades com

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

Apenas propus essa maneira apenas porque você não precisaria alterar nenhum evento de rolagem

Atualizar

Você também pode fazer uma pequena melhoria: se você obtiver a document.documentElement.scrollToppropriedade via javascript imediatamente antes da abertura da camada, poderá atribuir dinamicamente esse valor como toppropriedade do elemento body: com essa abordagem, a página permanecerá em seu lugar, independentemente de você ' re no topo ou se você já rolou.

Css

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

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');
Fabrizio Calderan
fonte
2
ele mexe com o meu layout, mas com algumas modificações pode funcionar. Gosto deste vai experimentá-lo mais
Dejan.S
4
com uma pequena modificação, isso funciona. eu adicionei uma largura: 100%; estou indo atualizar minha pergunta com a solução, mas você pode modificar seu com a largura: 100% ;? obrigado pela sugestão
Dejan.S
3
Eu não sei por que, mas isso funciona melhor para mim: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII
4
@whitesiroi, você está certo. Atualizei o violino: jsfiddle.net/evpozdniakov/2m8km9wg Obrigado!
evpozdniakov
1
Para aqueles que leem os comentários de uma solução, o último violino fornece uma solução para desativar e reativar a barra de rolagem, mantendo a posição da barra de rolagem nos dois casos. Obrigado!
precisa saber é o seguinte
78

Quatro pequenas adições à solução selecionada:

  1. Aplique 'noscroll' ao html em vez de ao corpo para evitar barras de rolagem duplas no IE
  2. Para verificar se há realmente uma barra de rolagem antes de adicionar a classe 'noscroll'. Caso contrário, o site também será pressionado pela nova barra de rolagem sem rolagem.
  3. Para manter qualquer scrollTop possível para que a página inteira não volte ao topo (como a atualização do Fabrizio, mas você precisa pegar o valor antes de adicionar a classe 'noscroll')
  4. Nem todos os navegadores manipulam o scrollTop da mesma maneira como documentado em http://help.dottoro.com/ljnvjiow.php

Solução completa que parece funcionar para a maioria dos navegadores:

CSS

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

Desativar rolagem

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

Ativar rolagem

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

Agradeço a Fabrizio e Dejan por me colocarem no caminho certo e a Brodingo pela solução para a barra de rolagem dupla

Mike Garcia
fonte
1
Isso foi bem testado na área de trabalho, mas no iPhone ele criou uma tela branca em branco até o leitor tentar rolar a página. Depois que o leitor tentou interagir com a página, a tela pretendida ficou visível com o pergaminho bloqueado.
Michael Khalili
Isso funcionou perfeitamente com o Fancybox no iPad para desativar a rolagem da imagem da mesa de luz afterLoad()e afterCloseretornos de chamada. Pode ser útil para outras pessoas que pesquisam esta pergunta.
Tomanow
Na parte "ativar a rolagem", convém remover o atributo de estilo colocado no elemento html após uma chamada para "desativar a rolagem"; não é?
21413 Ben
3
O jQuery padroniza os DOMs nativos, de scrollTopmodo que a linha 2 do código 'Desativar rolagem' possa ser expressa como $( window ).scrollTop().
Barney
Eu acho que outra coisa precisa ser adicionada a isso. No Chrome no OSX, é possível que o navegador "role demais", dando uma sensação elástica à rolagem. Com esse código, você está na área cinza acima ou abaixo da página e passa o mouse sobre um ponto em que desabilita a rolagem. Ele permanecerá em um local acima / abaixo da janela do navegador. Por esta razão, você precisa adicionar uma verificação para um valor de rolagem negativa: if (scrollTop < 0) { scrollTop = 0; }. Aqui está o código completo para desativar gist.github.com/jayd3e/2eefbbc571cd1668544b .
precisa saber é o seguinte
34

Com o jQuery incluído:


desabilitar

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

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

habilitar

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

uso

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();
ceed
fonte
1
este foi perfeito para mim, a resposta anterior, feita a minha página de salto, este não faz
Bogdan Tomi
Ainda bem que pude ajudar, você pode precisar verificar se há "TouchMove" também, para dispositivos móveis, aplausos
CEED
Bem, isso quase funcionou para mim. Ele fez maravilhas no Windows (Firefox, Chrome) e MacOS no Firefox ... mas depois fui para o Windows IE e Edge, junto com o MacOS no Chrome e Safari. O problema não era mais sobre a página pulando de um lado para o outro, mas a barra de rolagem estava pulando da parte superior para a posição atual ou a página tremulava para cima. Cara, isso era tão , tão perto. Talvez ainda possamos fazer funcionar.
Steven Ventimiglia
Isso funcionou perfeitamente para mim, obrigado! Ideal para você usar em um site onde o menu de sobreposição também fica na parte inferior da página!
precisa saber é o seguinte
12

Eu sou o OP

Com a ajuda da resposta do fcalderan, consegui formar uma solução. Deixo minha solução aqui, pois traz clareza sobre como usá-la e adiciona detalhes muito cruciais,width: 100%;

Eu adiciono esta classe

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

isso funcionou para mim e eu estava usando o Fancyapp.

Dejan.S
fonte
11

Isso funcionou muito bem para mim ....

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

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


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

basta agrupar essas duas linhas de código com o que decidir quando você vai bloquear a rolagem.

por exemplo

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});
dmackenz
fonte
Esta é a melhor resposta dentre todas
Jafo
7

Você não pode desativar o evento de rolagem, mas pode desativar as ações relacionadas que levam a uma rolagem, como a roda do mouse e o touchmove:

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

Você pode ocultar a barra de rolagem do corpo overflow: hiddene definir uma margem ao mesmo tempo para que o conteúdo não salte:

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

E você pode adicionar uma barra de rolagem desativada à página para preencher a lacuna:

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>

Fiz exatamente isso para minha própria implementação de lightbox. Parece estar funcionando bem até agora.

mpen
fonte
1
Na verdade, eu gosto mais desse método. Muito simples e funciona muito bem. Obrigado!
Dericcain
2

Esta é a solução que escolhemos. Simplesmente salve a posição de rolagem quando a sobreposição for aberta, volte para a posição salva sempre que o usuário tentar rolar a página e desligue o ouvinte quando a sobreposição for fechada.

É um pouco nervoso no IE, mas funciona como um encanto no 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
fonte
Funciona de fato, mas prejudica o design no caso de um cabeçalho fixo, conforme a barra de rolagem mergulha embaixo dele.
21719 Leon Leonens
@LeonWillens Não sei bem o que você quer dizer. Se você está preocupado com a sobreposição aparecendo sob um cabeçalho fixo, você vai precisar ajustar o z-indexde .overlay-shownser maior do que o cabeçalho fixo. (Eu tenho esse código em execução na produção em um site com um cabeçalho fixo e ele funciona muito bem.)
0b10011
Não, eu estava falando sobre a barra de rolagem da bodytag. Eu experimentei seu código ontem e tenho um cabeçalho fixo na parte superior da minha página. Se eu manusear a rolagem pela bodytag, a barra de rolagem estará sob o cabeçalho fixo.
quer
1
@LeonWillens Ops, parece que eu corrigi isso na produção em algum momento e esqueci de atualizar isso. Parece que, em vez de $("body"), estamos usando $(window). E em vez de z-index: -1sobrepor para ocultá-lo, você pode usar visibility: hiddenou similar. Veja jsfiddle.net/8p2gfeha para um teste rápido para ver se funciona. O cabeçalho fixo não aparece mais na parte superior da barra de rolagem. Eventualmente, tentarei incorporar essas mudanças na resposta.
0b10011
Funciona como um encanto! Obrigado :)
Leon Willens
1

Eu tive um problema semelhante: um menu à esquerda que, quando aparece, impede a rolagem. Assim que a altura foi ajustada para 100vh, a barra de rolagem desapareceu e o conteúdo saltou para a direita.

Portanto, se você não se importa em manter a barra de rolagem ativada (mas definir a janela para a altura máxima para que ela não role de verdade em qualquer lugar), outra possibilidade é definir uma pequena margem inferior, que manterá as barras de rolagem exibidas:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}
dhc
fonte
Isso não overflow:hiddenimpede que a margem tenha algum efeito?
Koja
0

você pode manter o estouro: oculto, mas gerenciar a posição da rolagem manualmente:

antes de mostrar, mantenha o rastro da posição real de rolagem:

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

deveria funcionar

malko
fonte
0

A maneira bruta, mas funcional, será forçar a rolagem de volta ao topo, desativando efetivamente a rolagem:

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

Quando você abre a mesa de luz, eleve a bandeira e, ao fechá-la, abaixe a bandeira.

Caso de teste ao vivo .

Shadow Wizard é Ear For You
fonte
0

Eu gosto de me ater ao método "overflow: hidden" e apenas adicionar padding-right que é igual à largura da barra de rolagem.

Obter a função de largura da barra de rolagem, por 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;
}

Ao mostrar a sobreposição, adicione a classe "noscroll" ao html e adicione padding-right ao corpo:

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

Ao se esconder, remova a classe e o preenchimento:

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

O estilo noscroll é exatamente isso:

.noscroll { overflow: hidden; }

Observe que se você tiver algum elemento com position: fixed, também precisará adicionar o preenchimento a esses elementos.

Janne Annala
fonte
Eu usei essa solução. Isso me ajudou a evitar barras de rolagem duplas (uma em branco para o corpo e a segunda para o conteúdo da sobreposição). Também funciona muito bem no OSX, que pode ou não mostrar as barras de rolagem.
Novazembla 15/04
0

<div id="lightbox">está dentro do <body>elemento, assim, quando você rola a caixa de luz, também rola o corpo. A solução é não estender o <body>elemento acima de 100%, colocar o conteúdo longo dentro de outro divelemento e adicionar uma barra de rolagem, se necessário, a esse divelemento 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>

Agora, rolar a caixa de luz (e bodytambém) não tem efeito, porque o corpo não ultrapassa 100% da altura da tela.

Marek C
fonte
0

Todos os sistemas baseados em javascript modal / lightbox usam um estouro ao exibir o modal / lightbox, na tag html ou na tag body.

Quando o lightbox é exibido, os js pressionam um estouro oculto no html ou na tag body. Quando o lightbox está oculto, alguns removem o outro oculto, pressionando um transbordamento automático em html ou tag corporal.

Os desenvolvedores que trabalham no Mac não vêem o problema da barra de rolagem.

Apenas substitua o oculto por um unset para não ver o conteúdo deslizando sob o modal de remoção da barra de rolagem.

Caixa de luz aberta / exibida:

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

Fechar / ocultar a caixa de luz:

<html style="overflow: auto;"></html>
Viseira
fonte
0

Se a página sob a camada superior puder ser "fixa" na parte superior, quando você abrir a sobreposição, poderá definir

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

fornecer essa classe ao corpo rolável, você ainda deverá ver a barra de rolagem correta, mas o conteúdo não pode ser rolado.

Para manter a posição da página, faça isso no jquery

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

Ao fechar a sobreposição, basta reverter essas propriedades com

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

Apenas propus essa maneira apenas porque você não precisaria alterar nenhum evento de rolagem

Bhuvan Arora
fonte
0

Isso fará com que a viewport salte para o topo, salvando a posição de rolagem e restaurando-a ao ativar a rolagem.

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

Agora tudo que você precisa fazer é chamar as funções

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

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

Você pode fazer isso com Javascript:

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

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

E desative-o quando sua mesa de luz estiver fechada.

Mas se sua mesa de luz contiver uma barra de rolagem, você não poderá rolar enquanto estiver aberta. Isso ocorre porque windowcontém ambos bodye #lightbox. Então você tem que usar uma arquitetura como a seguinte:

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

E, em seguida, aplique o onscrollevento apenas em #global.

ldiqual
fonte