Distribución de bloques en 1 sola fila y navegación horizontal sin declarar su ancho

Cómo distribuir elementos de bloque sin saber su número en una sola fila, y forzar el scroll-X (navegación horizontal) sin necesidad de fijar la anchura de la caja que los contiene.

Distribución de bloques en 1 sola fila y navegación horizontal sin declarar su ancho

Por Kseso ✎ 11
Distribución y navegación horizontal sin anchuras definidas puro Css

Una de las características de Css en nuestro sistema de escritura es que los contenidos fuerzan el crecimiento de su caja padre en la vertical o altura. Esto supone que lo natural, si no se altera por declaración expresa, es que llegados a un punto aparece el scroll vertical para navegar por la página de arriba a aabajo.

Si deseas cambiar este comportamiento típico hay que declarar un Css para cada caso. Pero casi siempre eso supone tener que crear un sistema de al menos dos cajas enlazadas: La exterior de medidas contenidas (aunque sea en vw/vh) y overflow en X y para la interior (que contendrá la información) calcular su anchura para que quepan sus elementos en una línea sin que se quede ni corta ni larga. Como por ejemplo en este Slider RWD.

Esto no supone problema cuando el contenido (lo alojado en la caja hija anterior) es conocido de antemano. Pero el problema surge cuando ese contenido es variable de caso a caso o se genera dinámicamente.

Ahora imagina la siguiente situación: quieres mostrar un artículo principalmente textual. Por una cuestión de usabilidad y legibilidad de los textos sabes que la anchura ha de ser tal que quepan entre 10 y 15 palabras por línea.

Normalmente marcas una anchura acorde con lo anterior en el cuerpo del artículo para que las líneas no se hagan eternas. Lo que supone que en pantallas "grandes" quedan espacios libres en los laterales. Si el post es lo suficientemente largo genera un scroll vertical considerable.

Una forma de aprovechar esos espacios vacíos en los laterales y minificar el scroll (cambiando el vertical por el horizontal) es recurrir a las multicolumnas Css. Pero evitando que su altura fuerce el desplazamiento vertical.

Esta demo es una variación del post Multicolumnas Css en pestañas. En este caso no generamos ni pestañas ni tampoco necesitamos saber de antemano el contenido para calcular número de columnas ni anchura de cada una.

Nota del Editor. Esta demo en el momento de su publicación generó un interesante debate en los comentarios relativo al comportamiento del scroll al usar la rueda del ratón o flechas de navegación: la expectativa del usuario sería que al hacer "scroll down" o "scroll up" con su dispositivo se tradujese en un desplazamiento horizontal del contenido.
La respuesta a esta cuestión ha sido tripe:
Furoya & Js en el comentario 1.5 construyó una demo usando Javascript.
Jorge MG & Js aporta la suya también basada en Js en el comentario nº 3
Hecho en puro Css la tienes en el post On mouse wheel down... scroll right

En este caso aunque inserto la demo en el post es mejor que la ves a pantalla completa. Redimensiona la ventana para que aparezcan las columnas y su número varíe:

See the Pen MYVpWb by Kseso (@Kseso) on CodePen.

Ver Demo A Full

Marcado html

En este caso partimos de un marcado básico de lo más sencillo:

<body> <!-- cualquiera que sea o necesites --> </body>

Como ves no importa realmente. La razón está en que sólo necesitaremos actuar sobre el body vía Css para logarlo.

Declarando estilos y @medias queries

Toda la magia está en crear las columnas a partir de un tamaño mínimo de la pantalla:

html { height: 100%; box-sizing: border-box; } body { height: 100%; overflow: auto; }

En dispositivos pequeños no hay columnas, el scroll es el típico: vertical. Para que aparezcan 3 columnas de anchura igual a la mitad de la pantalla creamos una regla @media query. En la demo es arbitraria (800px). Las declaraciones más significativas son:

@media screen and (min-width: 800px) { body { columns: 3; column-gap: 2rem; } }

Y para pantallas "gigantes" y para que la línea no resulte demasiado larga, añadimos una segunda @media query. En el caso de la demo y para que pueda ser efectiva en pantalla más comedidas la seteo a 1150px:

@media screen and (min-width: 1150px) { body { columns: 4; } }

¿Cómo?

