web-dev-qa-db-fra.com

La différence entre le pourcentage et les unités fr dans la disposition de la grille CSS

Je joue avec CSS Grid Layout et suis tombé sur une question pour laquelle je ne trouve pas de réponse.

Prenons l'exemple suivant:

: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;
}
<div class="grid">
  <div class="l-6">Column 1</div>
  <div class="l-6">Column 2</div>
  <div class="l-3">Column 3</div>
  <div class="l-4">Column 4</div>
  <div class="l-3">Column 5</div>                   
  <div class="l-2">Column 6</div>
  <div class="l-1">Column 7</div>
  <div class="l-10">Column 8</div>
  <div class="l-1">Column 9</div>
  <div class="l-5">Column 10</div>
  <div class="l-5">Column 11</div>
  <div class="l-2">Column 12</div>
</div>

Comme vous pouvez le voir, les colonnes sortent de la largeur de l'écran en raison du pourcentage de largeur défini avec calc(100% / var(--grid-columns)).

Mais si j'utilise des unités fr, cela fonctionne parfaitement:

: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;
}
<div class="grid">
  <div class="l-6">Column 1</div>
  <div class="l-6">Column 2</div>
  <div class="l-3">Column 3</div>
  <div class="l-4">Column 4</div>
  <div class="l-3">Column 5</div>                   
  <div class="l-2">Column 6</div>
  <div class="l-1">Column 7</div>
  <div class="l-10">Column 8</div>
  <div class="l-1">Column 9</div>
  <div class="l-5">Column 10</div>
  <div class="l-5">Column 11</div>
  <div class="l-2">Column 12</div>
</div>

Les ressources utilisées pour trouver une réponse:

Ce serait génial si quelqu'un pouvait expliquer pourquoi les largeurs en pourcentage font une telle différence.

16
Morpheus

fr

L'unité fr fonctionne uniquement avec l'espace libre dans le conteneur.

Donc dans votre code:

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

... l'espace libre dans le conteneur est réparti également sur 12 colonnes.

Étant donné que les colonnes ne concernent que l'espace libre , grid-column-gap n'est pas un facteur. Il a été soustrait de la largeur du conteneur avant que la longueur fr ne soit déterminée ( référence de spécification ).

Voici comment le navigateur effectue le calcul:

(free space - gutters) / 12  = 1fr

%

Lorsque vous utilisez des pourcentages ...

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

... le conteneur est divisé en 12 colonnes, chacune ayant une largeur de 8,33333%. Il s'agit d'une longueur réelle, contrairement à l'unité fr, qui ne traite que de l'espace libre.

Les longueurs de colonne et les écarts de grille sont pris en compte dans la largeur.

Voici comment le navigateur effectue le calcul:

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

Il y a un débordement clair.

(Remarque: grid-*-gap les propriétés s'appliquent uniquement entre les éléments de la grille - jamais entre les éléments et le conteneur. C'est pourquoi le nombre de lacunes de grille est de 11, pas de 13.)

Cela marche:

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

Ce qui se résume à ceci:

  • 12 colonnes

  • la largeur de chaque colonne est déterminée en prenant la pleine largeur du conteneur (100%) et en le divisant par 12

    100% / 12 = 8.3333% (individual column width)
    
  • puis soustrayez les espaces des colonnes (il y en a 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; }
<div class="grid">
  <div class="l-6">Column 1</div>
  <div class="l-6">Column 2</div>
  <div class="l-3">Column 3</div>
  <div class="l-4">Column 4</div>
  <div class="l-3">Column 5</div>
  <div class="l-2">Column 6</div>
  <div class="l-1">Column 7</div>
  <div class="l-10">Column 8</div>
  <div class="l-1">Column 9</div>
  <div class="l-5">Column 10</div>
  <div class="l-5">Column 11</div>
  <div class="l-2">Column 12</div>
</div>
30
Michael_B

Selon cette partie de la spécification l'unité fr n'est pas une longueur, elle est donc "calculée" APRÈS avoir déterminé la quantité d'espace libre disponible dans le moteur de disposition.

La variable que vous avez créée dans votre premier exemple IS partie d'un calcul (100% de la largeur et en divisant par 12) donc il exécute le calcul AVANT de passer au moteur de disposition.

Quand je dis moteur de mise en page, je l'utilise comme métaphore et je ne veux pas confondre les gens avec le processus de rendu effectué par le navigateur. J'essaie simplement de dire que dans votre premier exemple, vous présentez une série de chiffres qui sont branchés sur le navigateur pour commencer le processus de rendu et dans votre deuxième exemple, vous présentez davantage d'algorithme/fonction que le navigateur peut utiliser pour créer sa disposition.

2
edswartz