Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flexbox wrap according to number of item in container

Tags:

html

css

flexbox

I'm trying to create a flexbox with differents elements in each rows by respecting this rule :

  • if four items : display two items by rows
  • if fives items : display 3 items in first row and 2 items in the second row
  • if six items : display three items by row My issu is when I have four items flexbox wrap last element in the second row.

here is my code

.blocWrapper {
  border: 1px solid red;
  display: flex;
  justify-content: center;
  align-items: center;
}

.blocWrapper .blocContainer {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  border: 1px solid black;
  width: 65%;
  padding-top: 45px;
}

.blocWrapper .blocContainer .bloc {
  width: 300px;
  height: 180px;
  box-shadow: 0 0 3px rgba(0, 0, 0, .2);
  margin: auto;
  text-align: center;
  font-family: raleway;
  word-break: break-word;
  display: flex;
  align-items: center;
  flex-direction: colomn;
}

.blocWrapper .blocContainer .blocTitre {
  font-size: 20px;
  font-weight: 700;
  color: blue;
  margin: 24px;
}
<div class="blocWrapper">
  <article class="blocContainer">
    <div class=" bloc">
      <div class="blocTitre">bloc droit</div>
      <div id="blocContenu"> contenu droit </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc simulateur</div>
      <div id="blocContenu"> contenu simulateur </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>
    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>

  </article>

</div>
like image 268
Mamadou Berthé Avatar asked Jan 13 '18 21:01

Mamadou Berthé


1 Answers

Since Flexbox doesn't have a property where one can set how the items should wrap, I here make use of a pseudo element to accomplish the same.

.blocWrapper .blocContainer::before {
  content: '';
  width: 100%;
  order: 1;
}

What it does is simply take full width and will force any element before and after to be on a row of their own. With the order we position it it last.

Then with a clever nth-child/nth-last-child rule, we can count the amount of items, and if 4, we position all but the first 2, using the order: 2, after the ::before, and with that make them 2-by-2 when there is only 4.

.blocWrapper .blocContainer .bloc:nth-child(2):nth-last-child(3) ~ .bloc {
  order: 2;
}

This work like that, that the nth-child(2) will select the 2nd item, and if it also will be the 3rd from the end, we know there is only 4, hence that rule kicks in and move the last 2 after the pseudo.

Stack snippet

.blocWrapper {
  display: flex;
}

.blocWrapper .blocContainer {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid black;
  width: 65%;  
  padding-top: 45px;
}

.blocWrapper .blocContainer .bloc {
  width: 300px;
  height: 180px;
  box-shadow: 0 0 3px rgba(0, 0, 0, .2);
  margin: auto;
  text-align: center;
  font-family: raleway;
  word-break: break-word;
  display: flex;
  flex-direction: column;                 /*  fixed misspelled value  */
}

.blocWrapper .blocContainer .blocTitre {
  font-size: 20px;
  font-weight: 700;
  color: blue;
  margin: 24px;
}

/*  added rules  */
.blocWrapper .blocContainer::before {
  content: '';
  width: 100%;
  order: 1;
}
.blocWrapper .blocContainer .bloc:nth-child(2):nth-last-child(3) ~ .bloc {
  order: 2;
}

/* for demo purpose, so 3 items will always fit */
.blocWrapper .blocContainer {
  min-width: 900px;  
}
<div class="blocWrapper">
  <article class="blocContainer">
  
    <div class=" bloc">
      <div class="blocTitre">bloc droit</div>
      <div id="blocContenu"> contenu droit </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc simulateur</div>
      <div id="blocContenu"> contenu simulateur </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>
    
  </article>

</div>

And when more than 4, there will be 3 in the first row (if enough space is available, which I made sure for this demo with the extra rule having a min-width)

Stack snippet

.blocWrapper {
  display: flex;
}

.blocWrapper .blocContainer {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid black;
  width: 65%;  
  padding-top: 45px;
}

.blocWrapper .blocContainer .bloc {
  width: 300px;
  height: 180px;
  box-shadow: 0 0 3px rgba(0, 0, 0, .2);
  margin: auto;
  text-align: center;
  font-family: raleway;
  word-break: break-word;
  display: flex;
  flex-direction: column;                 /*  fixed misspelled value  */
}

.blocWrapper .blocContainer .blocTitre {
  font-size: 20px;
  font-weight: 700;
  color: blue;
  margin: 24px;
}

/*  added rules to check when there is only 4 items  */
.blocWrapper .blocContainer::before {
  content: '';
  width: 100%;
  order: 1;
}
.blocWrapper .blocContainer .bloc:nth-child(2):nth-last-child(3) ~ .bloc {
  order: 2;
}

/* for demo purpose, so 3 items will always fit */
.blocWrapper .blocContainer {
  min-width: 900px;  
}
<div class="blocWrapper">
  <article class="blocContainer">
  
    <div class=" bloc">
      <div class="blocTitre">bloc droit</div>
      <div id="blocContenu"> contenu droit </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc simulateur</div>
      <div id="blocContenu"> contenu simulateur </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>

    <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>
    
   <div class=" bloc">
      <div class="blocTitre">bloc activite professionnelle</div>
      <div id="blocContenu"> contenu activite professionnelle </div>
      <div id="blocLien"> lien</div>
    </div>
    
  </article>

</div>

To combine CSS selectors like that can be very powerful and expanded to count items e.g. on a last row, like this:

  • FlexBox align (stretch) last Item

Or like this:

  • Can CSS detect the number of children an element has?
like image 59
Asons Avatar answered Nov 15 '22 00:11

Asons