Largeur du fluide avec DIVs également espacés

329

J'ai un récipient de largeur fluide DIV.

Dans ce que j'ai 4 DIVs tous 300px x 250px ...

<div id="container">
   <div class="box1"> </div>
   <div class="box2"> </div>
   <div class="box3"> </div>
   <div class="box4"> </div>
</div>

Ce que je veux, c'est que la boîte 1 flotte à gauche, la boîte 4 à droite et les boîtes 2 et 3 à intervalles réguliers entre elles. Je veux que l'espacement soit également fluide afin que le navigateur soit plus petit, l'espace devient également plus petit.

entrez la description de l'image ici

Lee Price
la source
2
Pourquoi ne pas faire display:inline-block;au lieu de flotter?
ayyp
1
car IE6 / IE7 ne prend inline-blocken charge que les inlineéléments
Lee Price
D'accord, je ne savais pas pour quels navigateurs vous alliez.
ayyp
1
La solution la plus proche à laquelle je pouvais penser était d'envelopper chaque div .box enfant dans un autre div d'une largeur de 25%. Ensuite, centrez le div .box enfant sur le wrapper. Les divs .box seront espacées uniformément, mais les div gauche et droite ne seront pas directement sur le bord.
Paul Sham
5
J'ai transformé l'idée de @Paul Sham en JSFiddle .
Sparky

Réponses:

440

Voir: http://jsfiddle.net/thirtydot/EDp8R/

  • Cela fonctionne dans IE6 + et tous les navigateurs modernes!
  • J'ai réduit de moitié les dimensions demandées pour faciliter le travail.
  • text-align: justifycombiné avec .stretchest ce qui gère le positionnement.
  • display:inline-block; *display:inline; zoom:1correctifs inline-blockpour IE6 / 7, voir ici .
  • font-size: 0; line-height: 0 corrige un problème mineur dans IE6.

#container {
  border: 2px dashed #444;
  height: 125px;
  text-align: justify;
  -ms-text-justify: distribute-all-lines;
  text-justify: distribute-all-lines;
  /* just for demo */
  min-width: 612px;
}

.box1,
.box2,
.box3,
.box4 {
  width: 150px;
  height: 125px;
  vertical-align: top;
  display: inline-block;
  *display: inline;
  zoom: 1
}

.stretch {
  width: 100%;
  display: inline-block;
  font-size: 0;
  line-height: 0
}

.box1,
.box3 {
  background: #ccc
}

.box2,
.box4 {
  background: #0ff
}
<div id="container">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
  <div class="box4"></div>
  <span class="stretch"></span>
</div>

L'extra span( .stretch) peut être remplacé par :after.

Cela fonctionne toujours dans tous les mêmes navigateurs que la solution ci-dessus. :afterne fonctionne pas dans IE6 / 7, mais ils utilisent distribute-all-linesquand même, donc peu importe.

Voir: http://jsfiddle.net/thirtydot/EDp8R/3/

Il y a un inconvénient mineur :after: pour que la dernière ligne fonctionne parfaitement dans Safari, vous devez faire attention aux espaces dans le HTML.

Plus précisément, cela ne fonctionne pas:

<div id="container">
    ..
    <div class="box3"></div>
    <div class="box4"></div>
</div>

Et cela:

<div id="container">
    ..
    <div class="box3"></div>
    <div class="box4"></div></div>

Vous pouvez l'utiliser pour n'importe quel nombre arbitraire d'enfants divsans ajouter de boxNclasse à chacun en modifiant

