Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

style only first item in each flexbox row

Tags:

css

flexbox

I have a horizontal, wrapping flexbox, like so:

.container {
  display:        flex;
  flex-direction: row;
  flex-wrap:      wrap;
}

The number of items per row will vary depending on the screen width, and the width of each item will vary as well.

I would like to add styling to only the first item of each flexbox row. Below is an illustration of what I'm looking for.

Example 1
|--------|--------|--------|
|style me|        |        |
|--------|--------|--------|
|style me|        |        |
|--------|--------|--------|
|style me|        |
|--------|--------|

Example 2
|--------|---|-----|------------|
|style me|   |     |            |
|--------|---|-----|------------|
|  style me     |      |        |
|---------------|------|--------|
| style me |      |
|----------|------|

How can I do this using Flexbox?

I still need the rows to wrap as the screen is resized, so I don't think I can use Grid. However, if it is possible to use Grid to solve this problem, that would be a good solution for me as well.

Update

This can be accomplished using CSS Grid and either the auto-fill or auto-fit values. See this question for details:

CSS grid wrapping

like image 248
dwhieb Avatar asked Mar 09 '19 01:03

dwhieb


1 Answers

As @AndyHoffman already mentioned in the comments, (as of March 2019) it is impossible to do it with pure css. If you tolerate a bit of javascript, then you could iterate over all the flex children and see if their position indicates that they are in the first column and apply styling accordingly. A rudimentary example is shown in the snippet below:

function highlightFirst(){
  let flexChildren = document.querySelectorAll('.content');
  let leftPosition = flexChildren[0].offsetLeft;
  for(let flexChild of flexChildren){
    if(flexChild.offsetLeft <= leftPosition){
      flexChild.classList.add('firstColumn');
    }else{
      flexChild.classList.remove('firstColumn');
    }
  }
}
window.addEventListener('resize', highlightFirst);
highlightFirst();
* {
  list-style:none;
  margin: 0;
  padding: 0;
}

.wrapper {
  display: flex;
  flex-wrap: wrap;
  border: solid 1px black;
}

.content {
  height: 20px;
  background: grey;
  margin: 5px;
}

.firstColumn {
  border: 2px dashed red;
}
<ul class="wrapper">
    <li class="content" style="width:  14px;">1</li>
    <li class="content" style="width:  77px;">2</li>
    <li class="content" style="width:  41px;">3</li>
    <li class="content" style="width:  94px;">4</li>
    <li class="content" style="width:  76px;">5</li>
    <li class="content" style="width:  61px;">6</li>
    <li class="content" style="width:  81px;">7</li>
    <li class="content" style="width:  70px;">8</li>
    <li class="content" style="width:  22px;">9</li>
    <li class="content" style="width:  29px;">10</li>
    <li class="content" style="width:  27px;">11</li>
    <li class="content" style="width:  22px;">12</li>
    <li class="content" style="width:  56px;">13</li>
    <li class="content" style="width:  32px;">14</li>
    <li class="content" style="width:  55px;">15</li>
    <li class="content" style="width:  34px;">16</li>
    <li class="content" style="width:  75px;">17</li>
    <li class="content" style="width:  97px;">18</li>
    <li class="content" style="width:  25px;">19</li>
    <li class="content" style="width:  48px;">20</li>
</ul>

The example is really basic and rudimentary just to show a working principle, but in order to be usable in real-world scenarios it should be extended to circumvent the following shortcomings:

  1. The javascript is run only on start and on window resize - it would be best to use a resizeObserver on the parent .wrapper, but the support is really poor.
  2. It does not detect size changes of the content of each flex child
  3. Only left to right direction is assumed
  4. Exact left margin of all items is assumed (so that the first column always has the left edge aligned)
  5. It uses hard-coded class names
  6. Due to used ES6 language features, it might need transpiling or rewriting to support older browsers (it that is required)
like image 154
Piotr Wicijowski Avatar answered Oct 01 '22 20:10

Piotr Wicijowski