web-dev-qa-db-fra.com

Comment conserver les éléments flexibles enveloppés à la même largeur que les éléments de la ligne précédente?

J'ai un <ul> qui est un flex-box et un tas de <li>s qui sont les flex-items.

J'essaie d'obtenir le <li> pour avoir une largeur flexible, qui reste entre deux tailles en utilisant min-width et max-width. Cela fonctionne très bien tant qu'ils sont sur la même ligne. Cependant, lorsqu’ils sont bouclés, les <li>s de la nouvelle ligne utilisent autant d’espace que possible. Ce qui signifie qu'ils sont petits sur la première ligne et gros sur la deuxième ligne quand ils sont peu nombreux.

Existe-t-il un moyen de demander à flexbox de conserver la largeur des éléments après l’emballage, tout en conservant la largeur de celui-ci?

démo d'emballage:

enter image description here

Mon code ressemble à ceci:

<ul>
  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/100/100">
    </figure>
  </li>
  <!-- ... -->
</ul>

Et le CSS:

ul {
  display: flex;
  flex-wrap: wrap;
}

  li {
    min-width: 40px;
    max-width: 100px;
    flex: 1 0 0;
  }

Voici un exemple en direct sur codepen avec quelques commentaires supplémentaires, redimensionnez votre fenêtre pour la voir se dérouler.

40
midu

TL; DR

Ce n'est pas quelque chose que j'appellerais une solution} _, mais une solution de contournement plutôt élégante qui utilise uniquement des requêtes multimédia, et plus important encore sans JavaScript!

Mixin (SCSS):

@mixin flex-wrap-fix($flex-basis, $max-viewport-width: 2000px) {
  flex-grow: 1;
  flex-basis: $flex-basis;
  max-width: 100%;

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-viewport-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    @media(min-width: $flex-basis * $multiplier) {
      max-width: percentage(1/$multiplier);
    }
  }
}

Usage:

Appliquez le mixin à votre article flex:

.flex-item {
  @include flex-wrap-fix(100px)
}

Mettre à jour:

Le mélange ci-dessus devrait faire l'affaire, à condition que votre largeur de conteneur flex corresponde à la taille de votre fenêtre, comme c'est le cas dans l'exemple d'OP. Les requêtes multimédias ne vous aideront pas, car elles sont toujours basées sur la largeur de la fenêtre. Toutefois, vous pouvez utiliser la bibliothèque css-element-queries et ses requêtes d’éléments au lieu des requêtes multimédias du navigateur. Voici un mix que vous pouvez appliquer au flex conteneur:

@mixin flex-container-wrap-items($flex-basis, $max-expected-width: 2000px) {
  display: flex;
  flex-wrap: wrap;

  > * {
    max-width: 100%;
    flex-grow: 1;
    flex-basis: $flex-basis;
  }

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-expected-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    &[min-width~="#{$flex-basis * $multiplier}"] > * {
      max-width: percentage(1/$multiplier);
    }
  }
}

Explication:

Supposons, comme dans l'exemple du PO, que nous voulions que chaque élément ait une largeur maximale de 100px. Nous savons donc que pour une largeur de navigateur de 100px, nous pouvons adapter un élément par ligne, et ainsi de suite: 

| Viewport Width | Max Item Count Per Row | Item Width (min-max) |
|----------------|------------------------|----------------------|
| <= 100         | 1                      | 0px - 100px          |
| <= 200         | 2                      | 50px - 100px         |
| <= 300         | 3                      | 50px - 100px         |
| <= 400         | 4                      | 50px - 100px         |
| <= 500         | 5                      | 50px - 100px         |
| <= 600         | 6                      | 50px - 100px         |

Nous pouvons écrire des requêtes multimédia pour créer les règles suivantes:

| Viewport Width | Max Item Count Per Row | Item Max Width | Calculation |
|------------------------------------------------------------------------|
| <= 100px       | 1                      | 100%           | (100/1)     |
| <= 200px       | 2                      | 50%            | (100/2)     |
| <= 300px       | 3                      | 33.33333%      | (100/3)     |
| <= 400px       | 4                      | 25%            | (100/4)     |
| <= 500px       | 5                      | 20%            | (100/5)     |
| <= 600px       | 6                      | 16.66666%      | (100/6)     |

