This question already has answers here:
Zebra striping a flexbox table with wrapping items
(3 answers)
Closed 8 months ago.
When using tables, it is easy to alternate colors in table rows using the nth child selectors (https://stackoverflow.com/a/3084318/1385857). Is there a comparable way to do so when using the flexbox layout. I have the following (from https://philipwalton.github.io/solved-by-flexbox/demos/grids/):
<div class="Grid">
<div class="Grid-cell"></div>
[more divs]
<div class="Grid-cell"></div>
</div>
.Grid
{
display: flex;
flex-wrap: wrap;
}
.Grid-cell
{
flex: 1;
}
Is it possible to alternate row colors in this scenario. To clarify, there are no real rows, only the virtual rows created by flex box due to wrapping.
A bit late but it might help others. Here is a working solution I've just come up with.
It uses the linear-gradient CSS function.
The only downside is that it requires your cells to have a fixed height.
/* $cell_height: 80px */
.grid {
display: flex;
flex-flow: row wrap;
/* this is where the magic is */
background-image: linear-gradient(180deg, red 50%, green 50%);
background-repeat: repeat;
background-size: 100px 160px; /* width is not relevant, but height must be 2*$cell_height */
}
.grid-cell {
height: 80px; /* $cell_height */
/* this is just to have a responsive display for the demo */
width: 25%;
min-width: 250px;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
<div class="grid">
<div class="grid-cell">1</div>
<div class="grid-cell">2</div>
<div class="grid-cell">3</div>
<div class="grid-cell">4</div>
<div class="grid-cell">5</div>
<div class="grid-cell">6</div>
<div class="grid-cell">7</div>
<div class="grid-cell">8</div>
<div class="grid-cell">9</div>
<div class="grid-cell">10</div>
<div class="grid-cell">11</div>
<div class="grid-cell">12</div>
<div class="grid-cell">13</div>
<div class="grid-cell">14</div>
</div>
This is a super old post, but I guess still relevant as this issue just came up for me where I had to do a static layout that's responsive going from two columns to four, so trying to organize the columns into rows like an actual table didn't make sense. The above answer with the repeating gradient is creative and works great if you can have a fixed height on your items, but the down-voted nth-child selector answer is better with flex-box if your items need to wrap and have flexible heights. I think that answer just needed to be tweaked a bit for the situation.
<div class="list-cols">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
<div>Thirteen</div>
<div> </div>
<div> </div>
<div> </div>
</div>
Then adjust your selector for how many columns you have. In this case I've got 4 columns, so the nth-of-type formula selects 1-4, 9-12, etc. In your markup, the number of children needs to be divisible by 4 to make a complete last row, so fill it out with empty divs if necessary.
.list-cols {
display: flex;
flex-wrap: wrap;
}
.list-cols > div {
padding: 8px 12px;
box-sizing: border-box;
flex-basis: 25%;
width: 25%;
}
.list-cols > div:nth-of-type(8n+1),
.list-cols > div:nth-of-type(8n+2),
.list-cols > div:nth-of-type(8n+3),
.list-cols > div:nth-of-type(8n+4) {
background: #f2f2f2;
}
You can use the same technic with nth-child (2n+1, even, odd), or whatever you want.
The display of the element doesn't interfere with that here.
.Grid {
display: flex;
flex-wrap: wrap;
}
.Grid-row {
flex: 1;
}
.Grid-cell:nth-child(2n+1) {
background: pink;
}
<div class="Grid">
<div class="Grid-row">
<div class="Grid-cell">Grid-cell 1</div>
<div class="Grid-cell">Grid-cell 2</div>
<div class="Grid-cell">Grid-cell 3</div>
<div class="Grid-cell">Grid-cell 4</div>
<div class="Grid-cell">Grid-cell 5</div>
<div class="Grid-cell">Grid-cell 6</div>
<div class="Grid-cell">Grid-cell 7</div>
</div>
<div class="Grid-row">
<div class="Grid-cell">Grid-cell 1</div>
<div class="Grid-cell">Grid-cell 2</div>
<div class="Grid-cell">Grid-cell 3</div>
<div class="Grid-cell">Grid-cell 4</div>
<div class="Grid-cell">Grid-cell 5</div>
<div class="Grid-cell">Grid-cell 6</div>
<div class="Grid-cell">Grid-cell 7</div>
</div>
</div>
Related
I have a list of items which is displayed horizontally in div limited by a max-width. In order to hide elements that don't fit, the div has the property overflow-x:hidden. However, sometimes, an items starts to be displayed and is suddenly cut in the middle. This is ugly.
Screenshot: you have the list of items to the left, and another div width a button to the right. Both div are separated by a justify-content: space-between. As you can see, there is a small brown circle which is suddenly cut.
How to remove an element which is not entirely displayed?
ps: I'm working with styled-components in React, so I can easily add javascript if necessary.
by limiting your container height you can use flex and wrap to move the excess divs to the next row and use overflow-y instead of x.
POC:
.container, .container2 {
display: flex;
flex-flow: row wrap;
overflow-y: hidden;
border: solid 1px;
max-height: 25px;
margin: 20px;
}
.item {
margin: 5px;
}
.container2 {
max-width: 200px;
}
<div class="container">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item">item 3</div>
<div class="item">item 4</div>
<div class="item">item 5</div>
</div>
<div class="container2">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item">item 3</div>
<div class="item">item 4</div>
<div class="item">item 5</div>
</div>
You can hide the list items vertically instead of horizontally
div {
white-space: normal;
overflow: hidden;
}
.listItem {
display: inline-block;
}
inline-block will make sure your listItem will go into next line if it doesn't fit
So, I am creating a grid system based on flexbox and everything is going quite swimmingly. The basics of my grid are:
<div class="row">
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
</div>
And in my css:
.row {
margin: 10px 0;
display: flex;
flex-wrap: wrap;
}
.column {
padding: 10px;
flex: 1 1 0%;
}
Essentially, this makes the columns quite fluid, and they shrink/grow to fill all available space. This is great for me as I need to use this throughout various projects where I can't quite customize the grid for every single one. However, I have run into a small "issue". I was going to create a class called ".collapse" so I could collapse the left/right padding to have some columns fit right next together (for example: If I wanted a div with a background color (by adding a color class to the column=> .column .green) flush to an image in the next column). However, the spacing is all out of wack compared to row/columns above it.
<div class="row">
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
</div>
example screenshot here
As you can see in my little example mockup, they do kinda line up, but the right and left margins have "decreased". Is there any smart way around this? I tried adding "left/right margins" to the first-of-type and last-of-type, but this just gets a bit hacky as then anything added in between start having odd alignment issues.
For this kind of grid system, you usually would discourage using structural styling on the grid cells directly, and it lets you do something like this:
.row {
display: flex;
flex-flow: row wrap;
list-style: none;
padding: 0;
margin-left: -10px;
}
.column {
flex: 1 0 0;
padding-left: 10px;
}
.collapse { margin-left: 0; }
.collapse > .column { padding-left: 0; }
.red,
.purple {
padding: 10px;
margin-bottom: 10px;
}
.red { background-color: red; }
.purple { background-color: purple; }
<div class="row">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
<div class="row collapse">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
This approach uses no margins on the outer ends, which I find way more convenient.
It's worth noting that this kind os system is not all that useful anymore, with the advent of CSS Grid Layout, but there you have it.
On a side note, 0 is always 0, and it never needs a unit.
I have a use case that feels like flexbox CSS should be able to handle, but I can't get it working properly. I'm not sure if this use case is beyond what flexbox can handle or not, so I'm looking for advice. (I wrote JavaScript that does what I need, but I'm looking at this to see if a pure CSS implementation is feasible.)
I have one container div that will contain 1 or more items. Each of the contained items has a fixed width and height. The container div has a fixed height, but should only take as much width as it takes to contain its items. The items should be laid out within the div from top to bottom, and should wrap to a new column when they "fill up" the previous column.
Here's some sample HTML that I'm using to test:
<div class="my-container">
<div class="my-item">Item 1</div>
<div class="my-item">Item 2</div>
<div class="my-item">Item 3</div>
<div class="my-item">Item 4</div>
<div class="my-item">Item 5</div>
<div class="my-item">Item 6</div>
<div class="my-item">Item 7</div>
<div class="my-item">Item 8</div>
<div class="my-item">Item 9</div>
<div class="my-item">Item 10</div>
<div class="my-item">Item 11</div>
<div class="my-item">Item 12</div>
<div class="my-item">Item 13</div>
<div class="my-item">Item 14</div>
<div class="my-item">Item 15</div>
<div class="my-item">Item 16</div>
<div class="my-item">Item 17</div>
<div class="my-item">Item 18</div>
<div class="my-item">Item 19</div>
<div class="my-item">Item 20</div>
<div class="my-item">Item 21</div>
<div class="my-item">Item 22</div>
<div class="my-item">Item 23</div>
<div class="my-item">Item 24</div>
<div class="my-item">Item 25</div>
</div>
And here's the CSS I'm using to test:
.my-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
background-color: rgb(33, 150, 243);
padding: 15px;
height: 600px;
}
.my-item {
width: 250px;
height: 25px;
color: white;
padding: 10px;
flex: 0 0 auto;
}
Note that the values for the widths and heights are arbitrary here and may be changed. But the items will always have a fixed width/height and the container will always have a fixed height.
With the CSS above, the items do wrap to a new column correctly, but the container div fills the entire width of the viewport. I need the container div to only be wide enough to contain its items.
If I change the display attribute for my-container from "flex" to "inline-flex", the container width shrinks down, but isn't wide enough to show more than the first column, with subsequent columns not fully visible.
This may be one of those catch 22 situations. The items have fixed size, but need to flow into columns based on the container's height. And the container needs to take its width from the number of columns that its items have flowed into.
I also looked into CSS grid to see if that might be a possibility, but it sounds like you have to know the number of columns in advance for that to work, and I won't know that. The number of columns depends on the size of the items and the height of the container.
Can flexbox CSS solve this problem? If not, any other CSS-based approaches? I already have a JavaScript implementation that does this, I would just prefer to have a pure CSS implementation if that is feasible.
You can use grid's autofill property, so you don't need to know the number of columns.
.my-container {
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(auto-fill, minmax(45px, 1fr));
background-color: rgb(33, 150, 243);
padding: 15px;
height: 600px;
width: fit-content;
}
.my-item {
width: 250px;
height: 25px;
color: white;
padding: 10px;
flex: 0 0 auto;
}
JSFiddle Demo: https://jsfiddle.net/92sak0zc/6/
I noticed a weird bug in all the major browsers when you use a percentage width on an element in a nested flexbox with its justify-content property set to "flex-end". It renders the parent element as if the child were set to 100% width regardless of the percentage actually used by the child.
I have created a Fiddle to demonstrate the issue: https://jsfiddle.net/u21pe916/
HTML
<div class="wrapper">
<div class="flex-col-1">Column 1</div>
<div class="flex-col-2">
<div class="nested-col-1" id="percent-width">Nested Column 1</div>
<div class="nested-col-2">Nested Column 2</div>
</div>
</div>
<div class="wrapper">
<div class="flex-col-1">Column 1</div>
<div class="flex-col-2">
<div class="nested-col-1" id="unit-width">Nested Column 1</div>
<div class="nested-col-2">Nested Column 2</div>
</div>
</div>
CSS
.wrapper {
display: flex;
justify-content: flex-end;
}
.flex-col-2 {
display: flex;
justify-content: flex-end;
}
.nested-col-1 {
/* Overflow is for display purposes. It does not affect the bug. */
overflow: hidden;
}
#percent-width {
width: 0%;
}
#unit-width {
width: 0px;
}
Screenshot
Is there a fix/work-around so that percentage values can be used without creating the extra space?
I am trying to hide the first 3 elements having the class .row inside the block .container.
What I'm doing is hiding all the .row first, and then I am trying to display the first 3 .row by using .row:nth-child(-n+3)
jsfiddle here: http://jsfiddle.net/z8fMr/1/
.row {
display: none;
}
.row:nth-child(-n+3) {
display: block;
}
<div class="content">
<div class="notarow">I'm not a row and I must remain visible</div>
<div class="row">Row 1</div>
<div class="row">Row 2</div>
<div class="row">Row 3</div>
<div class="row">Row 4</div>
<div class="row">Row 5</div>
<div class="row">Row 6</div>
</div>
I have two problems here:
Row 3 is not displayed; am I using nth-child in the wrong way?
Is there a better practice than hiding everything and then creating a specific rule to display the n first elements that I want? Is there a way in CSS to just display the first 3 .row and then hide all the other .row?
You have a .notarow as the first child, so you have to account for that in your :nth-child() formula. Because of that .notarow, your first .row becomes the second child overall of the parent, so you have to count starting from the second to the fourth:
.row:nth-child(-n+4) {
display: block;
}
Updated fiddle
.row {
display: none;
}
.row:nth-child(-n+4) {
display: block;
}
<div class="content">
<div class="notarow">I'm not a row and I must remain visible</div>
<div class="row">Row 1</div>
<div class="row">Row 2</div>
<div class="row">Row 3</div>
<div class="row">Row 4</div>
<div class="row">Row 5</div>
<div class="row">Row 6</div>
</div>
What you're doing is fine.
You don't even need CSS3 selectors:
.row + .row + .row + .row {
display: none;
}
This should work even in IE7.
Updated fiddle
Also, like Giovanni's solution, something like this could also work.
.container > .row:nth-child(3) ~ .row {
/* this rule targets the rows after the 3rd .row */
display: none;
}
I found this answer by Googling "css show first n elements", but the question now seems to be the opposite (hiding first n elements)
:nth-child(n+4)
^ this will work if you're looking for what I was looking for