Solution CSS pure pour fractionner des éléments en une quantité dynamic de colonnes

Existe-t-il un moyen d’aligner les éléments dans plusieurs colonnes, où le nombre de colonnes dépend de l’élément le plus large? La hauteur de l’élément et la largeur du conteneur sont fixes, mais la largeur de l’élément est dynamic.

Je cherche un moyen CSS uniquement pour obtenir le comportement suivant:

(Supposons que le conteneur parent a une largeur de 300px.)

  • Si l’élément le plus large est plus large que 150px, utilisez une seule colonne
  • Si l’élément le plus large se situe entre 100px et 150px, utilisez deux colonnes
  • Si l’élément le plus large est inférieur à 100px, utilisez trois colonnes
  • Si l’élément le plus large est inférieur à la largeur du conteneur / N, utilisez N colonnes

Un moyen possible d’avoir ce comportement pourrait être d’utiliser la propriété display:inline-block et setting width à la largeur de l’élément le plus large du conteneur utilisant JavaScript.

Voir ce JSFiddle pour un exemple:

Exemple

Cependant, je pense qu’il devrait également y avoir une manière de faire CSS uniquement. C’est possible?

Sinon, peut-être existe-t-il une façon élégante de dissortingbuer / aligner les éléments de taille dynamic sur les colonnes d’un conteneur de largeur fixe?

… Je recherche un moyen CSS uniquement pour obtenir le comportement suivant … Si l’élément le plus large est plus large que …

… Je pense qu’il devrait aussi y avoir une façon de faire CSS uniquement …

Comme indiqué par @ Paulie-D , CSS ne peut pas détecter des largeurs variables dans vos div enfants et, par conséquent, il n’existe pas de solution CSS uniquement.

Cela est dû au fait que vous souhaitez obtenir la largeur de tous les éléments, puis en obtenir le maximum, puis utiliser cette largeur pour répartir les éléments en colonnes. Ce calcul est au-delà de CSS. Vous aurez besoin de Javascript pour le faire.

Sinon, peut-être existe-t-il une façon élégante de dissortingbuer / aligner les éléments de taille dynamic sur les colonnes d’un conteneur de largeur fixe?

Je vais expliquer cela en deux parties:


Partie 1, le CSS:

Lorsque nous disons que nous voulons que le contenu soit dans les colonnes, cela signifie un stream de haut en bas au lieu de stream d’encapsulation de gauche à droite. Pour cela, nous avons besoin de colonnes CSS.

L’astuce serait de spécifier auto pour le column-count / column-width . Cela dissortingbuera automatiquement le contenu dans le nombre de colonnes requirejs dans la largeur parente.

J’ai commis une erreur fondamentale dans la déclaration ci-dessus (d’ où une autre édition ). Selon les spécifications, l’algorithme dit:

  (01) if ((column-width = auto) et (column-count = auto)) alors
 (02) sortie;  / * pas un élément multicol * / 

C’est là que je me suis trompé plus tôt. Lorsque le column-count column-width sont définis sur auto ils ne sont pas considérés comme un élément multicol . Lorsque l’une de ces propriétés est définie sur une valeur non automatique, l’autre propriété est déterminée par celle-ci.

De la ref ci – dessus :

si le nombre de colonnes est défini sur auto , le nombre de colonnes sera déterminé par d’autres propriétés (par exemple, la column-width , si elle a une valeur non automatique) et si la column-width est définie sur auto , la largeur de la colonne sera déterminé par d’autres propriétés (par exemple, nombre de column-count , s’il a une valeur non automatique)

Un exemple serait de définir la column-width de column-width à une column-width fixe, par exemple 120px ( nous traiterons cela un peu plus tard dans la partie 2 ):

 .container { -webkit-columns: auto 120px; columns: auto 120px; } 

Cela entraînera le conteneur pour adapter le contenu dans autant de colonnes que possible pour une largeur de colonne de 120px dans sa propre largeur. Si vous augmentez la largeur du conteneur, vous obtiendrez plus de colonnes. Si vous réduisez la largeur du conteneur, le nombre de colonnes finissant par être réduit à une colonne sera réduit lorsque l’espace disponible est insuffisant.

Voir l’exemple complet dans l’extrait ci-dessous:

