3

I have a CSS like this.

I want to dynamically change the position of the cards to the center or right justified according to the number of elements of the card:

.section {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}
<div class="section">
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
</div>

For example, when the number of card elements is 3 or less, I want to center the elements like this:

.section {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
  justify-content: center;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}
<div class="section">
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
</div>

And when the number of card elements is 4 or more, I want to align the elements to the left or right like this:

.section {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
  /* justify-content: left; OR*/
  justify-content: right;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}
<div class="section">
  <div class="card">1</div>
  <div class="card">2</div>
  <div class="card">3</div>
  <div class="card">4</div>
  <div class="card">5</div>
  <div class="card">6</div>
</div>

I tried to achieve these using Flex, Grid, but I could not. Is it possible to achieve the operations described above using CSS, Flexbox or Grid Layout?

  • Seems that you want to differently style the parent according it's childrans and this is impossible for now without `javascript`, Take a look here https://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector – A. Meshu Nov 15 '19 at 07:25

2 Answers2

3

With an extra wrapper you can do this:

.wrapper {
  text-align: center;
  background-color: #ffabaf;
  max-width: 80vw;
  margin:10px;
}

.section {
  display: inline-flex;
  flex-wrap: wrap;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}
<div class="wrapper">
  <div class="section">
    <div class="card"></div>
  </div>
</div>


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

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

Or you can consider nth-child() and centring using margin if you really want to control this with the number of elements:

.section {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
  margin: 10px;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}
/* 1 */
.card:first-child:nth-last-child(1) {
  margin:auto;
}
/* 2 */
.card:first-child:nth-last-child(2) {
  margin-left:auto;
}
.card:last-child:nth-child(2) {
  margin-right:auto;
}
/* 3 */
.card:first-child:nth-last-child(3) {
  margin-left:auto;
}
.card:last-child:nth-child(3) {
  margin-right:auto;
}
<div class="section">
  <div class="card"></div>
</div>

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

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

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

Another syntax like below:

.section {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
  margin: 10px;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}

.card:first-child:nth-last-child(1),
.card:first-child:nth-last-child(2),
.card:first-child:nth-last-child(3){
  margin-left:auto;
}
.card:last-child:nth-child(1),
.card:last-child:nth-child(2),
.card:last-child:nth-child(3){
  margin-right:auto;
}
<div class="section">
  <div class="card"></div>
</div>

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

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

<div class="section">
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
</div>
Temani Afif
  • 180,975
  • 14
  • 166
  • 216
  • 1
    You can use `:only-child` instead of `:first-child:last-child`. – Ori Drori Nov 15 '19 at 08:14
  • 1
    @OriDrori true but I wanted to keep the same visual pattern so we can clearly see the trick from 1 to 3 – Temani Afif Nov 15 '19 at 08:16
  • I like the second snippet: very interesting approach combining child selectors like this. :-) – Artur Noetzel Nov 15 '19 at 08:22
  • Thank you for a very nice answer. I first considered the snippet method for a more concise description. However, the snippet did not work when there were more than four in the latest version of Firefox (with or without the `justify-content` property). Do I need any additional styles? –  Nov 17 '19 at 03:14
  • I took a screenshot of this behavior: https://imgur.com/pAUJQtE –  Nov 17 '19 at 03:20
  • Also, in code snippets 2 and 3, auto margin is applied to flex items after line breaks, and the alignment is no longer centered ([jsFiddle](https://jsfiddle.net/1jc7bpLk/)). So in order to get a margin for line breaks, I considered using the `gap` property (in flexbox). However, none of these attempts led to the problem being solved. –  Nov 17 '19 at 06:18
0

You cannot determine how many children an element has in css, so you will need some javaScript for this. In the following example the justify: center; style is inside its own class few-items-layout. The script is being executed onLoad and sets the class on the .cards container whenever the amount of its children is 3 or less:

HTML

<section class="cards">
  <div class="card">1</div>
  <div class="card">2</div>
  <div class="card">3</div>
  <div class="card">4</div>
  <div class="card">5</div>
  <div class="card">6</div>
</section>

CSS

.cards {
  display: flex;
  flex-wrap: wrap;
  background-color: #ffabaf;
  max-width: 80vw;
}

.cards.few-items-layout {
  justify-content: center;
}

.card {
  width: 90px;
  height: 90px;
  background-color: #afafbb;
  border: 3px solid;
}

javaScript

(function setLayoutClass() {
  let fewItemsLayoutClass = 'few-items-layout',
      cardsContainer = document.querySelector('.cards'),
      cardsAmount = document.querySelectorAll('.card').length;

  cardsContainer.classList.remove(fewItemsLayoutClass);

  if(cardsAmount <= 3) {
    cardsContainer.classList.add(fewItemsLayoutClass);
  }
})();
Artur Noetzel
  • 263
  • 1
  • 2
  • 9