Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS: How to change display grid to flex conditionally with CSS selectors?

I have a grid that is populated with elements from a v-for loop in Vue. Also, I have a search bar that reduces grid elements based on the input. If the element count is more than 3 then it looks great, but when I only have left 2 elements it's too spaced out. Therefore, I'd like to change display: grid; to display: flex; if elements in the grid are less than 3.

I've tried with CSS selectors, perhaps I'm doing something wrong since I'm fairly new to programming. I know how to add a dynamic class using javascript, however, I'd like to see if it would be possible with plain CSS.

Tried the following css selector and its variations:

.grid-container {
    display: grid;
    grid-template-columns: repeat( auto-fit, minmax(290px, 1fr) );
    grid-gap: 3rem;

}

.grid-container:first-child:nth-last-child(n + 2) {
    display: flex;
    display: -webkit-flex;
    flex-wrap: wrap;
    flex-direction: row;
    justify-content: flex-start;
    align-items: auto;
    align-content: center;
}
like image 421
Inga Avatar asked Nov 07 '22 16:11

Inga


1 Answers

You cannot (without JavaScript) select a parent element based on the number of children it has (with the exception of whether or not that element has 0 (:empty) or more (:not(:empty) children).

You can, however, select all the children based on the number of siblings they have. This means that you cannot change from grid to flex, but you could use display: flex all the time and then change how the elements flow in the flexbox (ie by modifying their align-self, justify-self, or flex-* properties). I can't give a specific example because I can't see your layout, but I can give a general demo of how it works below.

Here's the breakdown of the selector:

    .container > :first-child:nth-last-child(n + 3),
    .container > :first-child:nth-last-child(n + 3) ~ * 
  • .container Select all with the "container" class.
  • > Select direct children (ie, not children of children) of the container.
  • :first-child Filter the direct children so you just have the first child.
  • :nth-last-child(n + 3) Filter the first child so it's only selected if it is three or more elements from the end of its container. This will give 0 elements if the child is less than three elements from the end of its container. In other words it only keeps the selection if the first child has 2 or more siblings following it.
  • ~ * Select all siblings that follow the selected element.

document.addEventListener("DOMContentLoaded", () => {
  document.querySelector("#clickTarget").addEventListener("click", () => {
    let target = document.querySelector(".container > div:last-child");
    target.parentNode.removeChild(target);
  });
});
/* 0 or more elements */
.container > .child {
  background-color: blue;
}

/* 3 or more elements */
.container > .child:first-child:nth-last-child(n + 3),
.container > .child:first-child:nth-last-child(n + 3) ~ * {
  background-color: green;
}

/* 6 or more elements (must be after the above rule to override it) */
.container > .child:first-child:nth-last-child(n + 6),
.container > .child:first-child:nth-last-child(n + 6) ~ * {
  background-color: orange;
}
<button id="clickTarget">
  Pop Last Element
</button>

<div class="container">
  <div class="child">1</div>
  <div class="child">2</div>
  <div class="child">3</div>
  <div class="child">4</div>
  <div class="child">5</div>
  <div class="child">6</div>
  <div class="child">7</div>
</div>
like image 80
Ian Avatar answered Nov 12 '22 10:11

Ian