ScrollIntoView () fazendo com que toda a página se mova


109

Estou usando ScrollIntoView () para rolar o item destacado em uma lista para exibição. Quando eu rolar para baixo, ScrollIntoView (false) funciona perfeitamente. Mas quando eu rolar para cima, ScrollIntoView (true) está fazendo com que a página inteira se mova um pouco, o que eu acho que é o intuito. Existe uma maneira de evitar que a página inteira se mova ao usar ScrollIntoView (true)?

Aqui está a estrutura da minha página -

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs está vindo de uma chamada ajax. Usando o safari móvel.

Obrigado pela sua ajuda antecipadamente!


1
Você pode fornecer um JSFiddle para que possamos ver exatamente qual é o problema?
Robert Koritnik de

Respostas:


115

Você pode usar em scrollTopvez de scrollIntoView():

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle: http://jsfiddle.net/LEqjm/

Se houver mais de um elemento rolável que você deseja rolar, você precisará alterar o scrollTopde cada um individualmente, com base nos offsetTops dos elementos intermediários. Isso deve dar a você o controle refinado para evitar o problema que está tendo.

EDIT: offsetTop não é necessariamente relativo ao elemento pai - é relativo ao primeiro ancestral posicionado. Se o elemento pai não estiver posicionado (relativo, absoluto ou fixo), você pode precisar alterar a segunda linha para:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;

3
Para sua informação, isso só funciona quando o pai está no topo da página. Você provavelmente deveria chegartarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil,

2
offsetTop é relativo ao pai posicionado mais próximo, então se o nó pai tiver position: relative, então você não deve subtrair seu deslocamento. Mas você está certo para a maioria dos casos.
Brilliand

2
Aqui está um js fiddle: jsfiddle.net/LEqjm/258 que mostra também o comportamento impróprio de ScrollIntoView.
Rafi

1
@Brilliand obrigado pela ideia sobre position: relativeon prent div: ele realmente resolveu o problema
Alex Zhukovskiy

Ele está funcionando no Chrome, mas rola um pouco mais no IE, o que esconde o conteúdo do texto do topo. Qualquer solução @Phil, Agradecemos antecipadamente
Soniya

120

Corrigido com:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

consulte: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
Obrigado, isso funcionou. Eu não consegui entender o uso do bloco e seus valores quando li. Agora que resolveu um problema, eu sei o que está fazendo
Pavan

3
O que significa "mais próximo"? EDIT: Encontrou uma resposta aqui: stackoverflow.com/a/48635751/628418
Sammi

Isso resolveu meu problema. Tenho visto isso acontecer em nosso aplicativo da web há algum tempo, mas tem sido difícil bloquear a reprodução para isso. Depois de adicionar um novo recurso, ocorreu todas as vezes e fui capaz de rastreá-lo para esta chamada, que estava faltando o block : 'nearest'parâmetro.
roskelld

Se eles definissem o que os valores do bloco significam .... início e mais próximo ... é tudo tentativa e erro.
Bae

Funciona com o Chrome, mas não com o Edge para mim.
Michael,

13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});

ou você pode usartop: el['offsetTop']
Junior Mayhé

Isso funciona melhor para mim. Mas ainda um pouco problemático no firefox - às vezes ele para no meio do caminho para o elemento. Fino na borda e cromado.
Mark

9

Eu também tive esse problema e passei muitas horas tentando resolvê-lo. Espero que minha resolução ainda possa ajudar algumas pessoas.

Minha correção acabou sendo:

  • Para Chrome: mudando .scrollIntoView()para .scrollIntoView({block: 'nearest'})(graças a @jfrohn).
  • Para Firefox: aplique overflow: -moz-hidden-unscrollable;no elemento do contêiner que muda.
  • Não testado em outros navegadores.

8

Brinque com scrollIntoViewIfNeeded()... certifique-se de que é compatível com o navegador.


1
Não sabia que isso era uma coisa. Há um polyfill
mpen

No documento, é mencionado que não é padrão, mas está funcionando bem. devemos usar isso?
Shyam Kumar

8

Eu adicionei uma maneira de exibir o comportamento importante do ScrollIntoView - http://jsfiddle.net/LEqjm/258/ [deve ser um comentário, mas não tenho reputação suficiente]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});

7
Não é uma questão jQuery.
Seangates

6

O plugin jQuery scrollintoview()aumenta a usabilidade

Em vez da implementação DOM padrão, você pode usar um plugin que anima o movimento e não tem efeitos indesejados. Esta é a maneira mais simples de usá-lo com padrões:

$("yourTargetLiSelector").scrollintoview();

De qualquer forma, dirija-se a esta postagem do blog onde você pode ler todos os detalhes e, eventualmente, levará você ao código-fonte do GitHub do plugin.

Este plugin procura automaticamente o elemento ancestral rolável mais próximo e o rola de forma que o elemento selecionado esteja dentro de sua porta de visualização visível. Se o elemento já estiver na porta de visualização, ele não fará nada, é claro.


19
@Brilliand: Isso é verdade, mas não significa que eles não estejam usando ou estejam relutantes em usá-lo. Tudo o que estou fazendo é fornecer uma alternativa. Cabe ao OP decidir se esse é um caminho que eles seguiriam ou não. Talvez eles nunca tenham considerado usar jQuery em primeiro lugar.
Robert Koritnik

O fato de o OP não ter mencionado especificamente o jQuery é totalmente irrelevante: a resposta de @RobertKoritnik me serviu perfeitamente.
Dave Land,

1
A propósito, o Bing está mostrando sua amostra de código nos resultados da pesquisa para "impedir que o elemento ancestral role com scrollintoview." :-)
Dave Land

2

Usando a ideia de Brilliant, aqui está uma solução que somente rola (verticalmente) se o elemento NÃO estiver visível no momento. A ideia é obter a caixa delimitadora da janela de visualização e o elemento a ser exibido no espaço de coordenadas da janela do navegador. Verifique se ele está visível e, se não estiver, role pela distância necessária para que o elemento seja mostrado na parte superior ou inferior da janela de visualização.

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }

2

Adicionando mais informações para @Jescopostar.

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methodpara navegadores Chrome, Opera, Safari.
    Se o elemento já estiver na área visível da janela do navegador, nenhuma rolagem ocorrerá .
  • Element.scrollIntoView() método rola o elemento no qual é chamado para a área visível da janela do navegador.

Experimente o código abaixo no mozilla.org scrollIntoView()link. Postagem para identificar o navegador

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}

2

no meu contexto, ele empurraria a barra de ferramentas aderente para fora da tela ou entraria próximo a um botão de fab com absoluto.

usando o mais próximo resolvido.

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});

1

Tive o mesmo problema, resolvi removendo o transform:translateYCSS que coloquei na footerpágina.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.