.box1, .box2, .box3, .box4 { ...

à

#container > div { ...

Ceci sélectionne n'importe quel div qui est le premier enfant du #containerdiv, et aucun autre en dessous. Pour généraliser les couleurs d'arrière-plan, vous pouvez utiliser le sélecteur d'ordre n CSS3 , bien qu'il ne soit pris en charge que dans IE9 + et d'autres navigateurs modernes:

.box1, .box3 { ...

devient:

#container > div:nth-child(odd) { ...

Voir ici pour un exemple jsfiddle.

thirtydot
la source
123
Il m'a fallu 3h pour constater que vous devriez avoir des espaces entre chaque cases dans le html. "Justifier" étend les espaces entre les éléments et si votre contenu l'est, <div/><div/><div/>il ne fonctionne pas. Vous devez avoir <div/> <div/> <div/>.
venimus
5
je voulais juste le noter :) car il est difficile de noter si vous travaillez avec un contenu généré (ce qui est le cas commun). Je pensais utiliser justifypour un tel cas, mais merci de fournir une solution de travail. m'a sauvé beaucoup d'expériences (malgré le débogage de 3h: D). De plus, je pourrais ajouter une note que si vous voulez que votre dernière ligne soit alignée à gauche, vous devez ajouter des boîtes invisibles supplémentaires (pour compléter la ligne)
venimus
4
@venimus: J'ai écrit une autre réponse en utilisant cette technique: stackoverflow.com/questions/10548417/… . Qu'avez-vous fait pour vous débarrasser de la hauteur supplémentaire causée par l'ajout de boîtes invisibles?
thirtydot
11
Quelqu'un peut-il expliquer pourquoi le .stretch est nécessaire?
atp
6
@HartleySan: Le .stretch/ :afterest nécessaire car (généralement) avec un texte justifié, la dernière ligne n'est pas justifiée . Ici, nous voulons que la dernière ligne soit justifiée, d'où la nécessité :after. Quant à votre deuxième question, je l'ai exploré il y a quelque temps dans une réponse précédente . Dans cette réponse, JavaScript était requis. Si vous devez prendre en charge des navigateurs plus anciens (IE8), je pense que vous avez besoin de JavaScript.
thirtydot du
140

La façon la plus simple de le faire maintenant est d'utiliser une flexbox:

http://css-tricks.com/snippets/css/a-guide-to-flexbox/

Le CSS est alors simplement:

#container {
    display: flex;
    justify-content: space-between;
}

démo: http://jsfiddle.net/QPrk3/

Cependant , ceci n'est actuellement pris en charge que par des navigateurs relativement récents ( http://caniuse.com/flexbox ). De plus, les spécifications de la mise en page de la flexbox ont changé plusieurs fois, il est donc possible de couvrir plus de navigateurs en incluant en plus une syntaxe plus ancienne:

http://css-tricks.com/old-flexbox-and-new-flexbox/

http://css-tricks.com/using-flexbox/

Ben Jackson
la source
1
Merci pour cela, si facile, je l'ai appliqué à quatre listes espacées dans un pied de page fixé en bas d'une page. A travaillé un régal dans FF28.0, Chrome 34.0.1847.116 m et IE11.
user1063287
1
Flexbox n'est pas l'outil le plus pris en charge sur le Web et il ne bat pas l'approche classique de la marge et du remplissage.
TheBlackBenzKid
Pour tous ceux qui cherchent à justifier plusieurs divs avec une largeur non définie: utilisez flex-wrap avec l'option display: flex. Il encapsulera les divs avec une largeur dynamique.
Kamil Budziewski
20

Si css3 est une option, cela peut être fait en utilisant la calc()fonction css .

Cas 1: Justifier les cases sur une seule ligne ( FIDDLE )

Le balisage est simple - un tas de divs avec un élément conteneur.

CSS ressemble à ceci:

div
{
    height: 100px;
    float: left;
    background:pink;
    width: 50px;
    margin-right: calc((100% - 300px) / 5 - 1px); 
}
div:last-child
{
    margin-right:0;
}

-1px pour corriger un bug de calcul / arrondi IE9 + - voir ici

Cas 2: justification des cases sur plusieurs lignes ( FIDDLE )

Ici, en plus de la calc()fonction, media queriessont nécessaires.

L'idée de base est de mettre en place une requête média pour chaque état #columns, où j'utilise ensuite calc () pour calculer la marge de droite sur chacun des éléments (sauf ceux de la dernière colonne).

Cela ressemble à beaucoup de travail, mais si vous utilisez LESS ou SASS, cela peut être fait assez facilement

(Cela peut toujours être fait avec des CSS réguliers, mais vous devrez alors faire tous les calculs manuellement, puis si vous changez la largeur de votre boîte - vous devez tout recommencer)

Voici un exemple utilisant LESS: (Vous pouvez copier / coller ce code ici pour jouer avec, [c'est aussi le code que j'ai utilisé pour générer le violon mentionné ci-dessus])

@min-margin: 15px;
@div-width: 150px;

