Colocación automática de cuadrícula compatible con IE10 con Flexbox | Programar Plus

Si trabaja en aplicaciones web que admiten navegadores más antiguos y ha deseado CSS Grid desde el margen como yo, tengo buenas noticias: ¡he descubierto una forma inteligente solo CSS de usar la ubicación automática de cuadrícula en IE10 +!

Ahora, en realidad no es CSS Grid, pero sin mirar el código en sí, no podría saberlo. La estructura HTML se parece a CSS Grid. Tiene un conjunto definido de columnas con una cantidad indefinida de filas y tiene medianeras que admiten bordes y sombras en las celdas sin cortes. Pero lo que realmente está sucediendo detrás de escena es una combinación de flexbox y márgenes.

En este artículo, explicaré el enfoque. Aquí hay una demostración de lo que estamos viendo:

ver la pluma
Diseño de columna similar a CSS-Grid compatible con IE10 por Brian Holt (@bholtbholt)
en CodePen.

Filas de flujo automático con envoltura flexbox

Cinco rectángulos naranjas en dos filas con tres en la primera fila y dos en la segunda fila.Cuadrícula de ubicación automática creada por Flexbox

Obtener la configuración básica de la red es muy simple. Si está familiarizado con flexbox, estoy seguro de que ya lo ha adivinado flex-wrap: wrap es el truco aquí. Y tendrías razón.

Pongamos el marcado HTML en su lugar antes de escribir cualquier CSS. Queremos que se asemeje a la misma estructura que si estuviéramos usando la colocación automática: una .grid contenedor y un número indefinido de .grid__cells.

<div class="grid">
  <div class="grid__cell">...</div>
  ...
</div>

Establecemos tres puntos de interrupción de la cuadrícula. Un diseño de una columna, dos columnas y tres columnas para dispositivos móviles, pantallas pequeñas y pantallas medianas, respectivamente. Estoy usando los puntos de interrupción utilizados en Bootstrap para este artículo, aunque nos gustaría definirlos en puntos reales donde el diseño se rompe si estuviéramos trabajando con contenido real.

$screen-sm-min: 768px;
$screen-sm-max: 991px;
$screen-md-min: 992px;

Cinco rectángulos naranjas apilados uno encima del otro.La cuadrícula móvil primero se colapsa en una sola columna

Un enfoque móvil primero significa que nuestro diseño de una sola columna ya está completo, ya que cada .grid__cell ya es un bloque. Establecimos .grid para convertirse en un contenedor de caja flexible después del primer punto de interrupción y envolver las celdas.

@media (min-width: $screen-sm-min) {
  .grid {
    display: flex;
    flex-wrap: wrap;
  }
}

Nuestros diseños de dos y tres columnas necesitan anchos explícitos y propiedades flexibles; de lo contrario, se amontonarán en una sola línea. Mientras probaba IE10, experimenté un comportamiento inesperado con el flex-basis propiedad, y encontró establecer un ancho explícito con flex-basis: auto era más consistente. Sin embargo, esto no parecía ser un problema con IE11.

.grid__cell {
  min-width: 0;
  flex: 1 1 auto;
}

// Two-column grid
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
  $width: 50%;

  .grid__cell {
    width: $width;
  }
}

// Three-column grid
@media (min-width: $screen-md-min) {
  $width: 33.33%;

  .grid__cell {
    width: $width;
  }
}

No necesitamos envolver .grid__cell en una consulta de medios, ya que sus propiedades flexibles no tendrán efecto cuando el padre no sea un contenedor de caja flexible. También definimos un límite superior para la consulta de medios de dos columnas para que no afecte la cuadrícula de tres columnas.

¡Y eso es! Ahora tenemos una cuadrícula flexbox receptiva, fluida y envolvente. La parte fácil está hecha… bueno, siempre y cuando solo tengamos elementos que sean múltiplos de dos y tres. Con flex: 1 1 auto, el último elemento siempre ocupará el espacio restante en la última fila.

Tres filas de rectángulos naranjas.  Las dos primeras filas tienen dos columnas de cuadros y la tercera fila tiene un solo cuadro que abarca ambas columnas.Cuadrícula de dos columnas en pantallas más pequeñas
Dos filas de rectángulos naranjas.  La primera fila tiene tres columnas de rectángulos y la segunda fila tiene dos rectángulos que abarcan todo el ancho.Grilla de tres columnas en pantallas grandes

Alineación de celdas en la última fila

La última fila elusiva es por qué estamos aquí, ¿verdad? De forma predeterminada, cada celda se extenderá hasta el final de la fila en un diseño flexible, pero la cuadrícula deja un espacio en blanco. ¿Cómo hacemos eso en flexbox? ¡Con pseudo-elementos!

El truco es agregar un pseudo-elemento al .grid contenedor y configúrelo como una celda. Definimos el :after celda de pseudo-elemento en cada uno de nuestros puntos de ruptura con el mismo ancho que una celda real.

