CSS Snap Scroll

Ajuste de scroll


El estándar de CSS nos da la posibilidad de utilizar ciertas propiedades de ajuste tras un desplazamiento suave de ratón o con el dedo en dispositivos móviles. Con ello, podemos conseguir que un elemento se ajuste exactamente en el lugar correspondiente que nos interesa, justo al acabar el scroll.

Estas propiedades pertenecen a la familia de propiedades scroll-snap, entre las cuales se encuentran scroll-snap-type o scroll-padding, entre otras, que veremos a continuación. En principio, se dividen entre propiedades que utilizaremos en el contenedor padre, y propiedades que utilizaremos en los elementos hijos.

Para ello, utilizaremos el esquema del ejemplo base del artículo anterior, donde el elemento con clase .container es el elemento padre contenedor y los elementos con clase .slide son los elementos hijos:

<div class="container">
  <div class="slide" id="slide-1">
    Elemento hijo
  </div>
  <div class="slide" id="slide-2">
    Elemento hijo
  </div>
  <div class="slide" id="slide-3">
    Elemento hijo
  </div>
</div>

Vamos a explicarlo por partes, donde diferenciaremos las propiedades aplicadas al contenedor padre y las propiedades aplicadas a los elementos hijos.

Propiedades para el contenedor

Así pues, dentro del estándar de CSS Scroll Snap, tenemos unas propiedades que afectan a nuestro elemento padre contenedor. Son las siguientes propiedades:

PropiedadValoresDescripción
scroll-snap-typenone | Establece el tipo de desplazamiento de scroll y su dirección.
scroll-paddingauto | Establece el relleno que tendrá el scroll.

La propiedad scroll-snap-type

La propiedad scroll-snap-type es la propiedad de control que establece el mecanismo de ajuste de scroll en el desplazamiento por parte del usuario. Para ello, tenemos que indicar dos valores:

CategoríaValorDescripción
x | y | block | inline | bothIndica en que eje ajustará el desplazamiento del scroll.
mandatory | proximityIndica el modo en el que se ajustará al finalizar el scroll del usuario.

En el primer caso, x e y indican si se trata de un desplazamiento en horizontal o vertical. Los valores block e inline son sus equivalentes en propiedades lógicas. Por último, both es ideal si se quiere que se apliquen ambas.

Por último, hay que establecer el tipo de ajuste de desplazamiento. En el caso de mandatory, establecemos que es un ajuste obligatorio y cuando el usuario deje de hacer scroll, el navegador ajustará el scroll para que encaje exactamente con el hijo en esa dirección. En caso de indicar proximity, el navegador ajustará el scroll para que encaje exactamente con el hijo más próximo.

Recuerda que las barras de scroll deben estar visibles para que funcione correctamente. Podrías utilizar overflow-y (por ejemplo) a visible si lo necesitas.

La propiedad scroll-padding

También tenemos disponible la propiedad scroll-padding, que permite indicar una separación de relleno entre el ajuste que encaja exactamente al terminar el desplazamiento y el límite de esa zona. Como la propiedad padding de CSS, scroll-padding también tiene sus propiedades individuales:

PropiedadDescripción
scroll-padding-topIndica un padding de separación en la zona superior al detener el scroll.
scroll-padding-rightIdem a la derecha.
scroll-padding-bottomIdem en la zona inferior.
scroll-padding-leftIdem a la izquierda.
scroll-paddingPropiedad de atajo. 1, 2, 3 ó 4 parámetros (funciona igual que una propiedad padding).

También tenemos otras propiedades como scroll-padding-block o scroll-padding-inline, y sus derivadas como scroll-padding-*-start o scroll-padding-*-end, que son sus equivalentes en propiedades lógicas.

Ejemplo

Retomaremos el ejemplo del capítulo anterior. Sin embargo, observa el CSS de la clase .container. Le hemos añadido una pequeña parte donde activamos las propiedades scroll-snap-type y scroll-padding, previamente indicando que necesitamos scroll en el eje vertical con overflow-y:

<nav>
  <a href="#slide-1">Slide 1</a> ·
  <a href="#slide-2">Slide 2</a> ·
  <a href="#slide-3">Slide 3</a>
</nav>

<div class="container">
  <div class="slide" id="slide-1">
    <h1>Slide 1</h1>
  </div>
  <div class="slide" id="slide-2">
    <h1>Slide 2</h1>
  </div>
  <div class="slide" id="slide-3">
    <h1>Slide 3</h1>
  </div>
</div>
body, h1 {
  margin: 0;    /* Reset margins */
}

nav {
  position: fixed;
  top: 5px;
  right: 5px;
  background: white;
  padding: 5px 10px;
}