Comme ça:

li {
  flex: 1 0 0
  max-width: 100%;
}

@media(min-width: 200px) {
  li { max-width: 50%; }
}

@media(min-width: 300px) {
  li { max-width: 33.33333%; }
}

@media(min-width: 400px) {
  li { max-width: 25%; }
}

@media(min-width: 500px) {
  li { max-width: 20%; }
}

@media(min-width: 600px) {
  li { max-width: 16.66666%; }
}

Bien sûr, c'est répétitif, mais vous utilisez probablement une sorte de pré-processeur, qui peut prendre en charge la répétition pour vous. C’est précisément ce que fait le mixin de la section TL; DR ci-dessus.

Il ne nous reste plus qu'à spécifier 100px en tant que flex-basis et éventuellement la largeur maximale de la fenêtre du navigateur (définie par défaut sur 2000px) pour créer les requêtes multimédia pour:

@include flex-wrap-fix(100px)

Exemple

Enfin, une version "forkée" de l'exemple CodePen d'origine avec la sortie souhaitée, utilisant le mix ci-dessus:

http://codepen.io/anon/pen/aNVzoJ

 demo of the solution

49
Merott

J'ai essayé avec votre codepen et j'ai mis flex: 0 1 10%

Bien sûr, vous pouvez définir la base flexible comme vous le souhaitez. Je voulais simplement prouver que si vous définissez la base flexible et que vous la permettez de la réduire, elle se comportera beaucoup mieux.

Je pense que c'est ce dont vous aviez besoin. Voici l'aperçu: http://codepen.io/anon/pen/bwqNEZ

À votre santé

9
Pavelloz

Je pense que je l'ai eu ... mais c'est hacky. Le résultat est 14 images, chacune allant de 100 pixels de large à 40 pixels, même sur plusieurs lignes. 

 From 107px to 40px Width

  • Ajout d'un jeu de doublons des 14 <li>s d'origine et ajout de ceux-ci au flex <ul>
  • Ensuite, le deuxième ensemble a été rendu invisible:

    li:nth-of-type(n + 15) {
      visibility: hidden;
    }
    
  • Afin de maintenir une flexibilité uniforme, les modifications suivantes ont été apportées à chaque <li>:

    li {
      min-width: 40px;
      max-width: 10%;
      flex: 1 0 100px;
    }
    

S'il vous plaît examiner le CodePen

et/ou Snippet en mode Full Page.

ul {
  display: flex;
  flex-wrap: wrap;
  max-height: 258px;
}
li {
  min-width: 40px;
  max-width: 10%;
  flex: 1 0 100px;
}
ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  background-color: tomato;
}
li {
  margin: 0.5em;
  background-color: darkgreen;
}
li img {
  width: 100%;
  opacity: 0.5;
}
li figure,
li img {
  margin: 0;
  padding: 0;
}
li:nth-of-type(n + 15) {
  visibility: hidden;
}
<ul>
  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/101/101">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/201/201">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/80/80">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/111/111">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/40/40">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/110/110">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/75/75">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/89/89">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/32/32">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/61/61">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/320/320">
    </figure>
  </li>



  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/101/101">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/201/201">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/80/80">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/111/111">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/40/40">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/110/110">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/75/75">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/89/89">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/32/32">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/61/61">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/320/320">
    </figure>
  </li>
</ul>

2
zer00ne

La définition des pourcentages min-width et max-width a permis à toutes les images de conserver la même largeur lors de leur insertion sur la ligne suivante. Ce n'est pas idéal, mais plus proche de ce que vous recherchez?

li {
  min-width: 15%;
  max-width: 15%;  
}

1
lili2311

Cela ne fonctionne pas très bien, mais vous pouvez réaliser quelque chose dans cette direction avec des colonnes.

column-gap: 10px;
column-width: 150px;

https://codepen.io/hobbeshunter/pen/OgByNX

1
hobbeshunter

