I am currently in the process of building a search results page using Flexbox/CSS.
My requirements are that:
- Results should be displayed in a grid
- Responsive, with the number of columns varying from 1-3 based on screen size
- Results should maintain a 1:1 aspect ratio
- Results should will the width of the screen evenly
- Results should wrap
- Certain featured results to occasionally take up the size of 2 x 2 relative the size of the grid - this will only happen once every 20-30 results so no featured results would ever overlap
I am having trouble figuring out the last requirement, and if there's any possible way to make it work using pure CSS without involving JavaScript.
Please note that there are many answers on StackOverflow on how to do this with either colspan or rowspan, but not both. Those answers often involve setting up my grid to load rows from top-to-bottom, rather than left-to-right, which I also don't want.
Current:
What I want (see yellow):
I was able to get everything but my last requirement to work in CSS with the following code:
HTML (simplified):
<div class="products">
<div class="product">
<div class="content">
<img/>
</div>
</div>
<div class="product">
<div class="content">
<img/>
</div>
</div>
<div class="product">
<div class="content">
<img/>
</div>
</div>
[...and so on...]
</div>
SCSS:
// From bootstrap 4:
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
) !default;
@mixin media-breakpoint-up($name) {
@if $name == xs {
@content;
} @else {
@media screen and (min-width: map-get($grid-breakpoints, $name)) {
@content;
}
}
}
// Variables:
$gap: 1rem;
$background-color: white;
// Results:
.products {
// Parent flex layout
display: flex;
flex-wrap: wrap;
align-items: flex-start;
margin: -#{$gap} 0 #{$gap} -#{$gap};
.product {
// Child flex layout
flex: 1 1 auto;
position: relative;
&:before {
content: '';
display: block;
padding-top: 100%;
}
margin: #{$gap} 0 0 #{$gap};
// Background
background-color: $background-color;
background-repeat: no-repeat;
background-position: center;
// Number of columns based on screen size
@include media-breakpoint-up(sm) {
width: calc(100% - #{$gap});
max-width: calc(100% - #{$gap});
}
@include media-breakpoint-up(md) {
width: calc(50% - #{$gap});
max-width: calc(50% - #{$gap});
}
@include media-breakpoint-up(lg) {
width: calc(33.33% - #{$gap});
max-width: calc(33.33% - #{$gap});
}
@include media-breakpoint-up(xl) {
width: calc(25% - #{$gap});
max-width: calc(25% - #{$gap});
}
.content {
// Maintain aspect ratio
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
> img {
// Restrict to size of parent container
max-width:100%;
max-height:100%;
// Center horizontally and vertically
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
}