There's a responsive card pattern I've had to build out in a few projects lately and thought it was worth sharing. After some iterations I think I've found the CSS flexible enough to work for most situations. Feel free to comment if you have some advice or an alternative setup that works as well.
This list that has quite a few features:
Desktop
- List items scale flexibly to fit a configurable number per row
- Items align correctly according to configurable spacing
- The last item doesn't abnormally stretch to fill the container
- Items within a row have equal height
Mobile
- It becomes a horizontal scrolling list
- Configurable and equal padding to the left and right, despite being a scrolling flex container
- There is configurable spacing between items
- The first item is centered on the screen, properly accounting for both internal and external configurable spacing
- All items have equal height
- An item peeks from the right, hinting there are more to see
Here is a Codepen to demonstrate. You can hover over the list to show the spacing. Try view it at different widths and the list should change between mobile scrolling and a desktop grid.
Here is the CSS (SASS actually, but it's easy enough to convert):
ul {
/* Spacing between list items and the container */
--outer-spacing: 48px;
/* Spacing between list items and each other */
--item-spacing: 16px;
/* Items per row in desktop */
--items-per-row: 3;
box-sizing: border-box;
list-style: none;
padding: calc(var(--outer-spacing) - var(--item-spacing) / 2);
display: flex;
flex-flow: row wrap;
width: 100%;
margin: 0 auto;
justify-content: stretch;
/* On mobile this becomes a horizontal scrolling list */
@media (max-width: 600px) {
margin: 0;
padding: var(--outer-spacing);
overflow-x: auto;
flex-wrap: nowrap;
align-items: stretch;
/* Add a space after the last item
https://stackoverflow.com/a/38997047 */
&:after {
display: block;
content: ' ';
flex: 0 0 var(--outer-spacing);
}
}
}
li {
box-sizing: inherit;
display: inline-block; /* or inline-flex */
flex: 0 0 calc(100% / var(--items-per-row) - var(--item-spacing));
margin: calc(var(--item-spacing) / 2);
@media (max-width: 600px) {
flex: 0 0 100%;
margin: 0;
/* Item spacing */
& + & {
margin: 0 0 0 var(--item-spacing);
}
}
}
Cover Photo by Aditya Chinchure on Unsplash
Top comments (0)