问题
I'm using flex to create a multi column list that adjusts the number of columns based on the width of the container.
The problem I found is that if I want to use the full width of the parent by setting flex-grow to 1, the items in the last wrapped row are misaligned, since they try to fill the parent.
I found two workarounds that don't work for me: one used media queries, which I can't use because the parent is not the same width of the viewport; the other was using columns
, but I can't use it because it causes issues with outlines being cut off and wrapped, which I have in my real setup.
Q: Is there a way to make all items have the same width while filling the parent on full rows?
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid red;
width: 50%;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
margin: -1em -1em 0 0;
}
li {
border: 1px solid black;
padding: 1em;
margin: 1em 1em 0 0;
flex: 1 1 10em;
}
<div class="wrapper">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>
https://plnkr.co/edit/0u2QxcdLkDfhwV3zASrM
Resize until you get 2 items in the last row.
回答1:
Add a few extra flex items and make them "invisible" by setting their height/padding/border to 0/none. Based on how many columns you'll need, it takes one less for it to work.
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid red;
width: 100%;
max-width: 800px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
margin: -1em -1em 0 0;
}
li {
border: 1px solid black;
padding: 1em;
margin: 1em 1em 0 0;
flex: 1 1 10em;
}
li:nth-last-child(-n+3) {
height: 0;
border: none;
padding: 0;
margin: 0 1em 0 0;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div class="wrapper">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</body>
</html>
If all but the extra elements has a content, you could also use this CSS rule (thanks to Rick Hitchcock)
li:empty {
height: 0;
border: none;
padding: 0;
margin: 1em 1em 0 0;
}
If the amount of columns never will be more than 3, one can use pseudo elements. (Well, the columns can be more as long as there will never be more than 2 items missing on the last row)
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid red;
width: 100%;
max-width: 800px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
margin: -1em -1em 0 0;
}
li {
border: 1px solid black;
padding: 1em;
margin: 1em 1em 0 0;
flex: 1 1 10em;
}
ul::before, ul::after {
content: '';
height: 0;
border: none;
padding: 0;
margin: 0 1em 0 0;
flex: 1 1 10em;
order: 999; /* they need to be last */
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div class="wrapper">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>
</body>
</html>
回答2:
FLex
will fail without a bit of javascript to fill or not the eventual space on last line.
Grid
, in the futur will be 100% efficient for this kind of beahavior layout.
Snippet below that you can test in FF and Chrome if you have enable "experimental CSS".( https://igalia.github.io/css-grid-layout/enable.html )
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid red;
width: 50%;
min-width:12.25em;
}
ul {
list-style: none;
margin: 0;
padding: 0 0 1em 1em;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10em, 1fr))
}
li {
border: 1px solid black;
padding: 1em;
margin: 1em 1em 0 0;
}
<div class="wrapper">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>
Of course this is not the answer you expected, but it is about what CSS can (will) do.
You can keep on going with flex and a few tricks, but i believe the best would be flex + a bit of javascript :) at this time.
to start learning and testing the grid CSS system , see :
A tutorial https://css-tricks.com/snippets/css/complete-guide-grid/
browser supports http://caniuse.com/#search=grid
a Polyfill https://github.com/FremyCompany/css-grid-polyfill/
http://gridbyexample.com/browsers/
回答3:
It depends on the actual situation, but you can prevent flex-grow for the last one, two, three (whatever, I made it for the last two) children with the appropriate selectors:
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid red;
width: 50%;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
margin: -1em -1em 0 0;
}
li {
border: 1px solid black;
padding: 1em;
margin: 1em 1em 0 0;
flex: 1 1 10em;
}
li:last-child, li:nth-last-child(2) {
flex-grow: 0;
}
<div class="wrapper">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>
回答4:
It's like we need one more value in the "flex" rule for items: a boolean for "make all items uniform dimension". Like flex: grow shrink basis uniform
来源:https://stackoverflow.com/questions/42767664/flex-wrapped-items-with-same-width-as-the-rest