.container {
  height: 100vh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scroll-padding: 0;
}

.slide {
  height: 100%;
  background: var(--color, #aaa);
}

.slide:nth-child(2) { --color: steelblue; }
.slide:nth-child(3) { --color: tomato; }

/* Propiedades de elementos hijos */

.slide {
  scroll-snap-align: start;
  scroll-margin: 0;
}

Con scroll-snap-type: y mandatory indicamos que el scroll se va a aplicar en vertical y que va a ser obligatorio, además de no dejar ningún padding de scroll. Prueba a cambiar mandatory por proximity y comprueba que el ajuste se realiza por proximidad, en lugar de forma obligatoria (por dirección).

Sin embargo, todo esto no funcionaría si no establecemos las propiedades de la clase .slide, que afectan a los elementos hijos, y que explicaremos a continuación, en la siguiente parte de este artículo.

Propiedades para los hijos

En las propiedades hijas de nuestro contenedor con CSS Scroll Snap (en nuestro caso .slide), tenemos las siguientes propiedades que nos permitirán configurar el ajuste de scroll:

PropiedadValorDescripción
scroll-snap-alignnone | start | end | center
scroll-snap-stopnormal | always
scroll-margin0 |

Propiedad scroll-snap-align

La propiedad scroll-snap-align es una propiedad que permite indicar la posición de ajuste. Puede tomar los valores start, end y center y en el caso de indicarse dos parámetros, se aplica al eje horizontal (inline) y al eje vertical (block). Si sólo se indica un parámetro, se aplica el mismo valor a ambos.

Para entender esto con nuestro ejemplo, lo mejor es cambiar el height de .slide a un valor como 75% (por ejemplo). Ahora cada slide, ocupará el 75% de la pantalla, y por lo tanto si modificamos scroll-snap-align con el valor...

  • ...start, el .slide ajustará su parte inicial en la parte superior del navegador.
  • ...end, el .slide ajustará su parte final en la parte inferior del navegador.
  • ...center, el .slide se ajustará de modo que esté centrado en el navegador.

Propiedad scroll-snap-stop

La propiedad scroll-snap-stop permite indicar los valores normal o always para permitir que el navegador «atrape» el desplazamiento y lo detenga si pasa por una zona sensible a ajustarse en ella. La diferencia es que el valor por defecto normal permite pasar por una de estas zonas, mientras que el valor always define que si pasa por una zona, se detenga en ella.

Esta propiedad no tiene efecto en situaciones en las que solo tenemos una posición de ajuste.

La propiedad scroll-margin

De forma análoga a scroll-padding, también tenemos una propiedad scroll-margin que podemos aplicar en nuestros elementos hijos. Esta propiedad permite indicar un margen externo al hijo, que permitirá que se vea el elemento anterior (o posterior, dependiendo donde ajustemos), ya que aplica un margen al scroll.

De la misma forma que el anterior, podemos utilizar sus propiedades individuales:

PropiedadDescripción
scroll-margin-topIndica un margin de separación en la zona superior al detener el scroll.
scroll-margin-rightIdem en la zona derecha.
scroll-margin-bottomIdem en la zona inferior.
scroll-margin-leftIdem en la zona izquierda.
scroll-marginPropiedad de atajo. 1, 2, 3 ó 4 parámetros (funciona igual que una propiedad margin).

Ejemplo

En nuestro ejemplo anterior indicamos este CSS adicional:

.slide {
  scroll-snap-align: start;
  scroll-margin: 0;
}

Con la propiedad scroll-snap-align indicamos donde debe detenerse el scroll. Recuerda modificar el tamaño de alto del slide si quieres verlo sobre este ejemplo.

Aumentando la propiedad scroll-margin comprobarás que se establece un márgen que se aplica al scroll con ajuste que estamos realizando en este artículo. También puedes usar las mencionadas propiedades individuales, o indicar 4 parámetros con diferentes valores a modo de atajo.

Recuerda que aunque este ejemplo se haga sobre toda la pantalla y en vertical, podemos utilizar CSS Snap Scroll para crear sliders más pequeños, que no sean a pantalla completa, sliders de imágenes verticales, etc.

El siguiente ejemplo es un pequeño slider horizontal de elementos de texto:

<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
  <div class="item">Item 4</div>
  <div class="item">Item 5</div>
</div>
.container {
  padding: 1em;
  background: lightgrey;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  width: 150px;
  gap: 30px;
  overflow-x: scroll;

  scroll-snap-type: x proximity;
}

.item {
  background: red;
  width: 150px;
  height: 50px;
  color: #fff;

  display: flex;
  justify-content: center;
  align-items: center;

  scroll-snap-align: start;
  scroll-margin: 15px;
}

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev