web-dev-qa-db-fra.com

Grille 3 colonnes (de haut en bas) en utilisant la grille CSS

Ok, voici la situation, disons que j'ai une liste avec un nombre inconnu d'éléments, cela pourrait être 10 ou 100, et je veux les afficher en 3 colonnes allant du haut vers le bas et non de gauche à droite.

À l'heure actuelle, je peux y parvenir en utilisant columns: 3; et column-gap: 10px; C'est très bien et tout.

Ma question est la suivante: comment obtenir les mêmes résultats en utilisant display: grid; sans connaître le nombre d'éléments?

Je sais que vous pouvez y parvenir avec CSS Grid si vous avez un nombre fixe d'éléments, mais est-ce possible avec des éléments dynamiques? sans utiliser JS bien sûr.

ul {
  list-style: none;
  columns: 3;
  column-gap: 10px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>21</li>
  <li>22</li>
</ul>

10
Ruby

Je ne pense pas que cela soit possible sans connaître auparavant le nombre d'éléments que vous souhaitez afficher. Pour votre cas, vous pouvez le faire:

ul {
   display: grid;
   grid-auto-flow: column;
   grid-template-rows: repeat(8, 1fr);
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>21</li>
  <li>22</li>
</ul>

Mais le nombre de lignes doit être défini auparavant.

5
Ander

En théorie, vous pouvez obtenir ce résultat avec CSS Grid en utilisant "Quantité de requêtes" basé sur les sélecteurs :nth-*, comme ceci:

ul {
  list-style: none;
  display: grid;
  grid-auto-flow: row dense;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
}

/* by default, items go in first column */
li { grid-column: 1; }

/* if there are 1 to 3 items, the 2nd one goes to 2nd column and the 3rd one goes to 3rd column */
li:first-child:nth-last-child(n + 1):nth-last-child(-n + 3) ~ li:nth-child(n + 2):nth-child(-n + 2) { grid-column: 2; }
li:first-child:nth-last-child(n + 1):nth-last-child(-n + 3) ~ li:nth-child(n + 3) { grid-column: 3; }

/* ... */

/* if there are 19 to 21 items, items 8-14 to 2nd column and items 15+ to 3rd one */
li:first-child:nth-last-child(n + 19):nth-last-child(-n + 21) ~ li:nth-child(n + 8):nth-child(-n + 14) { grid-column: 2; }
li:first-child:nth-last-child(n + 19):nth-last-child(-n + 21) ~ li:nth-child(n + 15) { grid-column: 3; }

/* if there are 22 to 24 items, items 9-16 to 2nd column and items 17+ to 3rd one */
li:first-child:nth-last-child(n + 22):nth-last-child(-n + 24) ~ li:nth-child(n + 9):nth-child(-n + 16) { grid-column: 2; }
li:first-child:nth-last-child(n + 22):nth-last-child(-n + 24) ~ li:nth-child(n + 17) { grid-column: 3; }

/* if there are 25 to 27 items, items 10-18 to 2nd column and items 19+ to 3rd one */
li:first-child:nth-last-child(n + 25):nth-last-child(-n + 27) ~ li:nth-child(n + 10):nth-child(-n + 18) { grid-column: 2; }
li:first-child:nth-last-child(n + 25):nth-last-child(-n + 27) ~ li:nth-child(n + 19) { grid-column: 3; }

/* and so on */
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>21</li>
  <li>22</li>
</ul>

Cependant, cette approche n'est pas pratique. À mon avis, la disposition multi-colonnes CSS est la meilleure solution ici que CSS Grid.

1
Ilya Streltsyn

J'ai une liste avec un nombre inconnu d'éléments, cela pourrait être 10 ou 100

Comme vous l'avez déjà observé, Présentation multicolonnes CSS génère la disposition souhaitée avec du CSS pur - sans avoir à connaître à l'avance le nombre d'éléments contenus dans le conteneur.

Ce n'est pas le cas avec les grilles CSS - vous devez connaître à l'avance le nombre d'éléments dans la grille pour calculer le nombre de lignes nécessaires - ce qui est une limitation.

Donc, je vous suggérerais coller avec la disposition sur plusieurs colonnes pour votre disposition.


En supposant que la limitation ci-dessus soit ok, vous pouvez créer la mise en page avec css comme suit:

(Remarque: @Ander a déjà répondu à cette question, mais voici une petite explication.)

1) Sur le conteneur de grille, changez la propriété grid-auto-flow en column - Ceci affiche les éléments de la grille verticalement et non horizontalement (valeur par défaut). 

2) Une fois que vous connaissez le nombre d'éléments, vous pouvez calculer le nombre de lignes nécessaire pour créer une grille équilibrée comme suit:

#rows =  ceil( #items / #columns )

Donc, pour 22 éléments - le nombre de lignes = ceil (22/3) = 8

ul {
   display: grid;
   grid-auto-flow: column; /* 1 */
   grid-template-rows: repeat(8, 1fr);  /* 2 */
}

Nous pouvons légèrement améliorer cette solution avec SASS - pour produire une solution plus générique calculant le nombre de lignes. (SASS a une fonction ceil)

ul {
  list-style: none;
  padding: 0;
  display:grid;
  $num-items: 22;
  $num-cols: 3;
  $num-rows: ceil($num-items / $num-cols);
  grid-template-columns: repeat($num-cols, 1fr);
  grid-template-rows: repeat($num-rows, 1fr);
  grid-auto-flow: column;
  border: 5px solid gold;
}

Démo Codepen


FWIW: Voici une solution alternative qui utilise les sélecteurs nth-child sans avoir à modifier la propriété grid-auto-flow. Malheureusement, il a la même limitation que les éléments doivent être connus à l’avance.

li:nth-child(-n + 24) {
  grid-column: 3;
}

li:nth-child(-n + 16) {
  grid-column: 2;
}

li:nth-child(-n + 8) {
  grid-column: 1;
}

SASS Codepen

1
Danield