Pour Stylus, vous pouvez utiliser ce mixin: https://codepen.io/anon/pen/Epjwjq


   flex-wrap-fix($basis, $max) {
     flex-grow: 1
     flex-basis: $basis
     max-width: 100%

     $multiplier = ceil($max / $basis)

     for i in (1..$multiplier) {
       @media(min-width: ($basis * i)) {
         max-width: percentage(1/i)
       }
     }
   }
0
Daniel D

Ma solution n’est pas idéale car elle s’appuie sur JQuery: http://codepen.io/BigWillie/pen/WwyEXX

CSS

ul {
  display: flex;
  flex-wrap: wrap;
}

li {
  min-width: 40px;
  max-width: 100px;
  flex: 1;
}

JavaScript

var eqRowFlexItem = function(elem) {
    var w;
    var $elem = $(elem);
    // Clear out max-width on elements
    $elem.css('max-width', '');
    w = $(elem).eq(0).width();
    $(elem).css('max-width', w);
}

eqRowFlexItem('li');

$(window).resize(function() {
    eqRowFlexItem('li');
});

Je ne suis pas tout à fait sûr si cela répond au problème. J'ai trouvé ce post, car le titre correspondait au problème que j'avais. Je recherchais un effet selon lequel j'aurais un plus grand nombre d'éléments par ligne sur des écrans plus grands - et moins d'éléments par ligne sur des écrans plus petits. Dans les deux cas, ces éléments devaient également évoluer pour s'adapter ... à tous les périphériques.

Cependant, ces éléments parasites sur la dernière ligne se développeraient toujours pour remplir l'espace restant. 

JQuery obtient la largeur du premier élément - et l'applique comme largeur maximale à chaque élément. Le PO souhaitait que les blocs tombent dans une rage min-width/max-width. Définir la largeur maximale en CSS semble fonctionner. Nous effaçons l'élément max-width de la largeur, il sera donc défini par défaut sur max-width dans le fichier CSS ... puis obtiendra la largeur réelle.

0
Rob

J'ai eu le même problème, alors j'ai utilisé un très petit morceau de Jquery pour contrôler la largeur des boîtes et les rendre toutes identiques, même une fois qu'elles se sont déroulées.

Ma démo est sur CodePen Flex wrap, avec la même largeur sur la nouvelle ligne

function resize(){
  var colWidth;
  var screen = $(window).width(); 
  
  if(screen < 576){
    colWidth = Math.round(screen / 2) - 31;
    $(".item").width(colWidth);
  } 
  if(screen > 575 && screen < 768){
    colWidth = Math.round(screen / 3) - 31;
    $(".item").width(colWidth);
  } 
  else if (screen > 767 && screen < 992){
      colWidth = Math.round(screen / 4) -31;
      $(".item").width(colWidth);
  }
  else if (screen > 991 ){
      colWidth = Math.round(screen / 6) -31;
      $(".item").width(colWidth);
  }
}
  
window.onresize = function() {
  resize();
}

resize();
html,
body{
  padding:0;
  margin:0;
}
.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  -ms-box-orient: horizontal;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -moz-flex;
  display: -webkit-flex;
  display: flex;
  justify-content: left;
  background-color:#ddd;
}

.wrap    { 
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
}  

.item {
  background: tomato;
  height: 100px;
  margin:0 15px;
  line-height: 100px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
  margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="flex-container wrap">
  <li class="item">1</li>
  <li class="item">2</li>
  <li class="item">3</li>
  <li class="item">4</li>
  <li class="item">5</li>
  <li class="item">6</li>
  <li class="item">7</li>
  <li class="item">8</li>
  <li class="item">9</li>
</ul>

0
T.Hallam

Ce n'est pas parfait mais vaut la peine d'essayer. http://codepen.io/anon/pen/MKmXpV

Les changements sont

li
  width: 7.1428%
  flex: 0 0 auto

figure
  margin: 0 auto
  background-color: darkgreen
  min-width: 40px
  max-width: 100px
  • changé li flex en "0 0 auto" et la largeur de li en pourcentage basé sur.
  • déplacé les largeurs min et max du li à la figure
  • déplacé le fond vert sur la figure et centré les figures dans.
0
Miriam Salzer