@media (min-width: $screen-sm-min) {
  .grid {
    ...

    &:after {
      content: '';
      display: block;
      flex: 1 1 auto;
    }
  }
}

@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
  $width: 50%;

  .grid:after {
    width: $width;
  }
}

@media (min-width: $screen-md-min) {
  $width: 33.33%;

  .grid:after {
    width: $width;
  }
}

Esto crea una celda falsa que empujará contra nuestras celdas reales y alineará nuestra cuadrícula de dos columnas cuando las celdas sean impares. Dejar su altura indefinida le permite colapsar a la nada cuando las celdas son uniformes.

Tres filas de rectángulos naranjas.  Las dos primeras filas tienen dos columnas, cada una con un rectángulo.  La tercera fila tiene un solo rectángulo y una columna vacía.Cuadrícula de dos columnas con celdas impares, encajando en su lugar

Nuestra cuadrícula de tres columnas es un poco más compleja porque necesitamos manejar múltiples estados, como cuando hay una celda vacía y cuando hay dos celdas vacías.

Cuadrícula de tres columnas de rectángulos naranjas con dos filas.  La segunda fila solo tiene un rectángulo y una columna vacía.Cuadrícula de tres columnas con una celda vacía

Nuestro estado de una celda vacía ya está manejado porque en realidad no es diferente de una celda vacía en dos columnas. El :after celda tiene su ancho establecido y completa la fila. Sin embargo, la historia cambia cuando hay dos celdas vacías porque flex: 1 1 auto asoma la cabeza de nuevo: la última celda ahora se extiende a lo largo del 50% del ancho cuando se empuja contra el pseudo-elemento.

Cuadrícula de tres columnas de rectángulos naranjas con dos filas.  La segunda fila tiene un rectángulo que abarca la mitad del ancho de la cuadrícula y deja un espacio en blanco vacío.Cuadrícula de tres columnas con dos celdas vacías

Usando CSS :nth-of-type selectores, podemos apuntar a la primera columna de cada fila. Dado que nuestras filas son múltiplos de tres, las apuntamos con 3n luego cuenta hacia atrás por 2 para obtener el primer elemento de cada fila.

@media (min-width: $screen-md-min) {
  .grid__cell {
    ...

    &:nth-of-type(3n-2) {
      background-color: red;
    }
  }
}

Cuadrícula de tres columnas de rectángulos.  La primera columna de rectángulos es roja indicando los rectángulos que se seleccionan con CSS.  Los otros rectángulos son naranjas.Orientación a la primera celda de cada fila de tres columnas

En términos generales, nos dirigimos a todas las celdas de la primera columna, pero debemos limitar la selección solo a la última fila. En realidad, debemos limitarlo a cuando es la última celda en la primera columna de la última fila. Afortunadamente, hay un práctico pseudo-selector para apuntar al último elemento de este tipo. encadenamos :last-of-type para crear la declaración lógica.

@media (min-width: $screen-md-min) {
  .grid__cell {
    ...
    &:nth-of-type(3n-2):last-of-type {
      background-color: red;
    }
  }
}

Ahora que tenemos seleccionada la última celda en la primera columna de la última fila, usamos un margen para empujar el :after celda hasta la última columna y llene la celda del medio.

@media (min-width: $screen-md-min) {
  .grid__cell {
    ...

    &:nth-of-type(3n-2):last-of-type {
      margin-right: $width;
    }
  }
}

Aquí está nuestro flexbox-defined-auto-placement-grid-imitator en su totalidad. Mira sus filas bellamente alineadas. ¡Apuesto a que ni siquiera puedes decir que no es CSS Grid!

Cuadrícula de tres columnas con tres filas de rectángulos naranjas.  La última fila tiene un solo rectángulo en la primera columna y las otras dos columnas están vacías.Nuestra grilla completa de tres columnas.

Adición de medianeras con márgenes

La especificación de CSS Grid tiene un espacio entre columnas y filas para proporcionar espacio entre cada celda. Crear canales en flexbox es mucho más desafiante. Parece que llegará a flexbox, pero aún no hemos llegado… e IE nunca lo estará.

En Daniel Tonónguía de CSS Grid en IE, usó un div de celda interna con márgenes negativos, bordes, un poco de relleno y overflow: hidden. Aunque tal vez un poco raro, el efecto funciona, pero rompe nuestro deseo de mantener una estructura HTML similar a CSS Grid. El enfoque que prefiero puede parecer un poco tosco, pero también me pareció el más fácil de leer y entender. Además, continúa usando :nth-of-type pseudo-selectores que hacen que el enfoque general se sienta consistente.

Queremos espacios entre las celdas, pero no alrededor del exterior. También queremos que nuestras celdas queden al ras del contenedor.

Una cuadrícula de tres por dos de rectángulos naranjas.  Una flecha de bloque apunta a un espacio entre los rectángulos.Espacios entre las celdas, no en el exterior.