@3divs: (@div-width * 3);
@4divs: (@div-width * 4);
@5divs: (@div-width * 5);
@6divs: (@div-width * 6);
@7divs: (@div-width * 7);

@3divs-width: (@3divs + @min-margin * 2);
@4divs-width: (@4divs + @min-margin * 3);
@5divs-width: (@5divs + @min-margin * 4);
@6divs-width: (@6divs + @min-margin * 5);
@7divs-width: (@7divs + @min-margin * 6);


*{margin:0;padding:0;}

.container
{
    overflow: auto;
    display: block;
    min-width: @3divs-width;
}
.container > div
{
    margin-bottom: 20px;
    width: @div-width;
    height: 100px;
    background: blue;
    float:left;
    color: #fff;
    text-align: center;
}

@media (max-width: @3divs-width) {
    .container > div {  
        margin-right: @min-margin;
    }
    .container > div:nth-child(3n) {  
        margin-right: 0;
    }
}

@media (min-width: @3divs-width) and (max-width: @4divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{3divs})/2 - 1px)";
    }
    .container > div:nth-child(3n) {  
        margin-right: 0;
    }
}

@media (min-width: @4divs-width) and (max-width: @5divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{4divs})/3 - 1px)";
    }
    .container > div:nth-child(4n) {  
        margin-right: 0;
    }
}

@media (min-width: @5divs-width) and (max-width: @6divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{5divs})/4 - 1px)";
    }
    .container > div:nth-child(5n) {  
        margin-right: 0;
    }
}

@media (min-width: @6divs-width){
    .container > div {  
        margin-right: ~"calc((100% - @{6divs})/5 - 1px)";
    }
    .container > div:nth-child(6n) {  
        margin-right: 0;
    }
}

Donc, fondamentalement, vous devez d'abord décider d'une largeur de boîte et d'une marge minimale que vous souhaitez entre les boîtes.

Avec cela, vous pouvez déterminer la quantité d'espace dont vous avez besoin pour chaque état.

Ensuite, utilisez calc () pour calculer la marge droite et nth-child pour supprimer la marge droite des cases de la dernière colonne.

L' avantage de cette réponse par rapport à la réponse acceptée qui utilise text-align:justifyest que lorsque vous avez plus d'une ligne de cases - les cases de la dernière ligne ne sont pas «justifiées», par exemple: s'il reste 2 cases sur la dernière ligne - I Je ne veux pas que la première case soit à gauche et la suivante à droite - mais plutôt que les cases se suivent dans l'ordre.

En ce qui concerne la prise en charge du navigateur : cela fonctionnera sur IE9 +, Firefox, Chrome, Safari6.0 + - (voir ici pour plus de détails) Cependant, j'ai remarqué que sur IE9 +, il y a un petit problème entre les états de requête multimédia. [si quelqu'un sait comment résoudre ce problème, j'aimerais vraiment le savoir :)] <- CORRIGÉ ICI

Danield
la source
13

D'autres articles ont mentionné Flexbox , mais si plusieurs lignes d'éléments sont nécessaires , la space-betweenpropriété de Flexbox échoue (voir la fin de l'article)

À ce jour, la seule solution propre pour cela est avec le

Module de disposition de grille CSS ( démo Codepen )

Fondamentalement, le code nécessaire se résume à ceci:

ul {
  display: grid; /* (1) */
  grid-template-columns: repeat(auto-fit, 120px); /* (2) */
  grid-gap: 1rem; /* (3) */
  justify-content: space-between; /* (4) */
  align-content: flex-start; /* (5) */
}

1) Faire de l'élément conteneur un conteneur de grille

2) Définissez la grille avec une quantité «automatique» de colonnes - si nécessaire. Cette opération est effectuée pour les mises en page réactives. La largeur de chaque colonne sera de 120 pixels. (Notez l'utilisation de auto-fit(tel qu'apposé à auto-fill) qui (pour une disposition à 1 rangée) réduit les pistes vides à 0 - permettant aux éléments de s'étendre pour occuper l'espace restant. (Consultez cette démo pour voir de quoi je parle) )).

3) Définissez les espaces / gouttières pour les lignes et les colonnes de la grille - ici, car vous voulez une disposition «espace entre» - l'écart sera en fait un écart minimum car il augmentera si nécessaire.

4) et 5) - Similaire à la flexbox.

