"Posição: pegajosa;" não está trabalhando CSS e HTML

177

Quero fazer com que a barra de navegação fique no topo assim que rolar para ela, mas ela não está funcionando e não faço ideia do porquê. Se você puder ajudar, aqui está o meu código HTML e CSS:

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato",sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover{
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav style="position: sticky; position: -webkit-sticky;">
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Harleyoc1
fonte
10
Posição: necessidades pegajosas um coordonate para tel onde enfiar
G-Cyrillus
36
Você também deve ter cuidado com os elementos pai. position: stickypode parar de funcionar se for dentro de um flexbox a menos que você for cuidadoso e também falhará se há um overflow: hiddenou overflow: autoentre ele e tudo o que rola dentro (root corpo ou ancestral mais próximo com overflow: rolagem)
user56reinstatemonica8
2
@ user56reinstatemonica8 OMG muito obrigado por me contar sobre o overflow: hiddene overflow: auto! Estou coçando a cabeça há dias tentando fazer essa porcaria funcionar
Oneezy

Respostas:

206

O posicionamento fixo é um híbrido de posicionamento relativo e fixo. O elemento é tratado como posição relativa até cruzar um limite especificado, quando é tratado como posição fixa.
...
Você deve especificar um limite de, pelo menos, um dos top, right, bottom, ou leftpara o posicionamento pegajoso se comportar conforme o esperado. Caso contrário, será indistinguível do posicionamento relativo. [ fonte: MDN ]

Portanto, no seu exemplo, você deve definir a posição em que deve ficar no final usando a toppropriedade

html, body {
  height: 200%;
}

nav {
  position: sticky;
  position: -webkit-sticky;
  top: 0; /* required */
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Marvin
fonte
124
Em geral, essa resposta não é suficiente para manter a aderência ao trabalho, o pai também não deve ter propriedade de estouro.
ViliusL
Obrigado pelo seu comentário. Concordo com você que, para outros exemplos que não os do OP, minha resposta pode não ser suficiente. As outras respostas apontar isso :)
Marvin
Eu acho que o truque é que pegajoso posição só pode ser aplicado para as crianças, que pertence a um pai de rolagem com uma altura conhecida, (uma criança diretos em um flexbox tem uma altura saber qual é calculado a partir de outro flex-item)
code4j
@ViliusL obrigado pelo seu comentário! Esse foi o problema que tive com a posição: pegajosa, eu não saberia se não fosse por você, pois não encontrei essas informações em nenhum lugar.
Piotr Szlagura 24/01
posição pegajosa não deve ter um pai com propriedade overflow, também pegajosa não é suportada em alguns navegadores da Web
Rohan Shenoy
331

Verifique se um elemento ancestral possui um estouro definido (por exemplo overflow:hidden); tente alternar. Talvez você precise subir a árvore do DOM mais alto do que o esperado =).

Isso pode afetar seu position:stickyelemento descendente.

