Skip to main content
Inspiring
October 29, 2024
Answered

(Flexbox) Newbie question re: items-per-row

  • October 29, 2024
  • 3 replies
  • 4914 views

I'm currently teaching myself Flexbox (via css-tricks) and although everything seems straightforward enough at first glance, I find myself struggling to get the following simple behavior working correctly.

 

Basically, I'm going for something like this...
<div class="container">
     <a href="#">Stuff</a>
     <a href="#">Stuff</a>
     <a href="#">Stuff</a>
     <a href="#">Stuff</a>
</div>

...where a row of 4 anchor tags (or possibly span tags) becomes two rows of 2 tags when the width of the container becomes too narrow for 4. So I want it to skip the 3 & 1 scenario and go right from a row of 4 to two rows of 2. (Even numbers, never an orphaned option alone on a row.) These content "boxes" (a or span) should be of equal width to one another, and top-justified (so if one has more content than the others, it will be vertically longer, but equal-width and top-justified).

With Grid, they were columns so I'd just tell the grid to go from 4 colums to 2 via a @ Media screen declaration, when the viewport got narrower than X pixels. So I'm kind of looking for the Flex equivalent of that behavior (or the closest thing to it).

 

What would that css look like? I sometimes find it easier to reverse-engineer from the solution.
Thanks!

This topic has been closed for replies.
Correct answer L e n a
.container {
    display: flex;               /* Use Flexbox layout */
    flex-wrap: wrap;            /* Allow items to wrap onto multiple lines */
}

.container a {
    flex: 1 0 25%;              /* Basis of 25% for four items in a row */
    border: 1px dotted red;    /* Thick border for visibility */
    box-sizing: border-box;      /* Include padding and border in width */
}

/* Media query for widths below 600px */
@media (max-width: 600px) {
    .container a {
        flex: 1 0 50%;          /* Basis of 50% for two items in a row */
    }
}

By setting the flex property of the anchor tags to 25%, the layout accommodates four tags in a row. Upon reaching a specified breakpoint of 600 pixels, the flex property adjusts to 50%, allowing for only two tags per row.

This strategy guarantees that the layout maintains even distribution and avoids orphaned tags, aligning perfectly with the specified design requirements.

 

You can watch the result https://demo.puce-et-media.com/UnderS/flexbox-1.html

3 replies

Inspiring
October 31, 2024

Sorry I was in location and just get back now...

In fact it all depnd about your way, and what you want to learn...  @osgood_ propose a nice way to go too...  just explore it...

 

now sticking to tthe previous approach, there are as many solutions for integrating a gap as there are developers on this thread... although sometimes, for this kind of need, grid is more direct and simple... in any case, here are a few ideas for aligning 4 elements in a row, or 2 or 1 alone, depending on the width of the available screen and also now integrating a gap

 

Approach 1: Flexbox with Margin

.flex-container {
    display: flex;              
    flex-wrap: wrap;            
    margin: -5px;               /* Negative margin to offset child margins */
}

.flex-container .box {
    flex: 1 0 calc(25% - 10px); /* Basis of 25% minus margin */
    margin: 5px;                /* Margin for spacing */
}

Each box got, as you was exploring, a property flex: 1 0 calc(25% - 10px). So it means each box will take about 25% of the container width, minus 10 pixels for the margin (5 pixels on each side).

The negative margin on the container is helping to offset the margin applied to each box, so they stay aligned good without overflowing the container.

Then with media queries, when the screen width is less than 900 pixels, just adjusts to 50% for two boxes, and when it’s less than 600 pixels, apply 100% .

@media (max-width: 900px) {
    .flex-container .box {
        flex: 1 0 calc(50% - 10px); /* Basis of 50% for two items in a row */
    }
}

@media (max-width: 600px) {
    .flex-container .box {
        flex: 1 0 100%;          /* Basis of 100% for one item in a row */
    }
}



 

Approach 2: CSS Grid

.grid-container {
    display: grid;              
    grid-template-columns: repeat(4, 1fr); /* Four equal columns */
    gap: 10px;                  /* Gap between items */
}

Use display: grid property for create a grid layout and apply a grid-template-columns: repeat(4, 1fr) to define four columns in the grid.

The 1fr unit means that each column will have each an equivalent width from the available space, so they will adapt when the screen size changes.

Then gap: 10px property define the gap between each items whatever their width is.

Now, when the width is below 900 pixels, switch the grid-template-colums to 2, and below 600 pixels to just 1. 

