La propiedad de CSS position
, como su propio nombre indica, sirve para posicionar elementos HTML. Anteriormente ya echamos un vistazo general a sus propiedades con especial atención a position:absolute;
, que es uno de sus valores más útiles.
En este post veremos otro interesante valor de esta propiedad: position:sticky;
. No hace mucho me vi en la necesidad de usarlo en un banner, pero había un hándicap, y es que no me funcionaba (cuando todo parecía apuntar a que debería hacerlo) y no entendía por qué.
Si position:sticky;
no te funciona, sigue leyendo, porque quizá estás pasando por alto alguno de los detalles que hay que tener en cuenta para usarlo. Y si no, también, porque te puede ahorrar tiempo en el futuro.
¿Qué hace position: sticky y para qué sirve?
Básicamente hace que el elemento se comporte como en position:relative
hasta que, debido al scroll de la página, el elemento es alcanzado por la parte superior del viewport (no es exactamente así, pero es el uso más habitual). En ese momento se comporta como fixed
, y para que funcione correctamente hay que especificar al menos un valor top
, bottom
, left
o right
, en función de si va a ser sticky en un scroll horizontal o vertical.
Los casos más comunes en los que se aplica esto suelen ser: fijar un menú en la parte superior de la página, resaltar banners, formularios u otras llamadas a la acción.
El caso es que no me funcionaba y no entendía por qué, así que hice lo que haría cualquiera: irme a ver qué dice la especificación.
Vale, seamos sinceros, antes de eso hice una pequeña parada técnica en Stack Overflow 😊, pero después me fui a ver qué decía la especificación, y en la especificación se indica que se desplazará dentro del primer ancestro que tenga un scroll box (que sea scrollable), y si no, tomará como referencia el viewport.
Vale, bien, pero no dice mucho más. ¿Qué quiere decir exactamente scrollable? ¿Que tenga ya scroll en su interior o basta con que pueda tenerlo?
Por otro lado, había leído en Stack Overflow que no va a funcionar correctamente si el elemento padre (el ancestro inmediato) tiene overflow:hidden;
(por favor, hidden se lee "jidden", que más de una vez he oído a algún desarrollador decir "jaiden" y me chirría mucho, manías que tiene uno).
Volviendo al tema. Dado que mi banner estaba rodeado por dos div
anidados, prácticamente iguales y con la propiedad overflow
sin definir; y que en uno funcionaba y en el otro no, deduje que debía intentar averiguar qué significaba exactamente scrollable. O, al menos, intentar acotarlo al máximo.
Para ello preparé un pequeño html de ejemplo, donde todo el contenido está dentro de un elemento main
, en el que hay tres banner iguales y un poco de texto:
- El primer banner consiste solo en una imagen dentro de un hipervínculo
- El segundo es lo mismo que el primero, pero además rodeado por un
div
- Y el tercero es igual al segundo caso, pero el
div
tiene una altura definida superior a la altura de la imagen (y por tanto, del enlace)
En los tres casos definí el enlace como position: sticky
y con un desplazamiento superior de 80px
.
main a {
position: sticky;
top:80px;
border:10px solid #1B75CE;
display:inline-block;
}
Para que en el ejemplo se vean mejor, definí un borde azul para los enlaces y uno naranja para los div
:
El resultado fue el siguiente:
- Como el primer enlace es hijo directo de
main
, y este tiene suficiente contenido como para provocar un scroll en la ventana, en cuanto llega a 80px del borde superior se queda fijo hasta que finaliza el scroll.
- En el segundo caso, el enlace es hijo directo del
div
que lo rodea, y no hay más contenido, así que el enlace nunca se queda en una posición fija.
- En el tercer caso, como el
div
es más alto que el enlace, al hacer scroll el enlace se queda fijo a la vez que el del primer caso, pero se detiene en cuanto se topa con el final de su div
padre.
Resumen y consejos finales con position: sticky
Revisa bien estos puntos para asegurarte de que nada falle:
- Aparte de la propiedad en sí misma, recuerda definir un valor para top (si lo vas a hacer en vertical, que probablemente será lo más habitual). Sea con lo que sea, hay que definir la posición para cuando se quede
fixed
, si no, no funcionará.
- Asegúrate de que ningún ancestro de tu elemento sticky tiene
overflow:hidden;
u overflow:auto;
. Aún diría más, yo pondría en la lista de sospechososos a cualquier ancestro al que se le haya definido un overflow
explícitamente.
- Revisa que el elemento padre sea lo suficientemente grande como para que tu elemento esté sticky hasta donde lo habías planeado.
- Como complemento al punto anterior, ojo con los ancestros que usen flexbox, ya que por defecto provocan que sus elementos hijos crezcan hasta igualar sus alturas, así que ahí no hay scroll que valga a no ser que les modifiques el valor por defecto
align-items:stretch;
.
No te puedo garantizar que si no te funciona se deba exactamente a alguna de estas causas, pero creo que con estas pistas se pueden solucionar la gran mayoría de las incidencias. Al fin y al cabo, la especificación todavía es un borrador y no está tallado en piedra.
Eso sí, recuerda que a día de hoy su soporte es un poco irregular aunque razonablemente bueno. Tenlo en cuenta.
Por cierto, aquí puedes descargarte el ejemplo que he usado. Espero que te resulte útil, déjame en los comentarios tu opinión o cuéntanos si has tenido alguno de estos problemas con esta propiedad. A lo mejor conoces algún detalle que a mí se me haya podido escapar.