soy Kseso y esto EsCSS

Position-sticky: Títulos pegajosos y siempre visibles hasta que llega el siguiente

Cómo conseguir con sólo CSS que los títulos de cada parte de un artículo permanezcan fijos en la parte superior hasta que llega el siguiente apartado y con su título correspondiente que lo reemplazará. Incluye vídeo y demo.

Position-sticky: Títulos pegajosos y siempre visibles hasta que llega el siguiente

Por Kseso ✎ 8

Al escribir un artículo sueles dividirlo en secciones o partes, cada una de ellas encabezada por un titular. Si has planificado bien, cada encabezado de estas partes deberían ser h2 ya que habrás reservado el h1 para el título general del post.

Y lo que suele ocurrir a poco extensos que sean estos bloques es que a medida que vas leyendo scroll este titular desaparece de la vista al hacer scroll. Y si el lector no ha estado atento, lectura diagonal que dicen, al momento de fijar su atención en algún elemento no sabrá exactamente a qué corresponde.

Así que lo ideal sería que el título de cada parte del post permaneciera visible hasta que dicha parte terminase, y que fuese sustituido por el siguiente título (en caso de que hubiese más secciones). Y al terminar el artículo y pasar a otras partes secundarias de la página (comentarios, pie de página...) desapareciera para no confundir.

Pues esto que hasta hoy necesitaría de una buena dosis de codificación es posible con un par (contadas) de declaraciones Css:

.elemento { position: sticky; top: 0; }

Position: sticky

Con la llegada del documento "CSS Positioned Layout Module Level 3" en este blog le dediqué una entrada (ahora hace 2 años) a los nuevos valores que introducía para la declaración position: sticky.

Para que entiendas el comportamiento de este nuevo valor. Imagina un elemento cualquiera, por ejemplo un h2, dentro de su padre, por ejemplo un article, en cualquier parte de él (con hermanos antes y después de él).