Lo que está ocurriendo es que al fijar la altura del elemento que crea las columnas (el body), en caso de que la información no quepa en el número de ellas indicadas, se fuerza su crecimiento en aquella dirección que no tiene tamaño indicado. En este caso la anchura.

Basta que anules la declaración height: 100% del body para que sea el scroll vertical el que aparece.

Variaciones

La propiedad columns es la forma acortada (shorthand) de otras dos: column-width (anchura de las columnas) y column-count (el número de ellas. El valor inicial o por defecto es auto.

En los códigos anteriores he fijado el número de columnas por anchura. En este caso, que la anchura de la caja (el body) no está fijada y se fuerza a crecer en función del contenido, para cálculos toma el valor del viewport que ocupa el body.

Así que en vez de indicar el número de columnas en el que se divide el body podemos marcar la anchura de cada columna y dejar su número como auto.

body { height: 100%; overflow: auto; columns: 250px auto; column-gap: 0px; }

Como en la demo siguiente:

See the Pen xbWzPv by Kseso (@Kseso) on CodePen.

Ver Demo

Sin embargo esta variación tiene una particularidad. La anchura declarada de las columnas actúa como anchura mínima. Esto es, el espacio del viewport se divide entre el valor de column-width pero el sobrante (en caso de que no sea un número entero) no es ocupado por la siguiente columna (mostrando sólo una franja vertical de ella). Ese espacio (el resto) se distribuye y añade por igual entre las columnas ya generadas.

Así si se declara como en el código anterior una anchura de la columna de 250px y el espacio disponible en el elemento (antes de forzar su crecimiento) es, por ejemplo, de 550px no se mostrarán 2 columnas completas y 50px de la tercera. Las columnas pasan a tener una anchura final computada de 250px más la mitad del resto (50px/2) = 275px.

Esto supone que si no hay cabida para mostrar dos columnas completas como mínimo, la anchura final de cada columna es el total del viewport.

Apuntes finales

Sin embargo no hay que perder de vista que trabajando con columnas Css te vas a topar con unos cuantos imprevistos, fruto o bien del estancamiento en su desarrollo (CR desde 12 Abril 2011), o bien por bugs e inconsistencias entre los distintos navegadores.

Especialmente notorios en elementos reemplazados (como imágenes) que desbordan la anchura de la columna o los efectos raros si hay animaciones o transiciones.

Si eres un visitante del blog ya veterano recordarás de las dificultades que tuve con un tema basado en columnas allá por 2013. Tantos que al final fue obligado cambiarlo.

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: 11

  1. Hola Kseso.
    Cuando haces scroll con la rueda del ratón la página no se desplaza. Me imagino que al estar el puntero sobre una de las columnas, intenta desplazar esta, pero como no es más alta que el 100% no pasa nada. Estaría bien que se desplazara el contenido con la rueda ¿no?. Creo haber visto alguna web con el scroll horizontal pero no se si tendrían algo de js....

    ResponderEliminar
    Respuestas
    1. Creo que eso depende del navegador. En webkit sí funciona lo de "Shift" + ruedita..

      Eliminar
    2. Bueno, porque eso es un detalle de hardware y su código asociado.
      Todo depende del ratón y su rueda y la programación de su controlador.

      En último caso, por ahí andan código js para actuar sobre ese elemento.

      Un saludo

      Eliminar
    3. Ahora con más tiempo, Jaime

      En un viejo tema que tuve en el blog (el de las columnas y navegación horizontal) tenía implementado algo por el estilo: que el giro de la rueda del ratón se convirtiese en desplazamiento lateral.
      De eso se encargaba un script.

      Para la elaboración del tema me basé en un trabajo de Tommi Kaikkonen.
      Si sigue ese enlace podrás ver en el efecto de girar la rueda y que su giro se traduzca en desplazamientos laterales.

      Entre otros escripts implicados (jQuery) está el que puedes encontrar al final del código de la página enlazada:
      jquery.mousewheel.min.min-0f27db91.js

      Si decides jugar un poco con el uso de columnas ya nos contarás tus experiencias.

      Un saludo

      Eliminar
    4. Me parecía indispensable que cuando se hace sroll con el ratón la página se mueva por que es lo que todos esperamos, pero entiendo perfectamente que no es el tema de este artículo. Quizás no debí comentarlo. Aun así y gracias a tu respuesta he estado entretenido toda la tarde. No he conseguido nada ;P. Me falta mucho por aprender...

      Eliminar
    5. Perdón que vuelva con esto, pero me quedé pensando en tu último comentario.
      No sé si es indispensable. Es cómodo, pero hay que marcar algunas salvedades. En primer lugar, el desplazamiento horizontal no es natural a nuestro modo de lectura; será un mal necesario o tolerable en los móviles, pero a nosotros para leer o estructurar una página no nos sirve.
      Porque leemos de izquierda a derecha y de arriba hacia abajo.
      Cuando el espacio se nos acaba a la derecha, seguimos en la línea de abajo. Cuando se nos acaba el espacio abajo nos desplazamos y seguimos con el nuevo "renglón". Entonces sí el desplazamiento tiene sentido, porque vamos arrastrando el documento infinitamente para continuar con la lectura hasta donde nos quede cómodo (media página, una línea, ...) y lo podemos hacer a pulso.

      En el caso de movernos horizontalmente, será sólo para documentos diseñados "a viewport completo", porque no leemos verticalmente y después cuando se termina el espacio a la derecha desplazamos otro poco del documento : lo que debemos hacer es desplazar toda una página para ver el siguiente "bloque".
      Así que la ruedita del maus no sirve de nada, tenemos que dar un montón de giros para acomodar el bloque, y no pasarnos porque hay que regresar y hacer un posicionamiento "fino" hasta acomodar el cuadro en el espacio para el documento. Si la ruedita "saltara" no unas pocas líneas sino una página entera (en este caso, horizontalmente) ya sería otra cosa.

      Muy acertada tu aclaración sobre que la objeción al fin no tiene que ver con el artículo. Es un ejemplo de distribución de contenido, no una plantilla para que copien y peguen. Si alguien le quiere agregar el wheel event, nada se lo impide. Lo que me sorprendió es que hayas pasado toda una tarde y no hayas encontrado nada (¿ni en los enlaces que te dejó Kseso?). Ahora que hay más compatibilidades, es muy fácil hacer eso, y tiene que estar por todos lados. Ahí sí hasta sería negocio "copiar y pegar".
      Antes de escribirte esto me hice uno de aburrido; que es elemental, básico, casi pavote, nada más una estructura simple para que se entienda (bueno, hacen falta conocimientos básicos de JS) que está aplicada a uno de los tantos modos de mover "páginas" en HTML (¡porque ni usé CSS!). No le puse desplazamiento suave, ni nada. Aclaro para que no me hagan lo mismo que al redactor del artículo superior, y me reclamen lo irreclamable.

      Está aplicado a una galería de imágenes (de los pocos casos donde una estructura así se justifica) y te la dejo para que nadie diga que "no encuentra nada"; no porque tenga algo que ver con el tema del blog.

      Horizontal mouse wheel..

      Eliminar
    6. Hola Furoya. Gracias por dejarme tu punto de vista. Que me perdone Kseso a mi también por volver sobre el tema (más que nada por reincidir sabiendo que no es el tema principal del artículo).
      Coincido en todo lo que has expuesto aquí pero voy a darte mi punto de vista.
      "El desplazamiento horizontal no es natural a nuestro modo de lectura" Totalmente de acuerdo, pero si la página web está diseñada así (como creo que es en este artículo), si cuando das a la rueda del ratón no se mueve la página puede parecer que no hay más contenido que el que se muestra. Creo que todos esperamos que al dar a la rueda la página se mueva.

      "Lo que debemos hacer es desplazar toda una página para ver el siguiente "bloque".
      Así que la ruedita del maus no sirve de nada, tenemos que dar un montón de giros para acomodar el bloque, " Totalmente de acuerdo. Y verás que lo que conseguí al final es esto que tu dices y que no es para nada cómodo.

      "Lo que me sorprendió es que hayas pasado toda una tarde y no hayas encontrado nada (¿ni en los enlaces que te dejó Kseso?)"
      Toda una tarde y no pude sacar nada en claro. Eso si, al día siguiente y creo que por tener la mente más despejada pude hacer "algo" muy básico (en http://horizontalscroll.jaimepascual.es/ tengo lo que logré). Te repito que me queda mucho por aprender e insertar un jquery para mi es una odisea. Nadie nace aprendido y no me avergüenza decir que mi nivel es muy bajo.

      "Aclaro para que no me hagan lo mismo que al redactor del artículo superior, y me reclamen lo irreclamable"
      Yo no reclamé nada a Kseso, simplemente dije que esperaba que al mover la rueda del ratón la pantalla se moviera. Y aunque en un principio me he arrepentido porque entendí que no tenia nada que ver con el post, al ver que he aprendido algo me he sentido un poco mejor.

      Verás en el enlace que he puesto lo rudimentario y básico que es lo que se y comprobarás que para resoluciones de menos de 800px el scroll vertical no funciona (claro, lo impide el archivo js que hay al principio y que "obliga" a hacer scroll horizontal). Sigo investigando para ver como puedo "desactivar" este comportamiento en resoluciones pequeñas y "activarlo" en resoluciones grandes (como en el ejemplo que me dejo Kseso). Agradecería un comentario que me lleve a la solución más rápidamente y poder pasar a otro tema.

      Te agradezco sinceramente tu comentario ya que me pone con fuerzas renovadas sobre lo que he logrado para hacerlo mejor (ya me gustaría poder tener algún día el nivel suficiente para colaborar como haces tu con Kseso)

      Eliminar
  2. Señores. se me vayan un ratito a tomar el vermut o unas cañas y dejen allí sus "perdón, que me perdone..." y gaitas por el estilo
    xD xD

    Ahora en serio, Jaime: no necesitas disculparte por nada. Yo con mis artículos sólo pongo el campo de juego y vosotros, sus lectores, ya jugáis a lo que surja y como surja. Quicir: que una conversación puede y debe tomar los derrotéos que sus intevinientes quieran. Y está bien y es bueno que así sea.

    En el caso concreto que planteas, el ratón en su funcionamiento depende totalmente de su "programación".
    Recuerdo una vieja conversación con Mikemoro en donde ya salieron estas diferencias en el comportamiento del ratón. No no voy a buscarla.

    Ha ratones que el giro "vertical" de la rueda lo convierten en desplazamiento de la página horizontal si hay scroll-X y no scroll-Y.
    Otros permiten un pequeño movimiento de la rueda a izquierda / derecha para el scroll-X
    Otros... en fin, cada uno tiene sus prestaciones y funcionamiento.

    En el caso que nos ocupa, os habéis planteado el desplazamiento de la página con la rueda del ratón. Y está bien.
    Pero mal anfitrión sería si no os provocase un poquito ;-)

    <troll>
    ¿Por qué sólo os preocupáis del ratón?
    Hay otros tipos de navegación que en la página horizontal se ven afectadas.
    Como por ejemplo la teclas "Inicio" / "Re Pág" / "Av Pág" / "Fin"
    O las teclas ← ↑ ↓ → Hay que usar las horizontales, las verticales quedan off

    Como veis yo he venido aquí sólo a crear cáos y confusión xD
    </troll>

    Por cierto Furoya ¿probaste en el pen de tu último comentario a usar la tecla tab? Porque el desplazamiento lateral también me funciona con ella (hacia la derecha) y puedo retroceder (scroll hacia la izquierda) con Mayusculas + Tab

    Un saludo

    P.D.: no os desviéis de lo planteado por Jaime por mi intervención.

    ResponderEliminar
    Respuestas
    1. ¡De ninguna manera nos vamos a desviar, si al final lo pusiste interesante!

      Con respecto a lo de "perdón" ... pues uno quiere simular que es educado, y no lo dejan. Desde ahora voy a seguir siendo el mismo cavernícola salvaje de siempre.
      XD

      Sí, sabía lo de [Tab] porque en realidad estuve usando desplazamiento HTML, que si no se configura distinto en el SO, mueve el documento hasta el elemento en foco, que en ese ejemplo es un botón transparente de ancho 100%, así que nos va a poner justo cada bloque donde queremos. (Sí, el método funciona también con tus inventos donde la pseudoclase ':focus' cambia de página con CSS).
      Lo de las teclas se puede hacer. Pero Jaime no lo mencionó, y yo no voy a trabajar de más. Aunque las de dirección ya andan, sólo hay que poner en foco la ventana (con un click por el medio alcanza).


      Y ya que lo mencioné ... de nada, Jaime, no te puse el pen aquí porque es más que nada javascript, sería un abuso. Pero dejé el link para que lo puedas estudiar. Lo tuve que corregir, porque creí que el atributo 'onwheel=' ya andaba en IE, pero no, hay que seguir usando 'onmousewheel='. De cualquier forma, en una página real se "ponen" (virtualmente) con 'addEventListener()' a cada cual el que le ande.

      Una cosa que me molesta es cuando se copia y pega código sin entenderlo, esperando que magicamente funcione en cualquier circunstancia. En realidad no me hubiese molestado en escribir estas parrafadas, o en hacer y después corregir una demo, si no fuese porque me pareció que decías la verdad sobre buscar y estudiar lo que encontraste. Sos un buen ejemplo a seguir.


      Por lo general, nadie recomienda usar un jquery para efectos tan simples. Es cargar una library que la mayoría de las veces sirve para mil cosas, y nosotros le usamos una. Lo demás es lastre. Y después pasan estas cosas, que en alguna circunstancia ya no se comportan como uno quiere, y hay que ponerse a desarmar el escript para ver dónde corregirlo.
      Pero para eso hay que saber, ¡y si uno sabe no precisa de estos frameworks!.
      Para cosas más complejas, supongo que sirven; si son buenos ya deben estar probados por otros y nos ahorran trabajo. Pero si vendés una página con un JQ para hacer una rotación de banners, ... es un papelón. (Rogá que el cliente no entienda de programación web.)

      Con respecto a tu caso, quitando el 'preventDefault()' cuando el ancho encaje en alguna medida que no tenga scroll horizontal ya debería funcionar. Pero nunca aprendí la sintaxis JQuery, así que no tengo idea de cómo se puede modificar.
      Otra cosa que hay que hacer es el efecto compatible con Mozilla.

      Un saludo.

      Eliminar
  3. Aprovechando la vuelta de este artículo a la portada, coincido con anteriores comentarios de que el comportamiento esperado sería que la rueda del ratón desplazara horizontalmente el elemento.
    Pero como no ocurre así, he creado un pequeño script que captura el scroll de la rueda y lo convierte en horizontal:
    [code]
    var mouseWheelEvt = function (event) {
            var pix = 100, // número de píxeles de desplazamiento
                 sign = (event.type=="DOMMouseScroll")?(-1):(1); // cuando se usa el evento DOMMouseScroll, hay que invertir el signo del scroll porque event.detail se obtiene multiplicado por -1
            if (this.doScroll)
                    this.doScroll(event.wheelDelta>0?"left":"right"); // IE permite hacer scroll hacia left o hacia right sin indicar píxeles con doScroll
            else if ((event.wheelDelta || event.detail) > 0)
                    this.scrollLeft -= pix * sign; // restamos scroll, es decir, desplazamos a la izquierda (mousewheel) o a la derecha (DOMMouseScroll)
            else
                    this.scrollLeft += pix * sign; // sumamos scroll, desplazamos a la derecha (mousewheel) o izquierda (DOMMouseScroll)
            event.preventDefault();
    }
    document.querySelector('body').addEventListener('mousewheel', mouseWheelEvt);
    document.querySelector('html').addEventListener('DOMMouseScroll', mouseWheelEvt); // en Firefox se usa el evento DOMMouseScroll
    [/code]
    Además de las consideraciones que he añadido en los comentarios del script, hay que tener en cuenta que, cuando el scroll se aplica en el elemento raíz (como en el caso de las demos de esta página), en Firefox esta raíz es el elemento <html>, mientras que en otros navegadores es <body>.
    Y, por supuesto, es JavaScript puro, no necesita ninguna librería extra.

    ResponderEliminar
    Respuestas
    1. Gracias Jorge MG por tu aportación.
      La incluyo como ampliación al inicio del artículo junto con las otras dos surgieron en su momento.

      Un saludo

      Soluciones a la cuestión del scroll:

      Furoya & Js en el comentario 1.5 construyó una demo usando Javascript.
      Jorge MG & Js aporta la suya también basada en Js en el comentario nº 3.
      Hecho en puro Css la tienes en el post "On mouse wheel down... scroll right"

      Eliminar

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