"Posición: pegajosa"; no funciona CSS y HTML


177

Quiero que la barra de navegación se pegue a la parte superior una vez que me desplazo hacia ella, pero no funciona y no tengo idea de por qué. Si puede ayudar, aquí está mi código HTML y 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>


10
posición: sticky necesita un coordinador para decir dónde quedarse
G-Cyrillus

36
También debe tener cuidado con los elementos principales. position: stickypuede dejar de funcionar si está dentro de un FlexBox a menos que seas cuidadoso y también fallará si hay una overflow: hiddeno overflow: autoentre éste y lo que se desplaza hacia el interior (de la raíz del cuerpo o antepasado más cercano con overflow: scroll)
user56reinstatemonica8

2
@ user56reinstatemonica8 OMG muchas gracias por contarme sobre el overflow: hiddeny overflow: auto! He estado rascándome la cabeza durante días tratando de hacer que esta basura funcione
Oneezy

Respuestas:


206

El posicionamiento fijo es un híbrido de posicionamiento relativo y fijo. El elemento se trata como una posición relativa hasta que cruza un umbral especificado, en cuyo punto se trata como una posición fija.
...
Debe especificar un umbral con al menos uno de top, right, bottom, o leftpara el posicionamiento pegajosa a comportarse como se esperaba. De lo contrario, será indistinguible del posicionamiento relativo. [ fuente: MDN ]

Entonces, en su ejemplo, debe definir la posición en la que debería quedarse al final utilizando la toppropiedad.

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>


124
En general, esta respuesta no es suficiente para ser pegajoso para trabajar, el padre tampoco debe tener una propiedad de desbordamiento.
ViliusL

Gracias por tu comentario. Estoy de acuerdo con usted en que para otros ejemplos además de los OP, mi respuesta podría no ser suficiente. Las otras respuestas señalan esto :)
Marvin

Creo que el truco es que la posición fija solo se puede aplicar a los hijos que pertenecen a un padre desplazable con una altura conocida, (un hijo directo en un flexbox tiene una altura conocida que se calcula a partir de otro elemento flexible)
code4j

@ViliusL gracias por tu comentario! Ese era el problema que tenía con la posición: pegajoso, no lo habría sabido si no fuera por ti, ya que no encontré esta información en ninguna parte.
Piotr Szlagura

la posición fija no debe tener un elemento primario con propiedad de desbordamiento, tampoco está disponible en algunos navegadores web
Rohan Shenoy

331

Compruebe si un elemento ancestro tiene un conjunto de desbordamiento (p overflow:hidden. Ej. ); intenta alternarlo. Puede que tengas que subir el árbol DOM más alto de lo que esperas =).

Esto puede afectar su position:stickyelemento descendiente.


36
¡Ojalá pudiera votarte varias veces! Esto me ha mordido más de lo que me gustaría admitir.
Alexander Varwijk

2
Esta es la respuesta correcta. Sin embargo, puede ser difícil encontrar qué elemento padre está causando el problema. Escribí un script jquery para ayudar a identificar la propiedad de desbordamiento en los padres que identificaron el problema (solo ejecútelo en su consola). Debido a que el guión tiene algunas líneas, he agregado una respuesta que contiene el guión a continuación.
danday74

55
Me perdí la "s" en tus "elementos principales"
che-azeh