@media (max-width: 900px) {
    .grid-container {
        grid-template-columns: repeat(2, 1fr); /* Two columns */
    }
}

@media (max-width: 600px) {
    .grid-container {
        grid-template-columns: 1fr; /* One column */
    }
}

 

 

Approach 3: Flexbox with Gap

.flex-gap-container {
    display: flex;              
    flex-wrap: wrap;            
    gap: 10px;                  /* Gap for spacing */
}

.flex-gap-container .box {
    flex: 1 0 calc(25% - 10px); /* Basis of 25% for four items in a row */
}

you can also use Flexbox again, but this time take advantage of the gap property to manage the space between the boxes.

gap: 10px , that will automatically creates a space of 10 pixels between the flex items

no need to play with margin anymore... but... while the gap property works well beside Flexbox in modern browsers, it’s not supported in all versions. 

 

That should do the job for testing purpose  https://demo.puce-et-media.com/UnderS/flexbox-2.html

Under S.Author
Inspiring
November 7, 2024

So much to learn from here, thank you!

I have everything working perfect, and have only one last question about what we used to call "colspan" back in the Table days. In a flex container that sets sub-divs at 25% each, how do I make one of them occupy two spaces (ie, 50%) of the row in some situations? (What's the code I can use directly on that sub-div to tell it take up twice the usual width?)

Braniac
November 7, 2024

I assume you have 3 cols?

 

2 which span 25% each and 1 which spans 50%?

 

Try:

flex: 1; /* for the cols which span 25% */

 

flex: 2; /* for the col that spans 50% */

Braniac
October 29, 2024

Foĺlow Lenas advice or you can wrap the pairs of  "a" tags in divs and apply the  css attribute white-space: nowrap; to the divs, which will force the pairs of "a' tags onto a seperate line at any screen width which won't accommodate them, without using media queries, although on smart phone screens you may possibly want each 'a' tag to be on its own line...............so plenty to think about.

Under S.Author
Inspiring
October 29, 2024

I considered asking Lena to fix it so the 4 not only become 2 (when the viewports gets under X pixels) but also, as you are suggesting here, the 2 becoming 1 in even narrower spaces like smart phones... but a) I honestly have zero immediate need for that, and b) I figured I might be able to edit the code myself (to do just that) once I really absorb what Lena did, and how. If I was wrong, I'll be back for more pointers. 🙂

Braniac
October 29, 2024

There are so many viewport variations these days you may need to deploy a lot of media queries to achieve the desired effect across a range of devices. When l deployed a set of icons and didn't want a widow icon on one line the extensive amount of media queries l had to use became an issue so l used 'white-space nowrap' which does the job more automatically and caters for any size viewport rather than media queries which only activate at certain viewport widths.........l was exploring a more robust option to cater to a wider amount of devices automatically.

 

Maybe lm unusual but l frequently widen and narrow my browser viewport on a Mac so if there's no media query to  cater for the varying widths the intended design outcome doesn't always work.

 

L e n aCorrect answer
Inspiring
October 29, 2024
.container {
    display: flex;               /* Use Flexbox layout */
    flex-wrap: wrap;            /* Allow items to wrap onto multiple lines */
}

.container a {
    flex: 1 0 25%;              /* Basis of 25% for four items in a row */
    border: 1px dotted red;    /* Thick border for visibility */
    box-sizing: border-box;      /* Include padding and border in width */
}

/* Media query for widths below 600px */
@media (max-width: 600px) {
    .container a {
        flex: 1 0 50%;          /* Basis of 50% for two items in a row */
    }
}

By setting the flex property of the anchor tags to 25%, the layout accommodates four tags in a row. Upon reaching a specified breakpoint of 600 pixels, the flex property adjusts to 50%, allowing for only two tags per row.

This strategy guarantees that the layout maintains even distribution and avoids orphaned tags, aligning perfectly with the specified design requirements.

 

You can watch the result https://demo.puce-et-media.com/UnderS/flexbox-1.html

Under S.Author
Inspiring
October 29, 2024

Thank you, that is beautiful and exactly the behavior I'm going for. Can't wait to try this later.

 

About 'box-sizing: border-box' -- I have it applied to my html & body tags (so regardless how many different boxes there are on the page, the padding is always factored into the dimensions. Frankly, I think it's weird that border-box *isn't* the default behavior. Never had a problem so far, do I risk encountering any later? (By making border-box the default box-sizing behavior for the whole site, I mean.)