Exemple 1 :

 * { box-sizing: border-box; padding: 0; margin: 0; } p { margin-left: 16px; } .container { width: 400px; border: 1px solid #f00; margin: 16px; } .container.col { -webkit-columns: auto 120px; columns: auto 120px; } .container > div { -webkit-column-break-inside: avoid; column-break-inside: avoid; display: block; padding: 8px; border: 1px solid #ccc; } #one { width: 200px; } #two { width: 300px; } 
 

Small Container (1-column):

Maudie Mcmanus
Remedios
Chaya B
Duncan
Lashonda

Medium Container (2-column):

Maudie Mcmanus
Remedios
Chaya B
Duncan
Lashonda

Large Container (3-column):

Maudie Mcmanus
Remedios
Chaya B
Duncan
Lashonda

De même que tout ce qu’ils ont dit dans les commentaires, il n’existe pas de solution uniquement en CSS donc je voulais vous laisser une belle solution en utilisant js dans lequel vous n’avez même pas à parcourir le plus grand élément, tout provient d’un ensemble de CSS et math.

Vous pouvez changer le contenu des éléments et vous verrez comment le nombre de colonnes est ajusté. Si l’élément le plus large est inférieur à la largeur du conteneur / N, il utilisera automatiquement N colonnes.

Découvrez ce JSFiddle pour la démo

L’idée est très simple, vous set width: 'auto' , display: 'inline-block' au container pour lui permettre de s’adapter à son contenu qui est défini par la largeur de l’élément le plus large.

entrer la description de l'image ici

Maintenant, vous pouvez utiliser la largeur du container pour connaître la largeur de l’article le plus large, ce qui vous évitera de devoir l’itérer. Actuellement, vous pouvez utiliser cette largeur pour définir le rest des éléments, mais faisons un peu mieux, nous pouvons faire en sorte que les éléments occupent toute la largeur du container avec un calcul de la scope:

 var div = Math.floor(initialWidth / widestItemWidth); /*this is to get as many items fit with the width of the widest element*/ var itemWidth = initialWidth / div; /*for the width of the item occupy the entire container*/ 

Donc si l’élément le plus large est inférieur à la largeur du conteneur / N, il utilisera N colonnes automatiquement et elles s’adapteront à la largeur du container , c’est tout ce que vous avez à faire, définissez simplement une propriété css, faites un peu de calcul et ce que vous vouliez réaliser

 $(document).ready(function() { var $container = $('.container'); var $item = $('.item'); var initialWidth = $container.outerWidth(); $container.css({ /*to allow it to fit its contents which is defined by the width of the widest element*/ width: 'auto', display: 'inline-block' }); var widestItemWidth = $container.outerWidth(); /*Now this is the width of the widest item*/ var div = Math.floor(initialWidth / widestItemWidth); /*this is to get as many items fit with the width of the widest element*/ var itemWidth = initialWidth / div; /*for the width of the item occupy the entire container*/ /*if you don't want the items occupy the entire width of the container just use 'widestItemWidth' as width of $item*/ $item.css({ width: itemWidth, float: 'left' }); $container.css({ /*restoring the initial styles*/ width: initialWidth, display: 'block' }); }) 
 .container { width: 400px; overflow: hidden; } .container .item { padding: 8px; border: 1px solid rgb(216, 213, 213); } *{ box-sizing: border-box; } 
  
Maudie Mcmanus
Remedios Arrington
Chaya B
Duncan
Lashonda Tatum Walls

Le plus proche de ce que vous pouvez probablement obtenir avec une solution CSS pure consiste à utiliser des colonnes CSS comme suggéré par d’autres (ou l’approche CSS Grid – Voir Modifier) . Cependant, la solution consiste à utiliser des unités relatives et à connaître l’emplacement et le conteneur de colonnes dans votre mise en page et à utiliser les requêtes multimédia pour contrôler le nombre de colonnes. Ce n’est certainement pas une solution à l’épreuve des balles. Cependant, si vous créez la disposition et contrôlez l’emplacement et la scope de l’élément conteneur de colonne, vous pouvez contrôler le nombre de colonnes de manière assez fiable. Si c’est pour un widget qui est hors de votre contrôle, vous devrez en effet implémenter une solution basée sur Javascript.

Liens de référence: Colonnes CSS réactives , disposition de la grid CSS

EDIT: Après avoir relu votre question et examiné votre exemple de capture d’écran, il semble que vous recherchiez une solution de grid de grid CSS commune dans laquelle les éléments circulent horizontalement et non verticalement. J’ai mis à jour ma réponse pour inclure une démo d’extrait de code dans laquelle les blocs sont à nouveau horizontaux.

Démonstration d’extrait de code avec des requêtes de média basées sur des colonnes et des largeurs de conteneur (largeur de colonne minimale d’environ 10em):

 #main, #sideBar { box-sizing:border-box; display:block; padding:0; margin:0; width:100%; } .container { width: 100%; min-width:10em; -webkit-columns: 1; -moz-columns: 1; columns: 1; } .container .item { display: block; padding: 8px; border: 1px solid rgb(216, 213, 213); box-sizing:border-box; -webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */ page-break-inside: avoid; /* Firefox */ break-inside: avoid; /* IE 10+ */ } @media only screen and (min-width:20em) { .container { -webkit-columns: 2; -moz-columns: 2; columns: 2; } } @media only screen and (min-width:32em) { #main { float:left; width:65%; } #sideBar { float:left; width:30%; margin-left:5%; } #sideBar .container { -webkit-columns: 1; -moz-columns: 1; columns: 1; } } @media only screen and (min-width:48em) { #main .container { -webkit-columns: 3; -moz-columns: 3; columns: 3; } #sideBar .container { -webkit-columns: 1; -moz-columns: 1; columns: 1; } } @media only screen and (min-width:52em) { #sideBar .container { -webkit-columns: 2; -moz-columns: 2; columns: 2; } } @media only screen and (min-width:100em) { #main .container { -webkit-columns: 5; -moz-columns: 5; columns: 5; } #sideBar .container { -webkit-columns: 3; -moz-columns: 3; columns: 3; } } 
 

#main

Maudie Mcmanus
Remedios Arrington
Chaya B
Duncan
Lashonda Tatum Walls

Eh bien comme beaucoup d’autres l’ont souligné ici, il n’y a pas de solution CSS uniquement. Principalement parce que CSS a été conçu pour être chargé avant le contenu dom afin que le contenu s’affiche correctement. Notre principal problème ici est que nous ne connaissons pas la largeur de l’élément à l’avance, nous ne le saurons que lorsque la page aura été chargée. Presque toutes les solutions de la page ont la même idée, utilisez le Javascript pour parcourir les éléments, trouvez la plus large et définissez tous les autres éléments (avec la même classe) sur la largeur donnée. Pour améliorer le processus et en faire une solution à une seule ligne (avec jquery, on peut aussi le faire avec Javascript, mais pour plus de simplicité, jQuery), je suggère le “hack / sortingck” suivant:

1) Ne définissez pas la largeur de votre conteneur et définissez l’affichage sur une table plutôt que sur un bloc;

