web-dev-qa-db-fra.com

Maçonnerie CSS uniquement

Je dois mettre en place une structure de maçonnerie assez délabrée. Cependant, pour un certain nombre de raisons, je ne souhaite pas utiliser JavaScript pour le faire.

A grid of multiple columns of rectangles of varying height.

Paramètres:

  • Tous les éléments ont la même largeur
  • Les éléments ont une hauteur qui ne peut pas être calculée côté serveur (une image plus diverses quantités de texte)
  • Je peux vivre avec un nombre fixe de colonnes si je dois

il existe une solution triviale à cela qui fonctionne dans les navigateurs modernes, le column-count propriété.

Le problème avec cette solution est que les éléments sont classés en colonnes:

Starting from the top leftmost box, they're numbered 1 through 4 straight down, the topmost box in the next column is 5, and so on.

Bien que j'ai besoin que les éléments soient classés en lignes, au moins approximativement:

Starting from the top leftmost box, they're numbered 1 through 6 straight across, but because box 5 is the shortest the box underneath it is 7 as it has the appearance of being on a row higher than the next box on the far left.

Les approches que j'ai essayées ne fonctionnent pas:

Maintenant, je pourrais modifier le rendu côté serveur et réorganiser les éléments en divisant le nombre d'éléments par le nombre de colonnes, mais c'est compliqué, source d'erreurs comment les navigateurs décident de scinder la liste d’éléments en colonnes), je voudrais donc l’éviter si possible.

Existe-t-il une magie newfangled flexbox) qui rend cela possible?

92
Pekka 웃

Flexbox

Une maçonnerie dynamique n’est pas possible avec flexbox, du moins pas de manière propre et efficace.

Flexbox est un système de mise en page unidimensionnel. Cela signifie qu'il peut aligner des éléments sur des lignes horizontales OR). Un élément flexible est limité à sa ligne ou à sa colonne.

Un véritable système de grille est bidimensionnel, ce qui signifie qu'il peut aligner des éléments le long de lignes horizontales ET verticales. Les éléments de contenu peuvent s'étendre simultanément sur des lignes et des colonnes, ce que les éléments flexibles ne peuvent pas faire.

C’est pourquoi flexbox a une capacité limitée de construction de grilles. C’est également une raison pour laquelle le W3C a développé une autre technologie CSS3, Grid Layout .


row wrap

Dans un conteneur flex avec flex-flow: row wrap, Les éléments flex doivent être renvoyés à une nouvelle lignes.

Cela signifie que un élément flexible ne peut pas être placé sous un autre élément de la même ligne.

Remarquez ci-dessus comment div # 3 retourne ci-dessous div # 1, en créant une nouvelle ligne. Il ne peut pas envelopper sous div # 2.

Par conséquent, lorsque les éléments ne sont pas les plus hauts de la rangée, il reste un espace blanc, créant des espaces disgracieux.


column wrap

Si vous passez à flex-flow: column wrap, Une mise en page semblable à une grille est plus accessible. Cependant, un conteneur dans la direction des colonnes présente quatre problèmes potentiels dès le départ:

  1. Les éléments Flex s’écoulent verticalement et non horizontalement (comme vous en avez besoin dans ce cas).
  2. Le conteneur se dilate horizontalement et non verticalement (comme dans la disposition Pinterest).
  3. Le conteneur doit avoir une hauteur fixe pour que les articles sachent où envelopper.
  4. Au moment de la rédaction de cet article, les principaux navigateurs principaux présentaient une carence dans laquelle le conteneur ne se développe pas pour accueillir des colonnes supplémentaires .

Par conséquent, un conteneur dans la direction des colonnes n'est pas une option dans ce cas, et dans de nombreux autres cas.


CSS Grid avec les dimensions de l'élément indéfinies

La disposition de la grille serait une solution parfaite à votre problème si les différentes hauteurs des éléments de contenu pouvaient être prédéterminées. Toutes les autres exigences sont bien dans les capacités de Grid.

La largeur et la hauteur des éléments de la grille doivent être connues afin de combler les écarts avec les éléments environnants.

Donc, Grid, qui est le meilleur CSS à offrir pour la construction d’une structure en maçonnerie coulant horizontalement, manque dans ce cas.

En fait, tant qu’une technologie CSS n’est pas en mesure de combler automatiquement les lacunes, CSS n’a généralement pas de solution. Quelque chose comme cela nécessiterait probablement de refondre le document, donc je ne suis pas sûr de son utilité ou de son efficacité.

Vous aurez besoin d'un script.

Les solutions JavaScript ont tendance à utiliser un positionnement absolu, qui supprime les éléments de contenu du flux de documents afin de les réorganiser sans lacunes. Voici deux exemples:


CSS Grid avec les dimensions de l'élément définies

Pour les dispositions où la largeur et la hauteur des éléments de contenu sont connues, voici une disposition de maçonnerie coulant horizontalement en CSS pur:

grid-container {
  display: grid;                                                /* 1 */
  grid-auto-rows: 50px;                                         /* 2 */
  grid-gap: 10px;                                               /* 3 */
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));   /* 4 */
}