MarsAndBack
fonte
36
Gostaria de poder te votar várias vezes! Isso me incomodou mais do que gostaria de admitir.
Alexander Varwijk
2
Esta é a resposta certa. No entanto, pode ser difícil encontrar qual elemento pai está causando o problema. Eu escrevi um script jquery para ajudar a identificar a propriedade overflow nos pais que identificaram o problema (basta executá-lo no seu console). Como o script é algumas linhas, adicionei uma resposta contendo o script abaixo.
precisa saber é o seguinte
5
Eu perdi o "s" em seus "elementos pai"
che-azeh
5
Eu também perdi o "s" :( e esse era o problema. Em muitos lugares, as pessoas escrevem que você deve verificar apenas os pais, nem todos os pais. Encontrei o meu problema verificando se a chamada $(stickyElement).parents().css("overflow", "visible")no console da Web ajudaria e ajudou. Então localizei o pai distante com overflow:hidden. estilo que causou o problema Eu gostaria de ler esta resposta com mais cuidado.
Mariusz Pawelski
2
Se você precisar verificar se há overflow:hidden, você pode executar esse script no console do seu browser para verificar todos os pais / antepassados de um determinado elemento: gist.github.com/brandonjp/478cf6e32d90ab9cb2cd8cbb0799c7a7
brandonjp
100

Eu tenho o mesmo problema e encontrei a resposta aqui .

Se o seu elemento não estiver aderindo conforme o esperado, a primeira coisa a verificar são as regras aplicadas ao contêiner.

Especificamente, procure por qualquer propriedade de estouro definida no pai. Você não pode usar : overflow: hidden, overflow: scrollou overflow: autosobre o pai de um position: stickyelemento.

Miftah Mizwar
fonte
Essa também é a resposta certa, mas também a minha resposta, que ajuda a identificar facilmente os pais que estão causando o problema.
precisa saber é o seguinte
10
Você deve verificar não apenas o contêiner pai mais próximo, mas todos os elementos pai s .
Mariusz Pawelski
sim, ver a minha resposta para fazer exatamente isso e verificar TODOS os pais muito rapidamente
danday74
1
O link também me ajudou. Meu problema foi resolvido por "... Se você não estiver usando estouro e ainda ter problemas vale a pena verificar se a altura está definida no pai ..."
xenetics
Poupança de vida, descrição realmente simples para o problema, mas existe uma
22419 Rahul Singh
32

Me deparei com mais algumas coisas:

Quando o seu elemento adesivo é um componente (angular, etc.)

  • Se o próprio elemento 'sticky' for um componente com um seletor de elemento personalizado, como um componente angular chamado, <app-menu-bar>você precisará adicionar o seguinte ao css do componente:

    :host { display: block; }   

    ou

    app-menu-bar  { display: block; }   // (in the containing component's css)

    O Safari no iOS, em particular, parece exigir display:blockaté mesmo o elemento raiz app-rootde um aplicativo angular ou ele não ficará.

  • Se você estiver criando um componente e definindo o css dentro do componente (DOM sombreado / estilos encapsulados), verifique se ele position: stickyestá sendo aplicado ao seletor 'externo' (por exemplo, app-menu-barno devtools deve mostrar a posição de aderência) e não div no nível superior o componente. Com o Angular, isso pode ser alcançado com o :hostseletor no css do seu componente.

    :host
    {
        position: sticky;
        display: block;   // this is the same as shown above
        top: 0;
        background: red;    
    }

De outros

  • Se o elemento que segue o elemento adesivo tiver um plano de fundo sólido, adicione o seguinte para impedir que ele deslize por baixo:

    .sticky-element { z-index: 100; }
    .parent-of-sticky-element { position: relative; }
  • Seu elemento adesivo deve ser o primeiro (antes do seu conteúdo) se estiver usando tope depois se estiver usando bottom.

  • Existem complicações ao usar overflow: hiddeno elemento wrapper - em geral, ele mata o elemento adesivo dentro. Melhor explicado nesta pergunta

  • Os navegadores móveis podem desativar itens fixos / fixos quando o teclado na tela estiver visível. Não tenho certeza das regras exatas (alguém já sabe), mas quando o teclado está visível, você está olhando para uma espécie de 'janela' na janela e não poderá facilmente conseguir que as coisas atinjam o parte superior visível da tela.

  • Assegure-se de ter:

    position: sticky;

    e não

    display: sticky;

Diversos problemas de usabilidade

  • Seja cauteloso se o seu design exigir a fixação de itens na parte inferior da tela em dispositivos móveis. No iPhone X, por exemplo, eles exibem uma linha estreita para indicar a região de furto (para voltar à página inicial) - e os elementos dentro dessa região não são clicáveis. Portanto, se você colar algo, não deixe de testar no iPhone X se os usuários podem ativá-lo. Um grande botão "Comprar agora" não é bom se as pessoas não podem clicar nele!
  • Se você está anunciando no Facebook, a página da web é exibida em um controle de 'visualização da web' nos aplicativos móveis do Facebook. Especialmente ao exibir vídeo (onde seu conteúdo começa apenas na metade inferior da tela) - eles geralmente atrapalham completamente os elementos fixos, colocando sua página em uma janela de rolagem que realmente permite que seus elementos fixos desapareçam da parte superior da página. Certifique-se de testar no contexto de um anúncio real e não apenas no navegador do telefone ou no navegador do Facebook, que podem se comportar de maneira diferente.
Simon_Weaver
fonte
@ Sergey Não estou absolutamente claro qual display: blocke position: relativeaciona o comportamento correto no Safari - parecia que apenas display: blockera necessário? É claro que provavelmente não dói ter as duas especificadas #
Simon_Weaver 28/08/18
2
Apenas display: blockfoi suficiente
Sergey
27

Esta é uma continuação das respostas de MarsAndBack e Miftah Mizwar.

Suas respostas estão corretas. No entanto, é difícil identificar o (s) ancestral (es) do problema.

Para simplificar, basta executar esse script jQuery no console do navegador e ele informará o valor da propriedade overflow em todos os ancestrais.

$('.your-sticky-element').parents().filter(function() {
    console.log($(this));
    console.log($(this).css('overflow'));
    return $(this).css('overflow') === 'hidden';
});

Onde um ancestral não tem overflow: visibleseu CSS alterado para isso!

Além disso, como declarado em outro lugar, verifique se o elemento adesivo possui isso no CSS:

.your-sticky-element {
    position: sticky;
    top: 0;
}
danday74
fonte
2
Isso foi muito útil. Consegui identificar rapidamente o elemento pai que tinha um valor de overflow: invisible.
David Brower
4
Se você não possui o jQuery em sua página, é possível executar este pequeno trecho no console para adicioná-lo: (async function() { let response = await fetch('https://code.jquery.com/jquery-3.3.1.min.js'); let script = await response.text(); eval(script); })();
magikMaker 5/18
8
Você também pode executar esse snippet que não exige que o JQuery encontre o pai de estouro não "visível": var p = $0.parentElement; while(p != null) { var ov = getComputedStyle(p).overflow; if(ov !== 'visible') console.warn(ov, p); else console.log(ov, p); p = p.parentElement; }Onde $0está o último elemento selecionado nas ferramentas do desenvolvedor.
Mariusz Pawelski
Pode-se também lidar position: fixedcom propriedades apropriadas com JavaScript. A pergunta não indica a necessidade de JavaScript.
vintproykt
12

Eu tive que usar o seguinte CSS para fazê-lo funcionar:

.parent {
    display: flex;
    justify-content: space-around;
    align-items: flex-start;
    overflow: visible;
}

.sticky {
    position: sticky;
    position: -webkit-sticky;
    top: 0;
}

Se acima não funcionar, então ...

Passe por todos os ancestrais e verifique se nenhum desses elementos possui overflow: hidden. Você precisa mudar isso paraoverflow: visible

Unicco
fonte
1
display: flex faz a coisa #
MaciejLisCK
6

Caso você se depare com isso e seu adesivo não esteja funcionando - tente configurar o pai para:

display: unset

Trabalhou para mim

brianokinyi
fonte
É esse.
mm-93
Oh! Isso parece ser uma solução alternativa para o caso de um elemento pai ter uma altura limitada (por exemplo, um contêiner da barra de navegação ou algo assim, em oposição a um contêiner de corpo ou página inteiro) - parece que os adesivos não gostam de rolar para fora do pais (o que é totalmente ridículo!) Agora todo mundo só precisa ter a sorte de poder definir o pai display: unset, o que nem sempre é imediatamente viável
Ben Philipp
Também parece funcionar com contents, initial(?) Einline
Ben Philipp
5

Momento engraçado que não era óbvio para mim: pelo menos no Chrome 70 position: stickynão será aplicado se você o tiver definido usando o DevTools.

ik
fonte
Você tem uma fonte para isso ou alguma outra informação sobre como contornar isso?
AJMansfield
5

Parece que a barra de navegação a ser mantida não deve estar dentro de nenhuma div ou seção com outro conteúdo. Nenhuma solução estava funcionando para mim até que eu retirei a barra de navegação da div que a barra de navegação compartilhava com outra barra superior. Eu já tinha a barra superior e a barra de navegação envolvidas por uma div comum.

solaris333
fonte
Obrigado, era isso que eu estava procurando! Para mim, não havia pais com excesso de peso, nem problemas de altura. Seria bom ver essas informações na resposta aceita também.
18719 saglamcem
Acabei de descobrir ao experimentar que o adesivo não rolará para fora do elemento pai. Não importa quantos irmãos ele tenha, mas seu pai, aparentemente, não pode ser um contêiner de barra de navegação, mas deve ser algo no nível de um contêiner de página / conteúdo :( Isso é ridículo
Ben Philipp
Mas Lo! Se puder, se você definir o pai limitador como display: unset, essa restrição será levantada! veja stackoverflow.com/a/60560997/2902367 Também parece funcionar com contents, initial(?) einline
Ben Philipp
4

do meu comentário:

position:sticky precisa de uma coordenada para dizer onde ficar

nav {
  position: sticky;
  top: 0;
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}

body {
  height: 200vh;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Há polyfill para usar em outros navegadores que não o FF e o Chrome. Esta é uma regra experimental que pode ser implementada ou não a qualquer momento através dos navegadores. O Chrome o adicionou há alguns anos e depois o soltou, parece que voltou ... mas por quanto tempo?

A posição mais próxima seria a posição: coordenadas relativas + atualizadas enquanto a rolagem atingia o ponto de aderência, se você deseja transformar isso em um script javascript

G-Cyrillus
fonte
4

Sei que isso parece já ter sido respondido, mas me deparei com um caso específico e sinto que a maioria das respostas está errada.

o overflow:hidden respostas cobrem 90% dos casos. Esse é mais ou menos o cenário de "navegação atrativa".

Mas o comportamento pegajoso é melhor usado dentro da altura de um contêiner. Pense em um formulário de boletim informativo na coluna direita do seu site, que rola para baixo com a página. Se o seu elemento adesivo é o único filho do contêiner, o contêiner é exatamente do mesmo tamanho e não há espaço para rolar.

Seu contêiner precisa ter a altura que você espera que seu elemento role dentro. Qual no meu cenário "coluna da direita" é a altura da coluna da esquerda. A melhor maneira de conseguir isso é usar display:table-cellnas colunas. Se você não puder, e estiver preso float:righte assim como eu, terá que adivinhar a altura da coluna esquerda para computá-la com Javascript.

Tristan M
fonte
2
"Se o seu elemento adesivo é o único filho do contêiner, o contêiner é exatamente do mesmo tamanho e não há espaço para rolar". OURO!!! Obrigado!
Mark Jackson
Sim! Levei um tempo para descobrir isso. Achei uma restrição ridícula no começo, mas acho que deveria haver pelo menos a opção para isso. Eu preferiria algo como sticky-limit: parent, sticky-limit: bodyou sticky-limit: nth-parent(3)... De qualquer forma: se puder, você pode aumentar essa limitação configurando o pai limitador display: unsetcomo, conforme observado em stackoverflow.com/a/60560997/2902367 . Também parece funcionar com contents, initial(?) Einline
Ben Philipp
3

Eu sei que este é um post antigo. Mas se há alguém como eu que recentemente começou a mexer na posição: pegajoso, isso pode ser útil.

No meu caso, eu estava usando position: sticky como um item de grade. Não estava funcionando e o problema foi um estouro-x: oculto no htmlelemento. Assim que eu removi essa propriedade, funcionou bem. Tendo overflow-x: oculto no bodyelemento parecia funcionar, ainda não sei porquê.

Marco Peralta
fonte
1

duas respostas aqui:

  1. remover overflowpropriedade da bodytag

  2. definido height: 100%como bodypara corrigir o problema comoverflow-y: auto

min-height: 100% não funciona em vez de height: 100%

Javad Ebrahimi
fonte
1

Eu acredito que este artigo diz muito sobre como stickyfunciona

Como CSS Position Sticky realmente funciona! A posição CSS pegajosa tem duas partes principais, item pegajoso e recipiente pegajoso .

Item fixo  - é o elemento que definimos com a posição: estilos fixos. O elemento irá flutuar quando a posição de exibição corresponde à definição de posição, por exemplo: top: 0px.

Container pegajoso - é o elemento HTML que envolve o item pegajoso. Essa é a área máxima em que o item adesivo pode flutuar.

Quando você define um elemento com a posição: sticky, define automaticamente o elemento pai como um container sticky!

yuval.bl
fonte
1

O comportamento real de um elemento adesivo é:

  • Primeiro é relativo por um tempo
  • então é consertado por um tempo
  • finalmente, desaparece da vista

Um elemento posicionado com aderência é tratado como relativamente posicionado até que seu bloco que contenha ultrapasse um limite especificado (como definir um valor superior a não ser automático) em sua raiz de fluxo (ou no contêiner em que ele rola), quando é tratado como "preso" "até encontrar a extremidade oposta do seu bloco de contenção.

O elemento é posicionado de acordo com o fluxo normal do documento e, em seguida, é deslocado em relação ao ancestral de rolagem mais próximo e contendo o bloco (ancestral do nível de bloco mais próximo), incluindo elementos relacionados à tabela, com base nos valores de superior, direito, inferior, e esquerda. O deslocamento não afeta a posição de outros elementos.

Esse valor sempre cria um novo contexto de empilhamento. Observe que um elemento adesivo "adere" ao ancestral mais próximo que possui um "mecanismo de rolagem" (criado quando o estouro está oculto, rolagem, automático ou sobreposto), mesmo que esse ancestral não seja o ancestral de rolagem mais próximo.

Este exemplo ajudará você a entender:

code https://codepen.io/darylljann/pen/PpjwPM

Juanma Menendez
fonte
0

se a correção de danday74 não funcionar, verifique se o elemento pai tem uma altura.

No meu caso, tive dois filhos, um flutuando para a esquerda e outro flutuando para a direita. Eu queria que o flutuante certo ficasse pegajoso, mas tive que adicionar um <div style="clear: both;"></div>no final do pai, para dar altura.

Flo
fonte
Não sei por que isso foi votado por alguém, mas este foi exatamente o meu caso: eu adicionei float:leftao elemento pai (sem float, sua altura era 0) e position:stickyfuncionou.
aexl 13/03
0

Eu usei uma solução JS. Funciona no Firefox e Chrome. Qualquer problema, me avise.

html

<body>
  <header id="header">
    <h1>Extra-Long Page Heading That Wraps</h1>
    <nav id="nav">
      <ul>
        <li><a href="" title="">Home</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <p><!-- ridiculously long content --></p>
  </main>
  <footer>
    <p>FOOTER CONTENT</p>
  </footer>
  <script src="navbar.js" type="text/javascript"></script>
</body>

css

nav a {
    background: #aaa;
    font-size: 1.2rem;
    text-decoration: none;
    padding: 10px;
}

nav a:hover {
    background: #bbb;
}

nav li {
    background: #aaa;
    padding: 10px 0;

}

nav ul  {
    background: #aaa;
    list-style-type: none;
    margin: 0;
    padding: 0;

}

@media (min-width: 768px) {

    nav ul {
        display: flex;
    }
}

js

function applyNavbarSticky() {
    let header = document.querySelector('body > header:first-child')
    let navbar = document.querySelector('nav')
    header.style.position = 'sticky'

    function setTop() {
        let headerHeight = header.clientHeight
        let navbarHeight = navbar.clientHeight
        let styleTop = navbarHeight - headerHeight

        header.style.top = `${styleTop}px`
    }

    setTop()

    window.onresize = function () {
        setTop()
    }
}
Carl Brubaker
fonte
0

z-indextambém é muito importante. Às vezes funcionará, mas você simplesmente não verá. Tente configurá-lo para um número muito alto apenas para ter certeza. Também nem sempre coloque, top: 0mas tente algo mais alto, caso esteja escondido em algum lugar (sob uma barra de ferramentas).

Rexhin Hoxha
fonte
0

Aqui está o que estava me provocando ... minha div pegajosa estava dentro de outra div, para que a div pai precisasse de algum conteúdo adicional DEPOIS da div pegajosa, para tornar a div pai "alta o suficiente" para que a div pegajosa "deslizasse" sobre outro conteúdo como você rola para baixo.

Então, no meu caso, logo após a div pegajosa, eu tive que adicionar:

    %div{style:"height:600px;"} 
      &nbsp;

(Meu aplicativo tem duas divs lado a lado, com uma imagem "alta" à esquerda e um pequeno formulário de entrada de dados à direita, e eu queria que o formulário de entrada de dados flutuasse ao lado da imagem à medida que você rola para baixo, para que o formulário esteja sempre na tela.Não funcionaria até que eu adicionasse o "conteúdo extra" acima, para que a div pegajosa tenha algo para "deslizar por cima"

jpw
fonte
-1

É VERDADEIRO que as overflownecessidades sejam removidas ou configuradas initialpara fazer position: stickytrabalhos no elemento filho. Usei o Material Design no meu aplicativo Angular e descobri que alguns componentes do Material alteravam o overflowvalor. A correção para o meu cenário é

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
Anh Nguyen
fonte