55
También me perdí la "s" :( y ese era el problema. En muchos lugares la gente escribe que debes verificar solo a los padres, no a todos los padres. Encontré mi problema al verificar si llamar $(stickyElement).parents().css("overflow", "visible")a la consola web sería útil. el padre lejano con overflow:hiddenestilo que causó el problema. Ojalá leyera esta respuesta con más atención.
Mariusz Pawelski

2
Si necesita verificar overflow:hidden, puede ejecutar este script en la consola de su navegador para verificar todos los padres / antepasados ​​de un elemento dado: gist.github.com/brandonjp/478cf6e32d90ab9cb2cd8cbb0799c7a7
brandonjp

100

Tengo el mismo problema, y ​​encontré la respuesta aquí .

Si su elemento no se pega como se esperaba, lo primero que debe verificar son las reglas aplicadas al contenedor.

Específicamente, busque cualquier propiedad de desbordamiento establecida en el padre. No se puede utilizar : overflow: hidden, overflow: scrollo overflow: autoen el padre de un position: stickyelemento.


Esta también es la respuesta correcta, pero también veo mi respuesta que ayuda a identificar fácilmente al padre que causa el problema.
danday74

10
Usted debe comprobar no sólo contenedor principal más cercano, pero todas elemento padre s .
Mariusz Pawelski

Sí, ver mi respuesta para hacer exactamente eso y comprobar todos los padres muy rápidamente
danday74

1
El enlace también me ayudó. Mi problema se resolvió con "... Si no está utilizando el desbordamiento y todavía tiene problemas, vale la pena verificar si se establece una altura en el padre ..."
xenetics

Salvavidas, descripción realmente simple del problema, pero ¿hay alguna solución para esto simplemente curiosa
Rahul Singh

32

Pocas cosas más me he encontrado:

Cuando su elemento adhesivo es un componente (angular, etc.)

  • Si el elemento 'adhesivo' en sí mismo es un componente con un selector de elementos personalizado, como un componente angular llamado <app-menu-bar>, deberá agregar lo siguiente al CSS del componente:

    :host { display: block; }   

    o

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

    Safari en iOS en particular parece requerir display:blockincluso en el elemento raíz app-rootde una aplicación angular o no se pegará.

  • Si está creando un componente y está definiendo el CSS dentro del componente (DOM sombra / estilos encapsulados), asegúrese de que position: stickyse esté aplicando al selector 'externo' (por ejemplo, app-menu-baren devtools debe mostrar la posición fija) y no un nivel superior div dentro el componente. Con Angular, esto se puede lograr con el :hostselector en el CSS para su componente.

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

Otro

  • Si el elemento que sigue a su elemento adhesivo tiene un fondo sólido, debe agregar lo siguiente para evitar que se deslice debajo:

    .sticky-element { z-index: 100; }
    .parent-of-sticky-element { position: relative; }
  • Su elemento adhesivo debe ser el primero (antes de su contenido) si lo usa topy después si lo usa bottom.

  • Hay complicaciones cuando se usa overflow: hiddenen su elemento de envoltura; en general, matará el elemento adhesivo en el interior. Mejor explicado en esta pregunta

  • Los navegadores móviles pueden deshabilitar elementos fijos / fijos cuando el teclado en pantalla está visible. No estoy seguro de las reglas exactas (¿alguien lo sabe?) Pero cuando el teclado está visible, estás viendo una especie de 'ventana' en la ventana y no podrás hacer que las cosas se adhieran fácilmente parte superior visible real de la pantalla.

  • Asegúrate de tener:

    position: sticky;

    y no

    display: sticky;

Diversas preocupaciones de usabilidad

  • Tenga cuidado si su diseño requiere pegar cosas en la parte inferior de la pantalla en dispositivos móviles. En el iPhone X, por ejemplo, muestran una línea estrecha para indicar la región de deslizamiento (para volver a la página de inicio), y no se puede hacer clic en los elementos dentro de esta región. Entonces, si pega algo, asegúrese de probar en el iPhone X que los usuarios pueden activarlo. ¡Un gran botón 'Comprar ahora' no sirve si la gente no puede hacer clic en él!
  • Si está anunciando en Facebook, la página web se muestra en un control de 'vista web' dentro de las aplicaciones móviles de Facebook. Especialmente cuando se muestran videos (donde su contenido comienza solo en la mitad inferior de la pantalla), a menudo desordenan completamente los elementos adhesivos al colocar su página dentro de una ventana de visualización desplazable que realmente permite que sus elementos adhesivos desaparezcan en la parte superior de la página. Asegúrese de realizar la prueba en el contexto de un anuncio real y no solo en el navegador del teléfono o incluso en el navegador de Facebook, que pueden comportarse de manera diferente.

@Sergey No tengo absolutamente claro cuál de los dos display: blocky position: relativedesencadena el comportamiento correcto en Safari, ¿parecía que solo display: blockera necesario? Por supuesto, probablemente no está de más haber especificado ambos
Simon_Weaver

2
Solo display: blockfue suficiente
Sergey

27

Esta es una continuación de las respuestas de MarsAndBack y Miftah Mizwar.

Sus respuestas son correctas. Sin embargo, es difícil identificar los antepasados ​​problemáticos.

Para simplificar esto, simplemente ejecute este script jQuery en la consola de su navegador y le indicará el valor de la propiedad de desbordamiento en cada antepasado.

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

¡Donde un antepasado no tiene que overflow: visiblecambiar su CSS para que lo haga!

Además, como se indicó en otra parte, asegúrese de que su elemento adhesivo tenga esto en el CSS:

.your-sticky-element {
    position: sticky;
    top: 0;
}

2
Eso fue muy útil. Pude identificar rápidamente el elemento padre que tenía un valor de overflow: invisible.
David Brower

44
Si no tiene jQuery en su página, puede ejecutar este pequeño fragmento en la consola para agregarlo: (async function() { let response = await fetch('https://code.jquery.com/jquery-3.3.1.min.js'); let script = await response.text(); eval(script); })();
magikMaker

8
También puede ejecutar este fragmento que no requiere que JQuery encuentre un elemento primario de desbordamiento no "visible": 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; }¿Dónde $0está el último elemento seleccionado en las herramientas de desarrollador?
Mariusz Pawelski el

