Copy link to clipboard
Copied
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!
.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%;
...
Copy link to clipboard
Copied
.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
Copy link to clipboard
Copied
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.)
Copy link to clipboard
Copied
@L e n a Finally got to try the code! Love the results, with one caveat : "box-sizing: border-box" doesn't appear to be kicking in. As soon as I add a gap space, the container's width becomes 100% + gaps. In fact, the results appear identical with and without the box-sizing line included.
I suppose I can work around this with a "calc", but I'd rather not get that convoluted with the code if it can be avoided. Any theories on why this could be happening, or suggestions for solutions that don't involve substracting the manually-specified gap-length from 100% via "calc"?
Copy link to clipboard
Copied
One way, assuming it's a gap between the anchor tags you are requiring - set the css on the anchor tag to less than 25%, say 23%, and apply align-content: space-between; on the 'container ' css.
Copy link to clipboard
Copied
Good thinking. With 4 sub-groups and 3 gaps of 1.25em, I was going to use something like width:calc(100% - 3.75em) on the container. Would your method be a more elegant solution? Or would the two methods work equally well, with neither having much advantage over the other?
PS: I'm still a bit annoyed that the box-sizing fix didn't work on gaps like it works on padding. I mean the property is old as heck.. maybe it just doesn't play well with Flex, which is newer? Could Flex have its OWN proprietary equivalent to box-sizing: border-box that would fix this?
Copy link to clipboard
Copied
I don't see anything incorrect in using your solution......in fact you should be able to control the gaps more accurately using calc.
My advice would be to use what is familiar to you and that which you feel comfortable deploying..............there's many ways which can be used to arrive at practically the same result.
Doesn't grid also suffer the same issue where padding gets added to the width of a container despite using box-sizing: border-box? Somewhere in the back of my mind l seem to recall it does.
Copy link to clipboard
Copied
Yes, grid has the same issue. So neither function seems to consider gaps as padding. Wouldn't this suggest that it's the box-sizing property that's at fault, here? If so, the only obvious fix for this would be to update box-sizing at the root level to take these cell gaps into account like they already do with padding. Until then, we'll probably be hacking fixes; like back in the Internet Explorer days.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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. 🙂
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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?)
Copy link to clipboard
Copied
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% */
Copy link to clipboard
Copied
I'm glad that it helped you. Concerning your last request, and in order to complete with images, what @osgood_ has told you, I can't recommend enough that you visit the CSS Tricks site - https://css-tricks.com/snippets/css/a-guide-to-flexbox/... #aa-flex-grow is clearly explained.
You can also check out MDN's site, where the diagrams are sometimes supplemented by some very instructive technical details https://developer.mozilla.org/fr/docs/Learn/CSS/CSS_layout/Flexbox