Nuestra cuadrícula móvil o de una sola columna solo necesita un margen inferior en las celdas. Agregamos eso y anulamos la última celda con margin-bottom: 0 para que la celda encaje al ras contra el contenedor. Normalmente usaría initial, pero no hay soporte en IE.

$col-gap: 16px;

.grid__cell {
  ...
  margin-bottom: $col-gap;

  &:last-of-type {
    margin-bottom: 0;
  }
}

Una sola columna de rectángulos naranjas en cinco filas.Cuadrícula de una sola columna con espacios entre cada fila

Nuestras cuadrículas de dos y tres columnas necesitan márgenes a la derecha de las celdas, sin márgenes derechos en la última columna y sin márgenes inferiores en ninguna de las celdas de la última fila. Debido a los márgenes, también necesitaremos recalcular nuestros anchos ya que las celdas se envolverán si no encajan.

En un diseño de dos columnas, obtener la columna correcta (o la segunda) es bastante fácil con :nth-of-type(2n) o :nth-of-type(even). Prefiero un multiplicador n por coherencia con nuestra cuadrícula de tres columnas y para calcular la última fila.

Nuestra última fila es un poco más complicada. Cuando tenemos celdas impares, nuestro CSS móvil primero se encarga de eliminar los márgenes inferiores ya que la celda es la :last-of-type y nuestro :after la celda no tiene márgenes aplicados.

Una cuadrícula de dos por tres de rectángulos naranjas.  El último rectángulo es un poco más alto que los demás.Dos columnas con celdas pares

Cuando tenemos celdas pares, debemos apuntar a la penúltima celda, pero solo cuando está en la posición de la primera columna. Si no lo calificamos, la penúltima celda crecerá verticalmente para coincidir con la altura de la penúltima fila. Podemos orientarlo con :nth-of-type(2n-1):nth-last-of-type(2).

@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
  $width: calc(50% - #{$col-gap});

  .grid__cell {
    ...
    margin-right: $col-gap;

    // Remove margin in last column
    &:nth-of-type(2n) {
      margin-right: 0;
    }

    // For when the last row is complete
    // . .
    // * .
    &:nth-of-type(2n-1):nth-last-of-type(2) {
      margin-bottom: 0;
    }
  }
}

La misma cuadrícula de dos por tres que antes, pero con el último rectángulo a la misma altura que el resto.Dos columnas con celdas uniformes que se asientan al ras contra el contenedor

Nuestros canalones de tres columnas adoptan el mismo enfoque. Añadimos margin-right a todos ellos, elimínelo de la tercera columna y elimine los márgenes inferiores de la última fila. Nuevamente, nuestra última celda es manejada por nuestro enfoque móvil primero, pero ahora debemos cubrir cuándo hay dos celdas en la última fila y cuándo hay tres celdas. Podemos calificar a nuestros selectores con nth-of-type y nth-last-of-type.

@media (min-width: $screen-md-min) {
  $width: calc(33% - #{$col-gap});

  .grid__cell {
    ...
    margin-right: $col-gap;

    // Remove margin in last column
    &:nth-of-type(3n) {
      margin-right: 0;
    }

    // For when there two items in the last row
    // . . .
    // * .
    &:nth-of-type(3n-2):nth-last-of-type(2) {
      margin-bottom: 0;
    }

    // For when the last row is complete
    // . . .
    // * * .
    &:nth-of-type(3n-1):nth-last-of-type(2),
    &:nth-of-type(3n-2):nth-last-of-type(3) {
      margin-bottom: 0;
    }
  }
}

Una cuadrícula de tres por tres de rectángulos naranjas, con la última celda vacía.Cuadrícula de tres columnas con canales y una celda vacía

Necesitamos ajustar el margen de la última celda en la última fila cuando está sola debido a las columnas. Utilizamos el 33% más un canalón a cada lado.

@media (min-width: $screen-md-min) {
  $width: calc(33% - #{$col-gap});

  .grid__cell {
    ...
    // When there is only one item in the last rpw
    // Fill the margin so it's like the last item is
    // double the width
    // . . .
    // *->
    &:nth-of-type(3n-2):last-of-type {
      margin-right: calc(33% + #{$col-gap * 2});
    }
  }
}

¡Ahora nuestras canaletas están instaladas y la rejilla está completa! Llénalos de bordes, sombras o lo que tu corazón desee.

Una cuadrícula de tres por dos de rectángulos naranjas con la última celda vacía.Grilla completa de tres columnas con canaletas usando flexbox.

Terminando

Aquí está el resultado final una vez más:

ver la pluma
Diseño de columna similar a CSS-Grid compatible con IE10 por Brian Holt (@bholtbholt)
en CodePen.

Creo que esta técnica también podría admitir IE9 con ajustes menores, como usar bloques en línea en lugar de flexbox. También podríamos expandirnos a una cuadrícula de cuatro columnas agregando otro punto de interrupción y usando el mismo enfoque que la cuadrícula de tres columnas. ¡Siéntase libre de usar este enfoque y espero que ayude!