Uno también podría manejar position: fixedy propiedades apropiadas con JavaScript. La pregunta no indica la necesidad de JavaScript.
vintproykt hace

12

Tuve que usar el siguiente CSS para que funcionara:

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

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

Si lo anterior no funciona, entonces ...

Revisa todos los ancestros y asegúrate de que ninguno de estos elementos tenga overflow: hidden. Tienes que cambiar esto aoverflow: visible


1
display: flex hace la cosa
MaciejLisCK

6

En caso de que te hayas encontrado con esto y tu pegajoso no funcione, intenta configurar el padre para que:

display: unset

Trabajó para mi


Éste es el indicado.
mm-93

Oh! Esto parece ser una solución para el caso de que un elemento padre tenga una altura limitada (por ejemplo, un contenedor de barra de navegación o algo así, en lugar de un cuerpo entero o un contenedor de página), parece que a los adhesivos no les gusta desplazarse fuera de su padres (¡lo cual es completamente ridículo!) Ahora todo el mundo solo necesita ser tan afortunado como para poder establecer a los padres display: unset, lo que no siempre es viable de inmediato
Ben Philipp

También parece funcionar con contents, initial(?) Yinline
Ben Philipp

5

Momento divertido que no era obvio para mí: al menos en Chrome 70 position: stickyno se aplica si lo ha configurado con DevTools.


¿Tiene una fuente para esto o alguna otra información sobre cómo solucionar esto?
AJMansfield

5

Parece que la barra de navegación a pegar no debe estar dentro de ningún div o sección con otro contenido. Ninguna de las soluciones funcionó para mí hasta que saqué la barra de navegación del div que la barra de navegación compartía con otra barra superior. Anteriormente tenía la barra superior y la barra de navegación envueltas con un div común.


¡Gracias, esto era lo que estaba buscando! Para mí no había padres con desbordamiento, ni hubo problemas de altura. Sería bueno ver esta información también en la respuesta aceptada.
saglamcem

