web-dev-qa-db-fra.com

Faire en sorte que le conteneur de la grille remplisse des colonnes et non des lignes

Je veux que ma grille remplisse verticalement comme ceci:

1 4 7 
2 5 8
3 6 9
... arbitrary number of additional rows.

Au lieu de cela, il se remplit horizontalement comme ceci:

1 2 3
4 5 6
7 8 9

Je veux spécifier le nombre de colonnes dans ma grille, pas le nombre de lignes.

Voici à quoi ressemble ma div avec le style CSS intégré:

<div style="display:grid; grid-template-columns:1fr 1fr 1fr;">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
</div>

Il est important que ma grille ait 3 colonnes de largeur, mais je veux que les éléments soient renseignés par colonne et non par ligne. Est-ce possible dans CSS Grid? J'ai lu ceci https://css-tricks.com/snippets/css/complete-guide-grid/ mais je n'ai rien vu à propos de la commande.

CSS Flexbox a flex-direction, n’existe-t-il pas un attribut semblable à celui de CSS Grid?

16
Glen Pierce

Pour une grille à flux vertical qui crée de nouvelles colonnes si nécessaire et dont les lignes ne sont pas définies, envisagez d'utiliser CSS Présentation multicolonnes ( exemple ). CSS Grid Layout (au moins l’implémentation actuelle - Level 1 ) ne peut pas exécuter cette tâche. Voici le problème:

Dans CSS Grid Layout, il existe une relation inverse entre les propriétés grid-auto-flow et grid-template-rowsgrid-template-columns.

Plus précisément, avec grid-auto-flow: row (paramètre par défaut) et grid-template-columns tous les deux définis, les éléments de la grille se déroulent bien dans une direction horizontale, créant automatiquement de nouvelles lignes si nécessaire. Ce concept est illustré dans le code de la question.

Cependant, avec le passage à grid-template-rows, les éléments de la grille sont empilés dans une seule colonne.

Il n'y a pas de création automatique de colonnes avec grid-auto-flow: row et grid-template-rows. grid-template-columns doit être défini (d'où la relation inverse avec grid-auto-flow).

Le même comportement est vrai dans le scénario inverse.

Avec grid-auto-flow: column et grid-template-rows tous deux définis, les éléments de la grille se déplacent bien dans une direction verticale, créant automatiquement de nouvelles colonnes si nécessaire.

Cependant, avec le passage à grid-template-columns, les éléments de la grille sont empilés sur une seule ligne. (C'est le problème que la plupart des gens demandent, y compris dans cette question.)

Il n'y a pas de création automatique de lignes. Cela nécessite que grid-template-rows soit défini. (C’est la solution la plus souvent fournie, mais elle est généralement rejetée car les modèles comportent un nombre de lignes variable.)

Par conséquent, considérons une solution de mise en page _/multi-colonnes , comme suggéré ci-dessus.

Référence de spécification: 7.7. Positionnement automatique: la propriété grid-auto-flow

14
Michael_B

Une autre option consiste à supprimer la grille CSS et à utiliser les colonnes CSS, ce qui correspond exactement à ce que vous demandez et offre une meilleure prise en charge du navigateur.

.csscolumn {
  -webkit-column-count: 3;  /* Chrome, Safari, Opera */
  -moz-column-count: 3;     /* Firefox */
  column-count: 3;
}

/* styling for this demo */
.csscolumn {
  width: 50%;
}
.csscolumn + .csscolumn {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid;
}
<div class="csscolumn">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
</div>

<div class="csscolumn">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
</div>

<div class="csscolumn">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
  <div>10</div>
</div>

7
LGSon

Plus comme un exercice technique que comme une solution pratique, vous pouvez obtenir votre résultat en utilisant des styles spécifiques en fonction du nombre d'articles.

Voyons voir comment ça fonctionne:

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+3)

le premier sélecteur 

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6)

est actif est notre liste contient entre 4 et 6 éléments. Dans ce cas, certains éléments seront à la fois dans la première condition et dans la seconde.