[short] {
  grid-row: span 1;                                             /* 5 */
  background-color: green;
}

[tall] {
  grid-row: span 2;
  background-color: crimson;
}

[taller] {
  grid-row: span 3;
  background-color: blue;
}

[tallest] {
  grid-row: span 4;
  background-color: gray;
}

grid-item {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3em;
  font-weight: bold;
  color: white;
}
<grid-container>
  <grid-item short>01</grid-item>
  <grid-item short>02</grid-item>
  <grid-item tall>03</grid-item>
  <grid-item tall>04</grid-item>
  <grid-item short>05</grid-item>
  <grid-item taller>06</grid-item>
  <grid-item short>07</grid-item>
  <grid-item tallest>08</grid-item>
  <grid-item tall>09</grid-item>
  <grid-item short>10</grid-item>
  <grid-item tallest>etc.</grid-item>
  <grid-item tall></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
</grid-container>

démonstration de jsFiddle


Comment ça marche

  1. Établir un conteneur de grille au niveau du bloc. (inline-grid Serait l'autre option)
  2. La propriété grid-auto-rows définit la hauteur des lignes générées automatiquement. Dans cette grille, chaque rangée mesure 50 pixels de haut.
  3. La propriété grid-gap est un raccourci pour grid-column-gap Et grid-row-gap . Cette règle définit un écart de 10 pixels entre éléments de grille. (Cela ne s'applique pas à la zone située entre les articles et le conteneur.)
  4. La propriété grid-template-columns définit la largeur des colonnes explicitement définies.

    La notation repeat définit un modèle de répétition de colonnes (ou de lignes).

    La fonction auto-fill indique à la grille d'aligner autant de colonnes (ou de lignes) que possible sans déborder. le conteneur. (Cela peut créer un comportement similaire à celui de flex-wrap: wrap De la mise en page.)

    La fonction minmax() définit une plage de tailles minimale et maximale pour chaque colonne (ou ligne). Dans le code ci-dessus, la largeur de chaque colonne sera au minimum de 30% du conteneur et au maximum de l’espace libre disponible.

    L'unité fr représente une fraction de l'espace libre dans le conteneur de la grille. C'est comparable à la propriété flex-grow De flexbox.

  5. Avec grid-row et span nous indiquons aux éléments de la grille le nombre de lignes qu’ils doivent couvrir.


Prise en charge du navigateur pour la grille CSS

  • Chrome - Prise en charge complète à compter du 8 mars 2017 (version 57)
  • Firefox - Prise en charge complète à compter du 6 mars 2017 (version 52)
  • Safari - prise en charge complète à compter du 26 mars 2017 (version 10.1)
  • Edge - prise en charge complète à compter du 16 octobre 2017 (version 16)
  • IE11 - pas de support pour les spécifications actuelles; supporte la version obsolète

Voici l'image complète: http://caniuse.com/#search=grid


Fonction de superposition de grille dans Firefox

Dans les outils de développement de Firefox, lorsque vous inspectez le conteneur de grille, la déclaration CSS contient une petite icône de grille. Au clic, il affiche un aperçu de votre grille sur la page.

Plus de détails ici: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

128
Michael_B

C'est une technique récemment découverte faisant appel à flexbox: https://tobiasahlin.com/blog/masonry-with-css/ .

L'article a du sens pour moi, mais je n'ai pas essayé de l'utiliser, donc je ne sais pas s'il existe des avertissements, autres que ceux mentionnés dans la réponse de Michael.

Voici un exemple tiré de l'article, utilisant la propriété order, associée à :nth-child.

Extrait de pile

.container {
  display: flex;
  flex-flow: column wrap;
  align-content: space-between;
  /* Your container needs a fixed height, and it 
   * needs to be taller than your tallest column. */
  height: 960px;
  
  /* Optional */
  background-color: #f7f7f7;
  border-radius: 3px;
  padding: 20px;
  width: 60%;
  margin: 40px auto;
  counter-reset: items;
}

.item {
  width: 24%;
  /* Optional */
  position: relative;
  margin-bottom: 2%;
  border-radius: 3px;
  background-color: #a1cbfa;
  border: 1px solid #4290e2;
  box-shadow: 0 2px 2px rgba(0,90,250,0.05),
    0 4px 4px rgba(0,90,250,0.05),
    0 8px 8px rgba(0,90,250,0.05),
    0 16px 16px rgba(0,90,250,0.05);
  color: #fff;
  padding: 15px;
  box-sizing: border-box;
}

 /* Just to print out numbers */
div.item::before {
  counter-increment: items;
  content: counter(items);
}

/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n)   { order: 4; }

/* Force new columns */
.break {
  flex-basis: 100%;
  width: 0;
  border: 1px solid #ddd;
  margin: 0;
  content: "";
  padding: 0;
}

body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  
  <span class="item break"></span>
  <span class="item break"></span>
  <span class="item break"></span>
</div>
3
Oliver Joseph Ash