body {
  margin: 0;
}
ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, 120px);
  grid-gap: 1rem;
  justify-content: space-between;
  align-content: flex-start;
  
  /* boring properties: */
  list-style: none;
  width: 90vw;
  height: 90vh;
  margin: 2vh auto;
  border: 5px solid green;
  padding: 0;
  overflow: auto;
}
li {
  background: tomato;
  height: 120px;
}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Démo Codepen (Redimensionner pour voir l'effet)


Prise en charge du navigateur - Caniuse

Actuellement pris en charge par Chrome (Blink), Firefox, Safari et Edge! ... avec le soutien partiel d'IE (Voir cet article de Rachel Andrew)


NB:

La space-betweenpropriété de Flexbox fonctionne très bien pour une ligne d'éléments, mais lorsqu'elle est appliquée à un conteneur flexible qui enveloppe ses éléments - (avec flex-wrap: wrap) - échoue, car vous n'avez aucun contrôle sur l'alignement de la dernière ligne d'éléments; la dernière ligne sera toujours justifiée (généralement pas ce que vous voulez)

Démontrer:

Codepen (redimensionner pour voir de quoi je parle)


Pour en savoir plus sur les grilles CSS:

Danield
la source
1
Réponse très sous-estimée. C'était le moyen le plus simple et le plus efficace pour réaliser ce que je voulais faire. Je vous remercie.
Barnaby Mercer
1
C'était la plus petite quantité de CSS (et pas de JS!) Qui a produit exactement le comportement que je cherchais, avec quelques ajustements pour la taille et l'espace.
EKW
1
Je le cherche depuis un moment et je l'ai finalement trouvé!. Merci @Danield
nareeboy
2

Cela a fonctionné pour moi avec 5 images de différentes tailles.

  1. Créer une div conteneur
  2. Une liste non ordonnée pour les images
  3. Sur css, le non ordonné doit être affiché verticalement et sans puces
  4. Justifier le contenu du conteneur div

Cela fonctionne à cause du contenu justifié: espace entre, et il est sur une liste, affiché horizontalement.

Sur CSS

 #container {
            display: flex;
            justify-content: space-between;
 }
    #container ul li{ display:inline; list-style-type:none;
}

Sur html

<div id="container"> 
  <ul>  
        <li><img src="box1.png"><li>
        <li><img src="box2.png"><li>
        <li><img src="box3.png"><li>
        <li><img src="box4.png"><li>
        <li><img src="box5.png"><li>
    </ul>
</div>
Sebastián Brun Valiente
la source
Bien que ce code puisse bien fonctionner, une bonne réponse comprendrait une explication de son fonctionnement et pourquoi c'est une bonne solution.
Blackwood
Il convient de noter que flexbox n'est pas (ou seulement partiellement) pris en charge par IE caniuse.com/#feat=flexbox
David Salamon
est-ce réactif?
stackdave
1

en jQueryvous pourriez cibler le parent directement.

CELA EST UTILE SI VOUS NE SAVEZ PAS EXACTEMENT COMBIEN D'ENFANTS SERONT AJOUTÉS DYNAMIQUEMENT OU SI VOUS NE POUVEZ JUSTEMENT PAS DÉTERMINER LEUR NUMÉRO.

var tWidth=0;

$('.children').each(function(i,e){
tWidth += $(e).width();

///Example: If the Children have a padding-left of 10px;..
//You could do instead:
tWidth += ($(e).width()+10);

})
$('#parent').css('width',tWidth);

Cela permettra à la parentcroissance horizontale de childrens'ajouter.

REMARQUE: cela suppose que le '.children'ont un widthet HeightSet

J'espère que cela pourra aider.

ErickBest
la source
1

Si vous connaissez le nombre d'éléments par "ligne" et la largeur du conteneur, vous pouvez utiliser un sélecteur pour ajouter une marge aux éléments dont vous avez besoin pour créer un aspect justifié.

J'avais des rangées de trois divisions que je voulais justifier, donc utilisé le:

.tile:nth-child(3n+2) { margin: 0 10px }

cela permet au div central de chaque rangée d'avoir une marge qui force le 1er et le 3e div aux bords extérieurs du conteneur

Également idéal pour d'autres choses comme les couleurs de fond des bordures, etc.

Dave Robertson
la source