Me acabo de enterar al experimentar que lo adhesivo no se desplazará fuera de su elemento padre. No importa cuántos otros hermanos tenga, pero su padre no puede, aparentemente, ser un contenedor de barra de navegación, pero tiene que ser algo en el nivel de un contenedor de página / contenido :( Esto es ridículo
Ben Philipp

Pero lo! Si puede, si establece el padre límite a display: unset, ¡esta restricción se levanta! ver stackoverflow.com/a/60560997/2902367 también parece trabajar con contents, initialy (?)inline
Ben Philipp

4

de mi comentario:

position:sticky necesita un coordinador para decir dónde quedarse

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>

Hay polyfill para usar en otros navegadores que no sean FF y Chrome. Esta es una regla experimental que se puede implementar o no en cualquier momento a través de los navegadores. Chrome lo agregó hace un par de años y luego lo dejó caer, parece que regresó ... ¿pero por cuánto tiempo?

La posición más cercana sería: relativa + coordinadas actualizadas mientras el desplazamiento una vez alcanzado el punto fijo, si desea convertir esto en un script javascript


4

Sé que esto parece estar ya respondido, pero me encontré con un caso específico y siento que la mayoría de las respuestas pierden el punto.

Las overflow:hiddenrespuestas cubren el 90% de los casos. Ese es más o menos el escenario de "navegación fija".

Pero el comportamiento pegajoso se usa mejor dentro de la altura de un contenedor. Piense en un formulario de boletín informativo en la columna derecha de su sitio web que se desplaza hacia abajo con la página. Si su elemento adhesivo es el único elemento secundario del contenedor, el contenedor tiene exactamente el mismo tamaño y no hay espacio para desplazarse.

Su contenedor debe tener la altura a la que espera que se desplace su elemento. Que en mi escenario de "columna derecha" es la altura de la columna izquierda. La mejor manera de lograr esto es usarlo display:table-cellen las columnas. Si no puede, y está atrapado con float:rightcosas como yo, tendrá que adivinar la altura de la columna izquierda para calcularlo con Javascript.


2
"Si su elemento adhesivo es el único elemento secundario del contenedor, el contenedor tiene exactamente el mismo tamaño y no hay espacio para desplazarse". ¡¡¡ORO!!! ¡Gracias!
Mark Jackson

¡Si! Me tomó un tiempo resolver esto. Al principio me pareció una restricción ridícula, pero supongo que debería haber al menos la opción para eso. Preferiría algo como sticky-limit: parent, sticky-limit: bodyo sticky-limit: nth-parent(3)... De todos modos: si puede, puede levantar esta limitación configurando el padre limitador en display: unset, como se indica en stackoverflow.com/a/60560997/2902367 . También parece funcionar con contents, initial(?) Yinline
Ben Philipp

3

Sé que esta es una publicación anterior. Pero si hay alguien como yo que recientemente comenzó a jugar con la posición: esto puede ser útil.

En mi caso, estaba usando position: sticky como elemento de cuadrícula. No funcionaba y el problema era un overflow-x: oculto en el htmlelemento. Tan pronto como eliminé esa propiedad, funcionó bien. Tener overflow-x: oculto en el bodyelemento parecía funcionar, aunque todavía no tengo idea de por qué.


1

dos responden aquí:

  1. eliminar overflowpropiedad de la bodyetiqueta

  2. configurado height: 100%para bodysolucionar el problema conoverflow-y: auto

min-height: 100% no funciona en lugar de height: 100%


1

Creo que este artículo dice mucho sobre cómo stickyfunciona

¡Cómo funciona realmente CSS Position Sticky! La posición CSS adhesiva tiene dos partes principales, elemento adhesivo y contenedor adhesivo .

Elemento fijo  : es el elemento que definimos con la posición: estilos fijos. El elemento flotará cuando la posición de la ventana gráfica coincide con la definición de posición, por ejemplo: top: 0px.

Contenedor fijo: es el elemento HTML que envuelve el elemento fijo. Esta es el área máxima en la que el elemento adhesivo puede flotar.

Cuando define un elemento con posición: pegajoso, ¡está definiendo automáticamente el elemento padre como un contenedor adhesivo!


1

El comportamiento real de un elemento adhesivo es:

  • Primero es relativo por un tiempo
  • entonces se arregla por un tiempo
  • finalmente desaparece de la vista

Un elemento posicionado de forma fija se trata como relativamente posicionado hasta que su bloque que contiene cruza un umbral específico (como establecer la parte superior en un valor distinto de auto) dentro de su raíz de flujo (o el contenedor en el que se desplaza), en cuyo punto se trata como "atascado" "hasta encontrar el borde opuesto de su bloque contenedor.

El elemento se posiciona de acuerdo con el flujo normal del documento y luego se desplaza en relación con su ancestro de desplazamiento más cercano y el bloque que contiene (ancestro de nivel de bloque más cercano), incluidos los elementos relacionados con la tabla, basados ​​en los valores de arriba, derecha, abajo, E izquierda. El desplazamiento no afecta la posición de ningún otro elemento.

Este valor siempre crea un nuevo contexto de apilamiento. Tenga en cuenta que un elemento adhesivo "se adhiere" a su antepasado más cercano que tiene un "mecanismo de desplazamiento" (creado cuando el desbordamiento está oculto, desplazarse, auto o superposición), incluso si ese antepasado no es el ancestro desplazable más cercano.

Este ejemplo te ayudará a entender:

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


0

Si el arreglo de danday74 no funciona, verifique que el elemento padre tenga una altura.

En mi caso tuve dos hijos, uno flotando a la izquierda y otro flotando a la derecha. Quería que la flotante derecha se volviera pegajosa, pero tuve que agregar una <div style="clear: both;"></div>al final del padre, para darle altura.


No estoy seguro de por qué alguien lo votó negativamente, pero este fue exactamente mi caso: agregué float:leftal elemento padre (sin flotante, su altura era 0) y position:stickyfuncionó.
aexl

0

Usé una solución JS. Funciona en Firefox y Chrome. Cualquier problema, házmelo saber.

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

0

z-indexTambién es muy importante. A veces funcionará pero simplemente no lo verás. Intente configurarlo en un número muy alto solo para estar seguro. Además, no siempre pones top: 0pero prueba algo más alto en caso de que esté oculto en algún lugar (debajo de una barra de herramientas).


0

Esto es lo que me estaba haciendo tropezar ... mi div. Adhesivo estaba dentro de otro div, de modo que el div principal necesitaba algún contenido adicional DESPUÉS del div. te desplazas hacia abajo.

Entonces, en mi caso, justo después del div pegajoso, tuve que agregar:

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

(Mi aplicación tiene dos divisiones de lado a lado, con una imagen "alta" a la izquierda y un formulario de entrada de datos corto a la derecha, y quería que el formulario de entrada de datos flotara junto a la imagen a medida que se desplaza hacia abajo, por lo que el formulario siempre está en la pantalla. No funcionaría hasta que agregue el "contenido adicional" anterior para que el elemento adhesivo tenga algo para "deslizarse"


-1

Es VERDADERO que overflowdebe eliminarse o configurarse initialpara que position: stickyfuncione en el elemento secundario. Usé Material Design en mi aplicación Angular y descubrí que algunos componentes de Material cambiaron el overflowvalor. La solución para mi escenario es

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.