2) Ne pas définir de largeur pour les éléments à l’intérieur du div

Cela fera que les éléments auront la même largeur et seront affichés dans une colonne, donc lorsque nous utilisons jQuery pour obtenir la largeur maximale, nous n’avons pas besoin de parcourir les éléments.

Utilisez maintenant jQuery pour injecter des règles CSS supplémentaires dans l’en-tête du document pour le conteneur et pour les éléments. Nous devons changer le type d’affichage du conteneur en bloc au lieu de table, définir sa largeur à 400px (ou tout ce dont nous avons besoin) et nous devons rendre les blocs en ligne avec une largeur définie.

Étant donné que CSS applique toujours la dernière propriété, cela sera assez facile:

 $("").appendTo("head"); 

J’ai mis à jour votre exemple de violoniste ICI

Je l’ai testé dans IE 12, Edge, Chorme et Firefox et cela fonctionne dans tous les navigateurs.

EDIT 1

Si vous ne souhaitez pas utiliser jQuery pour garder la page aussi légère que possible, vous pouvez également utiliser l’un des formats suivants:

 document.head.innerHTML += ""; 

Explication rapide: le conteneur clientWidth inclura le remplissage et la bordure des éléments, puisque le remplissage dans l’exemple original est 8px et la bordure est 1px, nous devons le déduire deux fois (une fois une fois à droite) de la largeur du conteneur .

Voir le violon mis à jour

EDIT 2

Un document HTML complet:

         
Maudie Mcmanus
Remedios Arrington
Chaya B
Duncan
Lashonda Tatum Walls

Tout d’abord – Découvrez la démo de violon (jouez avec la .container du .container .)

Ceci n’est pas possible avec CSS uniquement, mais voici une solution élégante utilisant jquery, qui détecte la largeur du conteneur, la largeur de l’élément le plus large et répartit les éléments dans le nombre de colonnes approprié (créé dynamicment).

HTML

 

Without width:

Maudie Mcmanus
Remedios Arrington
Chaya B
Duncan
Lashonda Tatum Walls

Javascript

 $(function(){ var $items = $('.item'); // detect the widest column's width var widestItemWidth = 0; $items.each(function(){ widestItemWidth = Math.max(widestItemWidth, $(this).width()); }); // calculate the number of columns var $container = $('.container'); var containerWidth = $container.width(); var numOfColumns = parseInt(containerWidth / widestItemWidth); // create the columns for(var i = 0; i < numOfColumns; i++){ $container.prepend('
'); } var $columns = $('.column'); $columns.css('width', (100/numOfColumns)+'%'); // spread the items between the columns $items.each(function(i){ var columnIndex = i % numOfColumns; $(this).appendTo($columns.eq(columnIndex)); }); });

CSS

 .container { width: 400px; } .container .column { display: inline-block; box-sizing: border-box; vertical-align: text-top; } .container .item { display: inline-block; padding: 8px; border: 1px solid rgb(216, 213, 213); }