Meilleure façon de définir la distance entre les éléments de la boîte flexible

781

Pour définir la distance minimale entre les éléments flexbox que j'utilise margin: 0 5pxsur .itemet margin: 0 -5pxsur le conteneur. Pour moi, cela ressemble à un hack, mais je ne peux pas trouver de meilleure façon de le faire.

Exemple

#box {
  display: flex;
  width: 100px;
  margin: 0 -5px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  margin: 0 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Sasha Koss
la source
29
Ce n'est pas un hack - c'est l'une des méthodes prévues pour aligner les éléments. Il existe cependant d'autres propriétés. Voir w3.org/TR/css3-flexbox/#alignment
BoltClock
4
Ouais, je comprends. Mais par exemple, il existe une propriété de colonne-espace qui nous donne la possibilité de contrôler la distance du conteneur: w3.org/TR/css3-multicol/#column-gap
Sasha Koss
Parce que c'est un effondrement des marges de la flexbox. L'autre question a le droit de [Comment puis-je empêcher l'effondrement de la dernière marge dans la flexbox? ] ( stackoverflow.com/questions/38993170/… )
Jack Yang
6
Le module CSS d'alignement des boîtes de niveau 3 comprend une section sur les espaces entre les boîtes - qui s'applique aux éléments à plusieurs colonnes, aux conteneurs flexibles et aux conteneurs de grille. Donc, finalement, cela sera simple: row-gap: 5px- fait.
Danield
2
@JohnCarrell firefox prend déjà en charge la gappropriété sur les conteneurs flexibles ( caniuse )
Danield

Réponses:

428
  • Flexbox n'a pas de marges réductibles.
  • Flexbox n'a rien de semblable aux border-spacingtableaux (à l'exception de la propriété CSS gapqui n'est pas bien prise en charge dans la plupart des navigateurs, caniuse )

Par conséquent, réaliser ce que vous demandez est un peu plus difficile.

D'après mon expérience, la manière la plus "propre" qui n'utilise pas :first-child/ :last-childet fonctionne sans aucune modification flex-wrap:wrapest de mettre padding:5pxsur le conteneur et margin:5pxsur les enfants. Cela produira un 10pxécart entre chaque enfant et entre chaque enfant et ses parents.

Démo

.upper
{
  margin:30px;
  display:flex;
  flex-direction:row;
  width:300px;
  height:80px;
  border:1px red solid;

  padding:5px; /* this */
}

.upper > div
{
  flex:1 1 auto;
  border:1px red solid;
  text-align:center;

  margin:5px;  /* and that, will result in a 10px gap */
}

.upper.mc /* multicol test */
{flex-direction:column;flex-wrap:wrap;width:200px;height:200px;}
<div class="upper">
  <div>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa<br/>aaa</div>
  <div>aaa<br/>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa</div>
</div>

<div class="upper mc">
  <div>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa<br/>aaa</div>
  <div>aaa<br/>aaa<br/>aaa</div>
  <div>aaa</div>
  <div>aaa</div>
</div>

Tous les travailleurs sont essentiels
la source
220
Cela n'accomplit pas la même chose que la question demande, vous aurez un retrait de 10px à l'extrême gauche et à droite, ce que je suppose qu'ils n'ont pas l'intention d'avoir. D'où les marges négatives dans la question d'origine.
Chris Nicola
17
Et si la orderpropriété était définie? :first-child/:last-childne fonctionnera pas comme prévu.
Guria
4
"Flexbox n'a pas de marges qui s'effondrent." Très perspicace et apparemment vrai, mais puis-je demander une citation?
chharvey
2
N'est-ce pas une réponse pire que la question d'origine? Cette méthode nécessite que vous ayez de l'espace autour du conteneur et la gouttière doit toujours être un nombre pair.
limitlessloop
7
@chharvey, de la spécification w3.org/TR/css-flexbox-1/#item-margins , "Les marges des éléments flexibles adjacents ne s'effondrent pas."
romellem
197

Ce n'est pas un hack. La même technique est également utilisée par le bootstrap et sa grille, bien qu'au lieu de la marge, le bootstrap utilise un remplissage pour ses colonnes.

.row {
  margin:0 -15px;
}
.col-xx-xx {
  padding:0 15px;
}
Roumelis George
la source
1
Le seul problème avec cette méthode est le maintien d'éléments de hauteur égale avec des couleurs d'arrière-plan. Le positionnement absolu avec height:100%; width:100%ignore le rembourrage de l'élément.
Steven Vachon
3
Le problème ici est avec IE10 et 11. les flex-basisvaleurs ne tiennent pas compte box-sizing: border-box, donc un enfant avec un remplissage ou une bordure va déborder le parent (ou envelopper dans ce cas). Source
Carson
18
Il y a un autre problème avec cette approche: ajuster la marge comme ceci peut augmenter la largeur de la page. Démo: jsfiddle.net/a97tatf6/1
Nathan Osman
4
Bien que je convienne que ce n'est pas un hack, le fait que quelque chose soit largement utilisé ne signifie pas qu'il ne s'agit pas d'un hack. Voir polyfills, correctifs de sécurité temporaires, édition hexadécimale, etc.
William
15
Bien sûr, c'est un hack. Parce que Bootstrap utilise cette méthode ne signifie pas que ce n'est pas un hack. Cela signifie simplement que Bootstrap utilise un hack.
Michael Benjamin
108

Flexbox et css calc avec prise en charge de plusieurs lignes

Bonjour, voici ma solution de travail pour tous les navigateurs prenant en charge flexbox. Pas de marges négatives.

Démo de violon

   
.flexbox {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
}

.flexbox > div {
  /*
    1/3  - 3 columns per row
    10px - spacing between columns 
  */
  box-sizing: border-box;
  margin: 10px 10px 0 0;
  outline: 1px dotted red;
  width: calc(1/3*100% - (1 - 1/3)*10px);
}

/*
  align last row columns to the left
  3n - 3 columns per row
*/
.flexbox > div:nth-child(3n) {
  margin-right: 0;
}

.flexbox::after {
  content: '';
  flex: auto;
}

/*
  remove top margin from first row
  -n+3 - 3 columns per row 
*/
.flexbox > div:nth-child(-n+3) {
  margin-top: 0;
}
<div class="flexbox">
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
</div>

Notez que ce code peut être plus court en utilisant SASS

Mise à jour 2020.II.11 Colonnes alignées sur la dernière ligne à gauche

Update 2020.II.14 Suppression de la marge en bas de la dernière ligne

Dariusz Sikorski
la source
13
J'aime cette solution mais elle échoue s'il n'y a que 2 éléments dans la dernière ligne. Les articles ne sont pas empilés en raison du justify-content.
James Brantly
4
pour résoudre le problème des deux éléments, remplacez simplement par justify-content: space-evenly;ou justify-content: space-around;.
Paul Rooney
6
@PaulRooney Sur un site avec plusieurs listes, vous ne connaissez pas toujours le nombre d'éléments, si les listes sont générées par un CMS.
NinjaFart
1
@ 1.21gigawatts Veuillez ne pas apporter de modifications arbitraires au code / réponse de quelqu'un d'autre; écrivez plutôt votre propre réponse.
TylerH
2
@TylerH Ce n'était pas arbitraire. La question demandait comment, "... pour définir la distance entre les éléments de la boîte flexible". Cette réponse ne montre pas la taille de la gouttière. La définition d'une couleur d'arrière-plan montre la gouttière. L'ajout d'une bordure montre qu'il y a une marge sous la dernière ligne.
1,21 gigawatts le
93

Vous pouvez utiliser des bordures transparentes.

J'ai envisagé ce problème en essayant de créer un modèle de grille flexible qui peut se replier sur un modèle tableaux + cellules de tableau pour les navigateurs plus anciens. Et les bordures pour gouttières m'ont semblé être le meilleur choix approprié. c'est-à-dire que les cellules du tableau n'ont pas de marges.

par exemple

.column{
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 10px solid transparent;
}

Notez également que vous avez besoin min-width: 50px;de Flexbox. Le modèle flex ne prendra pas en charge les tailles fixes, sauf si vous le faites flex: none;sur l'élément enfant particulier que vous souhaitez fixe et donc exclu de l'être "flexi". http://jsfiddle.net/GLpUp/4/ Mais toutes les colonnes avec flex:none;n'est plus un modèle flexible. Voici quelque chose de plus proche d'un modèle flex: http://jsfiddle.net/GLpUp/5/

Vous pouvez donc utiliser les marges normalement si vous n'avez pas besoin du repli de cellule de tableau pour les anciens navigateurs. http://jsfiddle.net/GLpUp/3/

Le réglage background-clip: padding-box;sera nécessaire lors de l'utilisation d'un arrière-plan, sinon le fond coulera dans la zone de bordure transparente.

hexalys
la source
5
très bonne réponse. les marges sont utilisées différemment dans les flexbox (comme pour absorber de l'espace supplémentaire), donc les bordures transparentes offrent une excellente solution aux éléments uniformément espacés qui peuvent s'enrouler avec un comportement de type marge
Eolis
4
sauf lorsque vous utilisez la couleur d'arrière-plan, votre arrière-plan dépasse les limites souhaitées.
ahnbizcad
2
@ahnbizcad Eh bien avec différentes couleurs d'arrière-plan, vous pouvez utiliser du blanc ou la couleur adéquate selon la direction de l'arrière-plan.
hexalys
27
@ahnbizcad: Si vous n'avez pas besoin du support IE8, c'est une meilleure solution:background-clip: padding-box
Albin
5
Le commentaire d'Albin ici a besoin de plus de votes! C'est la meilleure solution. Des bordures transparentes, en combinaison avec un clip d'arrière-plan: une boîte de rembourrage (et des marges négatives sur le conteneur, si nécessaire, pour un alignement correct des bords) est une solution parfaite. IE8 ne prend pas en charge la flexbox de toute façon, donc son manque de prise en charge de l'arrière-plan ne devrait pas avoir d'importance.
Brian
74

Cette solution fonctionnera pour tous les cas, même s'il y a plusieurs lignes ou un certain nombre d'éléments. Mais le compte de la section doit être le même que vous voulez 4 dans la première ligne et 3 dans la deuxième ligne, cela ne fonctionnera pas de cette façon, l'espace pour le 4e contenu sera vide, le conteneur ne remplira pas.

Nous utilisons display: grid; et ses propriétés.

#box {
  display: grid;
  width: 100px;
  grid-gap: 5px;
  /* Space between items */
  grid-template-columns: 1fr 1fr 1fr 1fr;
  /* Decide the number of columns and size */
}

.item {
  background: gray;
  width: 100%;
  /* width is not necessary only added this to understand that width works as 100% to the grid template allocated space **DEFAULT WIDTH WILL BE 100%** */
  height: 50px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

L'inconvénient de cette méthode est dans Mobile Opera Mini ne sera pas pris en charge et dans PC, cela ne fonctionne qu'après IE10 .

Remarque pour une compatibilité complète du navigateur, y compris IE11, veuillez utiliser le préfixe automatique


RÉPONSE ANCIENNE

Ne pensez pas que c'est une ancienne solution, c'est toujours l'une des meilleures si vous ne voulez qu'une seule ligne d'éléments et cela fonctionnera avec tous les navigateurs.

Cette méthode est utilisée par la combinaison de frères et sœurs CSS , vous pouvez donc la manipuler de nombreuses autres manières également, mais si votre combinaison est incorrecte, cela peut également causer des problèmes.

.item+.item{
  margin-left: 5px;
}

Le code ci-dessous fera l'affaire. Dans cette méthode, il n'est pas nécessaire de donner margin: 0 -5px;au #boxwrapper.

Un échantillon de travail pour vous:

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 22px;
  height: 50px;
}
.item+.item{
 margin-left: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

weBBer
la source
J'ai modifié votre réponse basée sur la grille pour démontrer qu'elle fonctionne correctement, même si la dernière ligne contient moins d'éléments. Pour prouver que cela fonctionne dans ce cas. (N'hésitez pas à revenir si vous n'aimez pas ce changement.)
ToolmakerSteve
Selon cette question, ils ont seulement demandé de remplir correctement l'espace avec les éléments enfants sans pirater, ce que j'ai fait, en utilisant la grille, nous pouvons gérer selon la grid-template-columnsdéfinition que nous ne définissons pas dynamiquement. Donc, si vous donnez la valeur à 1fr 1fr 1fr 1fralors il divisera le div en 4fractionset essaiera de remplir les éléments enfants dans chacun fractions, à ma connaissance c'est le seul moyen grid. Ce que j'ai déclaré dans la réponse, c'est que si l'utilisateur a besoin de diviser le div en 4 et de les utiliser avec de nombreux éléments, même pour plusieurs lignes, le gidsera utile.
weBBer
69

Vous pouvez utiliser & > * + *comme sélecteur pour émuler un flex-gap(pour une seule ligne):

#box { display: flex; width: 230px; outline: 1px solid blue; }
.item { background: gray; width: 50px; height: 100px; }

/* ----- Flexbox gap: ----- */

#box > * + * {
  margin-left: 10px;
}
<div id='box'>
    <div class='item'></div>
    <div class='item'></div>
    <div class='item'></div>
    <div class='item'></div>
</div>

Si vous devez prendre en charge le flex wrapping , vous pouvez utiliser un élément wrapper:

.flex { display: flex; flex-wrap: wrap;  }
.box { background: gray; height: 100px; min-width: 100px; flex: auto; }
.flex-wrapper {outline: 1px solid red; }

/* ----- Flex gap 10px: ----- */

.flex > * {
  margin: 5px;
}
.flex {
  margin: -5px;
}
.flex-wrapper {
  width: 400px; /* optional */
  overflow: hidden; /* optional */
}
<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
  </div>
</div>

Faire Async
la source
3
Solution propre. Fonctionne pour n'importe quel nombre d'éléments enfants flexibles.
Konrad Gałęzowski
1
C'est ce que je cherchais et a très bien fonctionné pour moi 👍
Paul Odeon
Un point à noter cependant est que l' *opérateur n'augmente pas la spécificité comme vous pouvez vous y attendre. Ainsi, selon votre CSS existant, vous devrez peut-être augmenter la spécificité du .flex > *sélecteur ou ajouter !importantà la règle s'il existe d'autres sélecteurs appliquant une marge à cet élément.
Paul Odeon
Meilleure solution 👍
o01
26

Disons que si vous souhaitez définir un 10pxespace entre les éléments, vous pouvez simplement définir .item {margin-right:10px;}pour tous et le réinitialiser sur le dernier.item:last-child {margin-right:0;}

Vous pouvez également utiliser le frère général ~ou le +sélecteur de frère suivant pour définir la marge gauche sur les éléments à l'exclusion du premier .item ~ .item {margin-left:10px;}ou utiliser.item:not(:last-child) {margin-right: 10px;}

Flexbox est si intelligent qu'il recalcule automatiquement et distribue également la grille.

body {
  margin: 0;
}

.container {
  display: flex;
}

.item {
  flex: 1;
  background: gray;
  height: 50px;
}

.item:not(:last-child) {
  margin-right: 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Si vous souhaitez autoriser le bouclage flexible , consultez l'exemple suivant.

body {
  margin: 0;
}

.container {
  display: flex;
  flex-wrap: wrap;
  margin-left: -10px;
}

.item {
  flex: 0 0 calc(50% - 10px);
  background: gray;
  height: 50px;
  margin: 0 0 10px 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Autocollants
la source
6
Cela ne fonctionnerait pas si les éléments sont enveloppés, car :last-childcela n'affecte pas chaque dernier enfant à la fin d'une ligne, n'est-ce pas?
Flimm
2
@Flimm J'ai ajouté une approche pour travailler avec le film flexible, voir la deuxième partie ci-dessus.
Autocollants
La meilleure réponse pour moi ... simple, propre, efficace! Fonctionne parfaitement avec flex wrap, merci
Matthieu Marcé
16

J'ai trouvé une solution basée sur le sélecteur général de frères et sœurs, ~ et permettant une imbrication infinie.

Voir ce stylo code pour un exemple de travail

Fondamentalement, à l'intérieur des conteneurs de colonnes, chaque enfant précédé d'un autre enfant obtient une marge supérieure. De même, à l'intérieur de chaque conteneur de lignes, chaque enfant précédé d'un autre obtient une marge gauche.

.box {
  display: flex;
  flex-grow: 1;
  flex-shrink: 1;
}

.box.columns {
  flex-direction: row;
}

.box.columns>.box~.box {
  margin-left: 5px;
}

.box.rows {
  flex-direction: column;
}

.box.rows>.box~.box {
  margin-top: 5px;
}
<div class="box columns">
  <div class="box" style="background-color: red;"></div>
  <div class="box rows">
    <div class="box rows">
      <div class="box" style="background-color: blue;"></div>
      <div class="box" style="background-color: orange;"></div>
      <div class="box columns">
        <div class="box" style="background-color: yellow;"></div>
        <div class="box" style="background-color: pink;"></div>
      </div>
    </div>
    <div class="box" style="background-color: green;"></div>
  </div>
</div>

Simon Epskamp
la source
Il en résulte des éléments de tailles différentes car les marges ne sont pas appliquées globalement.
Steven Vachon
Vous devrez également ajouter du CSS supplémentaire pour gérer les écrans plus petits car cela semble un peu bizarre sur mobile, j'appliquerais la règle .box ~ .box aux écrans plus grands et pour les écrans plus petits, définissez la classe .box pour avoir une largeur maximale de 100% et une marge inférieure.
rhysclay
14

En passant de la réponse de sawa, voici une version légèrement améliorée qui vous permet de définir un espacement fixe entre les éléments sans la marge environnante.

http://jsfiddle.net/chris00/s52wmgtq/49/

La version Safari "-webkit-flex" est également incluse.

.outer1 {
    background-color: orange;
    padding: 10px;
}

.outer0 {
    background-color: green;
    overflow: hidden;
}

.container
{
    display: flex;
    display: -webkit-flex;
    flex-wrap: wrap;    
    -webkit-flex-wrap: wrap;
    background-color: rgba(0, 0, 255, 0.5);
    margin-left: -10px;
    margin-top: -10px;
}

.item
{
    flex-grow: 1;
    -webkit-flex-grow: 1;
    background-color: rgba(255, 0, 0, 0.5);
    width: 100px;
    padding: 10px;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    color: white;
}

<div class="outer1">
    <div class="outer0">
        <div class="container">
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
        </div>
    </div>
</div>
chris
la source
2
N'est-ce pas essentiellement le même que l'exemple donné dans la question?
ford
10

Selon #ChromDevSummit, il existe une implémentation de la gappropriété pour Flexbox, bien qu'à l'heure actuelle (14 novembre 2019), elle ne soit prise en charge que dans Firefox mais devrait être implémentée dans Chrome bientôt:

entrez la description de l'image ici

Démo en direct

Je mettrai également à jour ma réponse une fois qu'elle arrivera sur Chrome.

Eliya Cohen
la source
9

Je l'ai utilisé pour les colonnes enveloppées et à largeur fixe. La clé ici estcalc()

Échantillon SCSS

$gap: 10px;

dl {
  display: flex;
  flex-wrap: wrap;
  padding: $gap/2;

  dt, dd {
    margin: $gap/2;}

  dt { // full width, acts as header
    flex: 0 0 calc(100% - #{$gap});}

  dd { // default grid: four columns 
    flex: 0 0 calc(25% - #{$gap});}

  .half { // hall width columns
    flex: 0 0 calc(50% - #{$gap});}

}

Échantillon Codepen complet

Veiko Jääger
la source
2
Cela ajoute toujours une gouttière avant le premier et après le dernier élément, ce que OP empêche d'utiliser des marges négatives.
herman
2
Flexbox ne prend pas en charge calc () dans l'élément "flex" dans IE 11.
Adam Šipický
Ne peut pas toujours être utilisé. imaginez s'il y a aussi une frontière nécessaire pour les enfants directs
Andris
9

Un conteneur flexible avec une marge -x (négative) et des éléments flexibles avec une marge x (positive) ou un rembourrage conduisent tous deux au résultat visuel souhaité: les éléments flexibles ont un espace fixe de 2x uniquement entre eux.

Il semble que ce soit simplement une question de préférence, qu'il s'agisse d'utiliser une marge ou un rembourrage sur les éléments flexibles.

Dans cet exemple, les éléments flexibles sont mis à l'échelle dynamiquement afin de préserver l'écart fixe:

.flex-container { 
  margin: 0 -5px;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.flex-item {
  margin: 0 5px; // Alternatively: padding: 0 5px;
  flex: 1 0 auto;
}
Tim
la source
3
Désolé, je ne l'ai pas compris. Quelles nouveautés introduisent votre réponse qui ne sont pas dites directement dans la question?
utilisateur
Tout d'abord, je voulais résumer que la marge et le rembourrage sur l'élément flexible conduisent au résultat souhaité, car les réponses existantes ne mentionnent que l'un ou l'autre. Deuxièmement, je voulais donner un exemple, où les lacunes sont préservées en mettant à l'échelle les éléments flexibles eux-mêmes.
Tim
voici un exemple de codepen montrant cet effet. codepen.io/dalgard/pen/Dbnus
pedalpete
8

Finalement, ils ajouteront la gappropriété à flexbox. Jusque-là, vous pouvez utiliser à la place une grille CSS qui a déjà la gappropriété et avoir une seule ligne. Plus agréable que de gérer les marges.

Ollie Williams
la source
Discussion ici: github.com/w3c/csswg-drafts/issues/1696 - ils rationaliseront également la dénomination, à travers CSS Grid, Flexbox et CSS Columns.
Frank Lämmer
6

CSS gapPropriété :

Il existe une nouvelle gappropriété CSS pour les dispositions multi-colonnes, flexbox et grille qui fonctionne maintenant dans certains navigateurs! (Voir Puis-je utiliser le lien 1 ; lien 2 ).

#box {
  display: flex;
  flex-wrap: wrap;
  width: 200px;
  background-color: red;
  gap: 10px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Au moment de l'écriture, cela ne fonctionne malheureusement que dans Firefox. Il fonctionne actuellement dans Chrome si vous activez «Activer les fonctionnalités expérimentales de la plate-forme Web» dans about:flags.

Flimm
la source
5

En utilisant Flexbox dans ma solution, j'ai utilisé la justify-contentpropriété de l'élément parent (conteneur) et j'ai spécifié les marges à l'intérieur de la flex-basispropriété des éléments. Vérifiez l'extrait de code ci-dessous:

.container {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-around;
  margin-bottom: 10px;
}

.item {
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #999;
}

.item-1-4 {
  flex-basis: calc(25% - 10px);
}

.item-1-3 {
  flex-basis: calc(33.33333% - 10px);
}

.item-1-2 {
  flex-basis: calc(50% - 10px);
}
<div class="container">
  <div class="item item-1-4">1</div>
  <div class="item item-1-4">2</div>
  <div class="item item-1-4">3</div>
  <div class="item item-1-4">4</div>
</div>
<div class="container">
  <div class="item item-1-3">1</div>
  <div class="item item-1-3">2</div>
  <div class="item item-1-3">3</div>
</div>
<div class="container">
  <div class="item item-1-2">1</div>
  <div class="item item-1-2">2</div>
</div>

iClusterDev
la source
5

Avec Flexbox, la création de gouttières est pénible, en particulier lorsque l'emballage est impliqué.

Vous devez utiliser des marges négatives ( comme indiqué dans la question ):

#box {
  display: flex;
  width: 100px;
  margin: 0 -5px;
}

... ou modifiez le HTML ( comme indiqué dans une autre réponse ):

<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
            ...
  </div>
</div>

... ou autre chose.

Dans tous les cas, vous avez besoin d'un hack laid pour le faire fonctionner car flexbox ne fournit pas de fonctionnalité " flex-gap" ( du moins pour l'instant ).

Le problème des gouttières, cependant, est simple et facile avec CSS Grid Layout.

La spécification de grille fournit des propriétés qui créent de l'espace entre les éléments de la grille, tout en ignorant l'espace entre les éléments et le conteneur. Ces propriétés sont:

  • grid-column-gap
  • grid-row-gap
  • grid-gap (le raccourci pour les deux propriétés ci-dessus)

Récemment, la spécification a été mise à jour pour se conformer au module CSS Box Alignment , qui fournit un ensemble de propriétés d'alignement à utiliser sur tous les modèles de boîtes. Les propriétés sont donc maintenant:

  • column-gap
  • row-gap
  • gap (sténographie)

Cependant, tous les navigateurs prenant en charge Grid ne prennent pas en charge les nouvelles propriétés, donc j'utiliserai les versions originales dans la démo ci-dessous.

De plus, si un espacement est nécessaire entre les articles et le conteneur, paddingle conteneur fonctionne très bien (voir le troisième exemple dans la démo ci-dessous).

De la spécification:

10.1. Gouttières: les row-gap, column-gapet gap propriétés

Les propriétés row-gapet column-gap(et leur gapraccourci), lorsqu'elles sont spécifiées sur un conteneur de grille, définissent les gouttières entre les lignes de grille et les colonnes de grille. Leur syntaxe est définie dans CSS Box Alignment 3 §8 Gaps Between Boxes .

L'effet de ces propriétés est comme si les lignes de grille affectées avaient acquis une épaisseur: la piste de grille entre deux lignes de grille est l'espace entre les gouttières qui les représentent.

.box {
  display: inline-grid;
  grid-auto-rows: 50px;
  grid-template-columns: repeat(4, 50px);
  border: 1px solid black;
}

.one {
  grid-column-gap: 5px;
}

.two {
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

.three {
  grid-gap: 10px;
  padding: 10px;
}

.item {
  background: lightgray;
}
<div class='box one'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box two'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box three'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Plus d'information:

Michael Benjamin
la source
4

Pourquoi ne pas le faire comme ça:

.item + .item {
    margin-left: 5px;
}

Il utilise le sélecteur frère adjacent pour donner à tous les .iteméléments, sauf le premier a margin-left. Grâce à flexbox, cela donne même des éléments tout aussi larges. Cela pourrait également être fait avec des éléments positionnés verticalement et margin-top, bien sûr.

tillsanders
la source
8
Cela fonctionnerait tant que les éléments flexibles sont toujours sur une seule ligne. Si l'emballage est autorisé, ce ne sera probablement pas suffisant.
Nick F
4

Voici ma solution, qui ne nécessite pas de définir de classes sur les éléments enfants:

.flex-inline-row {
    display: inline-flex;
    flex-direction: row;
}

.flex-inline-row.flex-spacing-4px > :not(:last-child) {
    margin-right: 4px;
}

Usage:

<div class="flex-inline-row flex-spacing-4px">
  <span>Testing</span>
  <span>123</span>
</div>

La même technique peut être utilisée pour les lignes et colonnes flexibles normales en plus de l'exemple en ligne donné ci-dessus, et étendue avec des classes d'espacement autres que 4px.

MK10
la source
4

J'utilise souvent l'opérateur + pour de tels cas

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
.item + .item {
    margin-left: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

wutzebaer
la source
3

Je trouve que la façon la plus simple de le faire est d'utiliser des pourcentages et de laisser la marge correspondre à votre largeur

Cela signifie que vous vous retrouvez avec quelque chose comme ça si vous utilisez votre exemple

#box {
   display: flex;
}

.item {
   flex: 1 1 23%;
   margin: 0 1%;
}

Cela signifie que vos valeurs sont basées sur la largeur, ce qui pourrait ne pas être bon pour tout le monde.

lukefrake
la source
Je suis juste tombé sur cette solution et oui, c'est très agréable. Fonctionne dans mon cas, au moins (un stylo pour ceux qui pourraient le trouver intéressant: codepen.io/rishatmuhametshin/pen/XXjpaV ).
rishat
2

Voici une grille d'éléments d'interface utilisateur de carte avec un espacement complété à l'aide d'une boîte flexible:

entrez la description de l'image ici

J'étais frustré par l'espacement manuel des cartes en manipulant le remplissage et les marges avec des résultats douteux. Voici donc les combinaisons d'attributs CSS que j'ai trouvées très efficaces:

.card-container {
  width: 100%;
  height: 900px;
  overflow-y: scroll;
  max-width: inherit;
  background-color: #ffffff;
  
  /*Here's the relevant flexbox stuff*/
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap; 
}

/*Supplementary styles for .card element*/
.card {
  width: 120px;
  height: 120px;
  background-color: #ffeb3b;
  border-radius: 3px;
  margin: 20px 10px 20px 10px;
}
<section class="card-container">
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
      </section>

J'espère que cela aide les gens, présents et futurs.

buildpax
la source
Mise à jour: cet espacement est efficace pour les éléments HTML de rendu mobile qui nécessitent un certain alignement (par exemple, centre, gauche, etc.). Si vous utilisez Flex Box pour le développement mobile, j'ai trouvé un soulagement à passer à un alignement purement basé sur les marges.
buildpax
2

Columnify - Une classe solo pour N colonnes

Flexbox et SCSS

.columnify {
  display: flex;

  > * {
    flex: 1;

    &:not(:first-child) {
      margin-left: 2rem;
    }
  }
}

Flexbox et CSS

.columnify {
  display: flex;
}

.columnify > * {
  flex: 1;
}

.columnify > *:not(:first-child) {
  margin-left: 2rem;
}
<div class="columnify">
  <div style="display: inline-block; height: 20px; background-color: blue;"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
</div>

Jouez avec sur JSFiddle .

zurfyx
la source
1

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
/* u mean utility */
.u-gap-10 > *:not(:last-child) {
  margin-right: 10px;
}
<div id='box' class="u-gap-10">
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Amo Wu
la source
1

Utilisez simplement le .item + .itemsélecteur pour faire correspondre la seconde.item

#box {
  display: inline-flex;
  margin: 0 -5px;
}
.item {
  background: gray;
  width: 10px;
  height: 50px;
}

#box .item + .item {
  margin-left: 10px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Andrew Luca
la source
1

En supposant:

  • Vous voulez une disposition de grille à 4 colonnes avec habillage
  • Le nombre d'articles n'est pas nécessairement un multiple de 4

Définissez une marge gauche sur chaque élément sauf le 1er, le 5e, le 9e élément, etc. et définissez une largeur fixe sur chaque article. Si la marge de gauche est de 10 pixels, chaque ligne aura une marge de 30 pixels entre 4 éléments, le pourcentage de largeur de l'élément peut être calculé comme suit:

100% / 4 - horizontal-border - horizontal-padding - left-margin * (4 - 1) / 4

Il s'agit d'une solution de contournement décente pour les problèmes impliquant la dernière ligne de flexbox.

.flex {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 1em 0;
  background-color: peachpuff;
}

.item {
  margin-left: 10px;
  border: 1px solid;
  padding: 10px;
  width: calc(100% / 4 - 2px - 20px - 10px * (4 - 1) / 4);
  background-color: papayawhip;
}

.item:nth-child(4n + 1) {
  margin-left: 0;
}

.item:nth-child(n + 5) {
  margin-top: 10px;
}
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
<div class="flex">
  <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 class="item">6</div>
</div>
<div class="flex">
  <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 class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>

Salman A
la source
1

Il existe en effet un moyen agréable, bien rangé et uniquement CSS de faire cela (que l'on peut considérer comme "meilleur").

De toutes les réponses publiées ici, je n'ai trouvé qu'une seule qui utilise avec succès calc () (par Dariusz Sikorski). Mais lorsque posé avec: "mais il échoue s'il n'y a que 2 éléments dans la dernière ligne", il n'y a pas eu de solution développée.

Cette solution répond à la question du PO avec une alternative aux marges négatives et résout le problème posé à Dariusz.

Remarques:

  • Cet exemple montre uniquement une disposition à 3 colonnes
  • Il calc()permet au navigateur de faire les calculs comme il le souhaite - 100%/3 (bien que 33,3333% devraient fonctionner aussi bien) , et (1em/3)*2 (bien que 0,66em devrait également bien fonctionner) .
  • Il utilise ::afterpour remplir la dernière ligne s'il y a moins d'éléments que de colonnes

.flex-container {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}
.flex-container:after {
  content: "";
}
.flex-container > div,
.flex-container:after {
  box-sizing: border-box;
  width: calc((100%/3) - ((1em/3)*2));
}
.flex-container > :nth-child(n + 4) {
  margin-top: 1em;
}

/* the following is just to visualize the items */
.flex-container > div,
.flex-container:after {
  font-size: 2em;
}
.flex-container {
  margin-bottom:4em;
}
.flex-container > div {
  text-align: center;
  background-color: #aaa;
  padding: 1em;
}
.flex-container:after {
  border: 1px dashed red;
}
<h2>Example 1 (2 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
</div>

<h2>Example 2 (3 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

Également sur https://codepen.io/anon/pen/rqWagE

aequalsb
la source
1

Vous pouvez utiliser la nouvelle propriété gap. Je copie-colle l'explication que j'ai trouvée dans cet article , ainsi que plus d'informations

La disposition de la grille CSS présente un écart (auparavant un écart de grille) depuis un certain temps. En spécifiant l'espacement interne d'un élément conteneur plutôt que l'espacement autour des éléments enfants, l'écart résout de nombreux problèmes de disposition courants. Par exemple, avec gap, vous n'avez pas à vous soucier des marges sur les éléments enfants provoquant des espaces indésirables sur les bords d'un élément conteneur:

Malheureusement pour le moment, seul FireFox prend en charge l'écart dans les dispositions flexibles.

@use postcss-preset-env {
  stage: 0;
  browsers: last 2 versions
}

section {
  width: 30vw;
  
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12ch, 1fr));
  
  &[flex] {
    display: flex;
    flex-wrap: wrap;
  }
  
  margin-bottom: 3rem;
}

.tag {
  color: white;
  background: hsl(265 100% 47%);
  padding: .5rem 1rem;
  border-radius: 1rem;
}

button {
  display: inline-flex;
  place-items: center;
  gap: .5rem;
  background: hsl(265 100% 47%);
  border: 1px solid hsl(265 100% 67%);
  color: white;
  padding: 1rem 2rem;
  border-radius: 1rem;
  font-size: 1.25rem;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
<section>
  <h1>Grid</h1> 
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>
<br>
<section flex>
  <h1>Flex</h1>
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>

Andres Paul
la source
gapa déjà été recommandé dans une réponse ici stackoverflow.com/a/58041749/2756409 En outre, ce n'est pas CSS.
TylerH
0

Cela ne fonctionnera pas dans tous les cas, mais si vous avez des largeurs enfants flexibles (%) et connaissez le nombre d'éléments par ligne, vous pouvez spécifier très clairement les marges des éléments nécessaires en utilisant le nth-child/ les sélecteur / s.

Cela dépend en grande partie de ce que vous entendez par «mieux». De cette façon, ne nécessite pas de balisage wrapper supplémentaire pour les éléments enfants ou les éléments négatifs - mais ces choses ont toutes les deux leur place.

section {
  display: block
  width: 100vw;
}
.container {
  align-content: flex-start;
  align-items: stretch;
  background-color: #ccc;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  width: 100%;
}

.child-item {
  background-color: #c00;
  margin-bottom: 2%;
  min-height: 5em;
  width: 32%;
}

.child-item:nth-child(3n-1) {
  margin-left: 2%;
  margin-right: 2%;
}
<html>
  <body>
      <div class="container">
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
        <div class="child-item"></div>
      </div>
   </body>
</html>

jnmrobinson
la source
Pas réactif. Fonctionne uniquement pour le parent à largeur fixe.
Green
1
L'OP ne demande pas de solution réactive et leur exemple utilise une largeur fixe. Étant donné que cela utilise des valeurs%, il est facile de prétendre que cela est réactif car les éléments s'adapteront à la taille du parent qui est définie en pourcentage.
jnmrobinson
0

J'ai rencontré le même problème plus tôt, puis suis tombé sur la réponse à cela. J'espère que cela aidera les autres pour référence future.

réponse longue et courte, ajoutez une bordure à vos articles flexibles pour enfants. vous pouvez ensuite spécifier des marges entre les éléments flexibles à votre guise. Dans l'extrait, j'utilise du noir à des fins d'illustration, vous pouvez utiliser «transparent» si vous le souhaitez.

#box {
  display: flex;
  width: 100px;
  /* margin: 0 -5px; *remove this*/
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  /* margin: 0 5px; *remove this*/
  border: 1px solid black; /* add this */
}
.item.special{ margin: 0 10px; }
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item special'></div>
</div>

Tunasing
la source
0

L'astuce de marge négative sur le conteneur de boîte fonctionne très bien. Voici un autre exemple qui fonctionne très bien avec l'ordre, l'emballage et ce qui ne fonctionne pas.

.container {
   border: 1px solid green;
   width: 200px;
   display: inline-block;
}

#box {
  display: flex;
  flex-wrap: wrap-reverse;
  margin: -10px;
  border: 1px solid red;
}
.item {
  flex: 1 1 auto;
  order: 1;
  background: gray;
  width: 50px;
  height: 50px;
  margin: 10px;
  border: 1px solid blue;
}
.first {
  order: 0;
}
<div class=container>
<div id='box'>
  <div class='item'>1</div>
  <div class='item'>2</div>
  <div class='item first'>3*</div>
  <div class='item'>4</div>
  <div class='item'>5</div>
</div>
</div>

cghislai
la source