La diferencia entre unidades porcentuales y fr en el diseño de cuadrícula CSS

Estoy jugando con CSS Grid Layout y encontré una pregunta para la que no puedo encontrar una respuesta.

Considere el siguiente ejemplo:

:root { --grid-columns: 12; --column-gap: 10px; --row-gap: 10px; } .grid { display: grid; grid-template-columns: repeat(var(--grid-columns), calc(100% / var(--grid-columns))); grid-column-gap: var(--column-gap); grid-row-gap: var(--row-gap); justify-content: center; } [class*=l-] { border: 1px solid red; } .l-1 { grid-column-start: span 1; } .l-2 { grid-column-start: span 2; } .l-3 { grid-column-start: span 3; } .l-4 { grid-column-start: span 4; } .l-5 { grid-column-start: span 5; } .l-6 { grid-column-start: span 6; } .l-7 { grid-column-start: span 7; } .l-8 { grid-column-start: span 8; } .l-9 { grid-column-start: span 9; } .l-10 { grid-column-start: span 10; } .l-11 { grid-column-start: span 11; } .l-12 { grid-column-start: span 12; } 
 
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Column 9
Column 10
Column 11
Column 12

Como puede ver, las columnas salen del ancho de la pantalla debido al ancho de porcentaje establecido con calc(100% / var(--grid-columns)) .

Pero si uso unidades fr , funciona perfectamente:

 :root { --grid-columns: 12; --column-gap: 10px; --row-gap: 10px; } .grid { display: grid; grid-template-columns: repeat(var(--grid-columns), 1fr); grid-column-gap: var(--column-gap); grid-row-gap: var(--row-gap); justify-content: center; } [class*=l-] { border: 1px solid red; } .l-1 { grid-column-start: span 1; } .l-2 { grid-column-start: span 2; } .l-3 { grid-column-start: span 3; } .l-4 { grid-column-start: span 4; } .l-5 { grid-column-start: span 5; } .l-6 { grid-column-start: span 6; } .l-7 { grid-column-start: span 7; } .l-8 { grid-column-start: span 8; } .l-9 { grid-column-start: span 9; } .l-10 { grid-column-start: span 10; } .l-11 { grid-column-start: span 11; } .l-12 { grid-column-start: span 12; } 
 
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Column 9
Column 10
Column 11
Column 12

Los recursos utilizados para encontrar una respuesta:

  • https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns

  • https://css-tricks.com/snippets/css/complete-guide-grid/

  • https://www.w3.org/TR/css-grid-1/

Sería genial si alguien pudiera explicar por qué el porcentaje de ancho hace una gran diferencia.

fr

La unidad fr solo funciona con el espacio libre en el contenedor.

Entonces en tu código:

 grid-template-columns: repeat(12, 1fr); 

… el espacio libre en el contenedor se distribuye equitativamente entre 12 columnas.

Como las columnas solo tratan con espacio libre , grid-column-gap no es un factor. Se resta del ancho del contenedor antes de determinar la longitud del fr ( referencia de la especificación ).

Así es como el navegador hace el cálculo:

 (free space - gutters) / 12 = 1fr 

%

Cuando usas porcentajes …

 grid-template-columns: repeat(12, calc(100% / 12)); 

… el contenedor está dividido en 12 columnas, cada una con un ancho de 8.33333%. Esta es una longitud real, a diferencia de la unidad fr , que solo trata con el espacio libre.

Tanto las longitudes de columna como los espacios de cuadrícula se tienen en cuenta en el ancho.

Así es como el navegador hace el cálculo:

 8.33333% * 12 = 100% + 11 * 10px = 110px 

Hay un desbordamiento claro.

(Nota: grid-*-gap propiedades grid-*-gap aplican solo entre los elementos de la cuadrícula, nunca entre los elementos y el contenedor. Por eso, el número de huecos de malla es 11, no 13.)

Esto funciona:

 grid-template-columns: repeat(12, calc(8.3333% - 9.1667px)); 

Lo que se reduce a esto:

  • 12 columnas

  • el ancho de cada columna se determina tomando el ancho completo del contenedor ( 100% ) y dividiéndolo por 12

     100% / 12 = 8.3333% (individual column width) 
  • luego resta los huecos de la columna (hay 11)

      10px * 11 = 110px (total width of column gaps) 110px / 12 = 9.1667px (amount to be deducted from each column) 
 .grid { display: grid; grid-template-columns: repeat(12, calc(8.3333% - 9.1667px)); grid-column-gap: 10px; grid-row-gap: 10px; justify-content: center; } .l-1 { grid-column-start: span 1; } .l-2 { grid-column-start: span 2; } .l-3 { grid-column-start: span 3; } .l-4 { grid-column-start: span 4; } .l-5 { grid-column-start: span 5; } .l-6 { grid-column-start: span 6; } .l-7 { grid-column-start: span 7; } .l-8 { grid-column-start: span 8; } .l-9 { grid-column-start: span 9; } .l-10 { grid-column-start: span 10; } .l-11 { grid-column-start: span 11; } .l-12 { grid-column-start: span 12; } [class*=l-] { border: 1px solid red; } 
 
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Column 9
Column 10
Column 11
Column 12

De acuerdo con esta parte de la especificación, la unidad fr no tiene una longitud, por lo que se “calcula” DESPUÉS de determinar la cantidad de espacio libre disponible dentro del motor de diseño.

La variable que ha creado en su primer ejemplo forma parte de un cálculo (100% del ancho y se divide entre 12) por lo que ejecuta el cálculo ANTES de pasar al motor de diseño.

Cuando digo el motor de diseño, lo uso como una metáfora y no quiero confundir a las personas con el proceso de renderización que realiza el navegador. Solo estoy tratando de decir que en su primer ejemplo presenta una serie de números que se conectan al navegador para comenzar el proceso de representación y en su segundo ejemplo presenta más de un algoritmo / función que el navegador puede usar para hacer su diseño