Dans ce cas, nous voulons que 2 éléments soient dans la première colonne. cibler les éléments restants (à partir du troisième) avec 

~ .item:nth-child(n+3)

et les mettre sur la deuxième colonne. Une règle similaire, maintenant à partir du 5

~ .item:nth-child(n+5)

met les autres éléments dans la troisième colonne. Ces deux règles ont la même priorité et ciblent les deux derniers éléments. Il est donc essentiel qu’elles apparaissent dans cet ordre.

Nous devons répéter des règles similaires dans la limite du nombre d'éléments pouvant être présents (probablement un travail pour un pré-processeur) 

var elements = 5;

function add () {
    var ctn = document.getElementById("container");
    var ele = document.createElement("div");
    elements ++;
    ele.innerHTML = elements;
    ele.className = "item";
    ctn.appendChild (ele);
}
#container {
  width: 90%;
  border: solid 1px red;
  display: grid;
  grid-template-rows: 33% 33% 33%;
  grid-auto-flow: column dense;
}

.item {
  width: 90%;
  height: 80px;
  background-color: lightgreen;
  margin: 10px;
  grid-column: 1;
}

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+3) {
  background-color: yellow;
  grid-column: 2;
}

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+5) {
  background-color: tomato;
  grid-column: 3;
}

.item:first-child:nth-last-child(n+7):nth-last-child(-n + 9) ~ .item:nth-child(n+4) {
  background-color: burlywood;
  grid-column: 2;
}

.item:first-child:nth-last-child(n+7):nth-last-child(-n + 9) ~ .item:nth-child(n+7) {
  background-color: blueviolet;
  grid-column: 3;
}

.item:first-child:nth-last-child(n+10):nth-last-child(-n + 12) ~ .item:nth-child(n+5) {
  background-color: darkcyan;
  grid-column: 2;
}

.item:first-child:nth-last-child(n+10):nth-last-child(-n + 12) ~ .item:nth-child(n+9) {
  background-color: chartreuse;
  grid-column: 3;
}

.item:first-child:nth-last-child(n+13):nth-last-child(-n + 15) ~ .item:nth-child(n+6) {
  background-color: yellow;
  grid-column: 2;
}

.item:first-child:nth-last-child(n+13):nth-last-child(-n + 15) ~ .item:nth-child(n+11) {
  background-color: tomato;
  grid-column: 3;
}
<button onclick="add()">Add</button>
<div id="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>

4
vals

La méthode la plus simple que j'ai vue suit:

.grid {
	display: grid;
	grid-auto-flow: column;
	grid-gap: 1px;
	grid-template-columns: repeat(3, 1fr); 
	grid-template-rows: repeat(5, auto);    
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
</div>

2
RayYates

Voici une approche basée sur CSS Grid utilisant JavaScript et le CSSOM pour insérer une paire de:

transform: translate(x, y)

règles dans une feuille de style générée.

Les deux règles de transformation (il n'y a que seulement deux, selon que la grille est 3 colonnes de large déplacent les éléments inférieurs de la grille à une colonne d'origine, en déplaçant les éléments vers le haut et le droit.

Par conséquent, vous pouvez ajouter un nombre quelconque d’éléments à la grille à une colonne et le script ajustera toujours la grille afin qu’elle ait trois colonnes de taille plus ou moins égale.

Si les colonnes ne peuvent pas être de tailles exactement égales, la ou les colonnes les plus hautes seront toujours la première et/ou la deuxième colonne (jamais la troisième, la plus à droite). 

Exemple de travail (9 unités de grille):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));
var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.Push(shortColumn);
    }

    else {

        columns.Push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>


Exemple de travail (10 unités de grille):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.Push(shortColumn);
    }

    else {

        columns.Push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
</div>


Exemple de travail (11 unités de grille):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.Push(shortColumn);
    }

    else {

        columns.Push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</div>

Exemple de travail (14 unités de grille):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.Push(shortColumn);
    }

    else {

        columns.Push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
</div>

0
Rounin