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!

estou aqui
fonte
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;
Brilliand
fonte
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

jfrohn
fonte
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'});
dipolo_moment
fonte
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.
paddotk
fonte
8

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

Jesco
fonte
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);
}
});
Michal Tsadok
fonte
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.

Robert Koritnik
fonte
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;
        }
    }
KungPhoo
fonte
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);
    }
}
Yash
fonte
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'
});
Gui Seek
fonte
1

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

yael kfir
fonte