El comportamiento del h2 será el siguiente: a medida que haces scroll desplazando el article se desplazará con él (como si su posición fuese relative hasta alcanzar la parte superior de la ventana. Una vez ahí arriba permanecerá como si su posición fuese una especie de fixed o absolute hasta que la parte inferior del article alcance la parte superior del viewport, momento en que el h2 también sigue subiendo para desaparecer.

Y al bajar (scroll contrario) su comportamiento es igual a la inversa.

¿Complicado? No. Soy yo que me explico fatal. Si usas Firefox, Chrome Canary o Safari sólo tienes que fijarte en el comportamiento de los títulos principales de cada parte de este artículo.

Y si usas otro navegador, lo que ves en este vídeo:

Vídeo del comportamiento de position: sticky;

Obligado declarar situación

Si regresas al código anterior, verás que junto a la propiedad position está declarada una de situación o emplazamiento: top: 0;

Esta segunda declaración de emplazamiento es obligatoria para que position: sticky; funcione. Y su valor indica a qué distancia de la parte superior se quedará fijo el elemento.

Si es 0 (cero) no dejará ningún espacio entre el tope y él. Cualquier otro valor lo mantendrá a dicha distancia (si es positivo) y lo sobrepasará si es negativo.

Más fácil y sencillez de declarar y con resultados tan prácticos y vistosos en pocas otras propiedades lo encontrarás.

Y para terminar, te dejo una demo en base a esta declaración position: sticky y jugando un poco con z-index

See the Pen CSS position: sticky by Kseso (@Kseso) on CodePen.

Recuerda que debes visualizarlo con Firefox, Chrome Canary o Safari. Aquí puedes ver su soporte de forma detallada.

Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Don Kseso Kseso

Comentarios: 8

  1. En Chrome no funciona ni con prefijos ni con el 'enable-experimental-web-platform-features'. No hay caso.
    Y debe ser porque esto aún está verde. Tiene varios "detalles" por corregir. Uno evidente, es que no se "comunica" con el navegador para decirle que el view-port fue forzado a cambiar de tamaño; y una consecuencia inmediata es que si nos desplazamos con "Retrocede página" o con "Avanza página" o con la barra espaciadora el salto ignora la altura del sticky y se desplaza como si pudiésemos ver hasta arriba (o abajo).
    Por supuesto que es el mismo problema que teníamos al hacer esto mismo por nuestra cuenta, pero ahora que es oficial, los desarrolladores tienen la obligación de resolverlo antes de implementarlo.

    ResponderEliminar
    Respuestas
    1. En Chorme estable en versiones anteriores se podía habilitar mediante chrome://flags. Sin embargo en la versión 37 (actual) fue removido.

      No se que pruebas hiciste, Furoya, esta vez. Pero sí reconoce y funciona con "Av Pag y Re Pag, Al menos en FF.
      Date cuenta que en este blog (puedes hacer la prueba en este artículo mismo) sólo lo uso para los h2 del cuerpo del artículo (contenido) y en resoluciones mayores de 600px.

      Eliminar
    2. Nooop.
      No lo hace. Verás, el problema del scroll por página es que el navegador calcula la distancia a mover dependiendo no sólo del nivel de zoom, sino (y por supuesto) de la altura del viewport. En vez de mover realmente de "a una página" lo que hace es desplazar "casi" la altura visible. Esto es para que el último texto que ves debajo termine como el primero que queda arriba, y nos sirva de referencia para seguir leyendo.
      Pero al fijar una capa arriba delante del documento, esas líneas previamente leídas (y alguna que otra que aún no leímos) queda tapada, y tenemos que desplazar "por pasos" un poco hacia abajo para poder leer desde donde dejamos.

      Cuando inventábamos esto con JS, teníamos que leer la altura del banner fijo y crear un desplazamiento que lo contemplara, o si era un título, usar algún método para contraerlo dejando solamente una pestaña, y si queríamos confirmar la sección que veíamos le pasábamos el puntero por encima y se desplegaba. En realidad lo que quedaba fijo era un botón o pestaña del título.

      Supongo que ahora también se puede hacer con CSS, pero vamos a esperar que lo corrijan los navegadores.
      Porque lo van a tener que hacer, no les cuesta nada.

      Eliminar
    3. Pues si tú dices que no y yo que sí y suponiendo que los dos usamos FF (ver. 32.0.2 yo) y sabiendo que no hay necesidad de mentir... cabe deducir que es alguna otra variable la que crea la discrepancia y no la propiedad en sí.
      Posíblemente la implementación en según qué.

      No se si será el SO (vi$ta en mi caso) o qué.
      Te adjunto vídeo
      En él uso para navegar un teclado en pantalla (cutre, sí, pero para la demo suficiente). Con el teclado físico el resultado es el mismo: el h2 permanece sticky hasta que llega el siguiente que es el que se muestra.

      Hay un pequeño detalle en el uso que hago aquí, en los posts del blog:
      Como todos los h2 (títulos) comparten caja padre realmente no son desplazado al llegar el siguiente a la parte superior del viewport. Permanecen todos ahí, sólo que se ve él último en "llegar" por una cuestión de apilamiento vertical (z-index no declarado = a todos el mismo prevaleciendo el último que aparece en el html).

      Eliminar
    4. Es que me parece que hablamos de cosas distintas. A pesar de que hay un teclado en pantalla tapando el texto, en el video está clarísimo ese error en el desplazamiento.

      Veamos. En la marca 0:02 las líneas finales son
      form ... [ ⌨ ] ... lores de
      los ... [ ⌨ ] ... los.

      En la marca 0:03 se desplaza una página y arriba no quedan esas líneas sino
      naturaleza del elemento ... ... equiparado

      y debajo
      inform ... [ ⌨ ] ... ral. Sería
      el text ... [ ⌨ ]

      Ya en la siguiente marca 0:04 arriba tampoco queda el texto previo sino
      elemento que no fuese table.

      y al pié solamente se ve un marcador de lista. Que ya no nos importa porque me parece que se entiende dónde está el error. Lo que debería estudiar es eso que comentás sobre el padre compartido, quizá con otra diagramación el navegador se dé cuenta que hay un elemento con posición fija que se come parte del viewport.
      En el ejemplo incrustado de Codepen pasa exactamente lo mismo, pero allí hay un recurso que funciona y olvidé mencionar más arriba : el título es semitransparente, y deja leer el texto que tiene debajo; que es el que nos sirve de referencia para no perdernos. Claro que si tapa dos líneas, a una nos va a costar interpretarla, así borrosa y mezclada con las letras del título.
      Pero algo es algo, y peor es nada.

      Eliminar
    5. ah! Era eso.
      Ya comprendo. Te refieres a la falta de precisión en el avance, no a su funcionamiento.

      Mis disculpas, se ve que ayer no era mi mejor día en cuanto a comprensión lectora.

      Eliminar
    6. Sí, me imaginé, no hay problema.
      Lástima que te tuviste que poner a hacer un video.

      Cabe aclarar que este problema también existe en la posición 'fixed' pura y limpia. Y no estaría de más una propiedad CSS que le dijera al navegador si debe restar la altura de un elemento fijo en el viewport, cuando llega a uno de los bordes.
      Porque se puede dar el caso de que no sea necesario. Y eso lo sabe el diseñador.

      Eliminar
  2. Tengo chrome canary, y nones. ¡lastima me había emocionado!

    ResponderEliminar

EsCss RSS del Blog RSSS Comentarios Humans.txt ᛯ Diseno por Kseso SiteMap