Reputation: 391
I have a page that is 50/50 wide. The left half has a row with six divs. Criteria:
My codepen: https://codepen.io/johnsontroye/pen/zzNVBr
<body>
<div class="container">
<div class="column" style="margin-right: 20px">
<div class="flex-container">
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L1
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L2
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L3
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L4
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L5
</div>
</div>
</div>
<div class="flex-item">
<div class="flex-item-inner">
<div class="flex-item-inner-content">
L6
</div>
</div>
</div>
</div>
</div>
<div class="column" style="margin-left: 20px; border: 1px black solid; height: 500px">
Other stuff
<div>
</body>
.container {
display: flex;
flex-direction: row;
padding: 25px;
border: 2px red solid;
}
.column {
width: 100%;
height: 100%;
float: left;
}
.flex-container {
padding: 0;
font-size: 0;
border: 1px solid black;
box-sizing: border-box;
}
.flex-item {
position: relative;
display: inline-block;
height: 0;
width: 100%;
padding-top: 100%;
border: 1px black solid;
font-size: 20px;
color: black;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
@media (min-width: 480px) {
.flex-item {
width: 33.3333%;
padding-top: 33.3333%;
}
}
@media (min-width: 768px) {
.flex-item {
width: 16.6666%;
padding-top: 16.6666%;
}
}
.flex-item-inner {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin-right: 25px;
background: white;
border: 1px solid red;
box-sizing: border-box;
}
.flex-item-inner-content {
border: 1px solid orange;
}
.flex-item:last-child .flex-item-inner {
margin-right: 0;
color: green;
}
Upvotes: 0
Views: 4140
Reputation: 87191
The main trick here is to make the div
a square.
Normally one set a width
, the height
to 0
and a padding
that equals to the width
.square {
height: 0;
width: 33%;
padding-bottom: 33%;
background: lightgray;
}
<div class="square">
<div>
Content
</div>
</div>
Now, when we add display: flex
, we can't use padding
with percent (Firefox bug) and we can't use height with percent since we used height: 0
.
To overcome these issues when can use viewport units vw
instead, and with that we can also use height
instead of padding
to keep it squared.
So instead of setting a width like this, calc((100% / 6) - 10px);
, to spread 6 items equally with a gutter about 10px wide, we use viewport units like this calc(( (50vw - 65px) / 6) - 10px);
The 50vw
is half the browser width, the 65px
is the sum of the container
's left/right padding, 50px
, plus the 15px
gutter between the columns
.
This also allows us to skip the extra flex-item-inner
element, skip using position: absolute
on the content
element, and, as we didn't use percent for the height on the flex-item
, we can do like this to center the content
.flex-item-content {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
And the end result is this
Stack snippet
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 25px;
border: 2px red solid;
}
.column {
flex-basis: calc(50% - 15px);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.flex-item {
position: relative;
flex-basis: calc(( (50vw - 65px) / 6) - 10px);
height: calc(( (50vw - 65px) / 6) - 10px);
background: white;
border: 1px solid red;
overflow: hidden;
}
.flex-item-content {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.flex-item:last-child .flex-item-content {
color: green;
}
.column .other {
padding: 15px;
border: 1px solid black;
padding-bottom: 35px;
}
.column.left .other {
margin-top: 10px;
}
.column.right .other:nth-child(n+2) {
margin-top: 10px;
}
@media (max-width: 768px) {
.flex-item {
flex-basis: calc(( (50vw - 65px) / 3) - 10px);
height: calc(( (50vw - 65px) / 3) - 10px);
}
.flex-item:nth-child(n+4) {
margin-top: 12px;
}
}
@media (max-width: 480px) {
.flex-item {
flex-basis: calc(( (50vw - 65px) / 2) - 10px);
height: calc(( (50vw - 65px) / 2) - 10px);
}
.flex-item:nth-child(n+3) {
margin-top: 15px;
}
}
<div class="container">
<div class="column left">
<div class="flex-container">
<div class="flex-item">
<div class="flex-item-content">
L1
</div>
</div>
<div class="flex-item">
<div class="flex-item-content">
L2
</div>
</div>
<div class="flex-item">
<div class="flex-item-content">
L3
</div>
</div>
<div class="flex-item">
<div class="flex-item-content">
L4
</div>
</div>
<div class="flex-item">
<div class="flex-item-content">
L5<br>L5
</div>
</div>
<div class="flex-item">
<div class="flex-item-content">
L6
</div>
</div>
</div>
<div class="other">
Other stuff - left
</div>
</div>
<div class="column right">
<div class="other">
Other stuff - right
</div>
<div class="other">
Other stuff - right
</div>
</div>
</div>
Upvotes: 3
Reputation: 2914
Only in the latest browsers? CSS Grid to the rescue! It's got great support in the latest versions. You may need some vendor prefixes still; check on CanIUse for the details.
Here it is as a fork: https://codepen.io/jackmakesthings/pen/MoJNNV
.container {
display: flex;
flex-direction: row;
padding: 25px;
border: 2px red solid;
}
.column {
width: 100%;
height: 100%;
float: left;
}
.grid-row {
display: grid;
grid-gap: 10px; /* set this to whatever space you need between boxes */
grid-template-columns: repeat(6, 1fr); /* grid autosizes 6 columns */
}
.row-item {
grid-column: 1 / 7; /* to span the whole row */
border: 1px solid;
padding: 10px;
}
.grid-item {
position: relative;
border: 1px solid;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
/* This is a nifty trick for getting those fixed aspect ratio boxes. */
.grid-item:before {
content: '';
float: left;
width: 0;
height: 0;
padding-bottom: 100%;
}
.grid-item:after {
display: table;
clear: both;
}
/* Responsive grid changes? Sure! */
@media (max-width: 1000px) {
/* We just have to change the grid template: */
.grid-row {
grid-template-columns: repeat(3, 1fr);
}
/* Unexpected thing I ran into - you also have to change this, or the grid stays big enough to accommodate the old 6-column-sized row-item. Makes sense, but vexed me for a minute! */
.row-item {
grid-column: 1 / 4;
}
}
<div class="container">
<div class="column" style="margin-right: 20px">
<div class="grid-row">
<div class="grid-item">L1</div>
<div class="grid-item">L2</div>
<div class="grid-item">L3</div>
<div class="grid-item">L4</div>
<div class="grid-item">L5</div>
<div class="grid-item">L6</div>
<div class="row-item">some other thing</div>
<div class="row-item">and another</div>
</div>
</div>
<div class="column" style="margin-left: 20px; border: 1px black solid; height: 500px">
Other stuff
<div>
Upvotes: 0
Reputation: 484
This is doable with some fairly simple code, as long as the parent column's width is consistent at 50%-ish, and that the space between squares don't have to be strictly equal to a certain value. The vw
(viewport width percentage) unit allows for a consistent size to be applied to both width and height of an element.
Here is an example that I boiled down to the fewest elements, and some notes help to move it in to your codebase.
.flex-item
's height
and flex-basis
(third value of flex
) to get a size you like.padding
or margin
values are needed because justify-content: space-between;
helpfully calculates that for us.line-height
equal to the height
of .flex-item
would allow for an inner element with display: inline-block;
and vertical-align: middle;
to be centred..column {
width: 48vw;
height: 48vw;
padding: 1vw;
border: 1px solid #ccc;
}
.flex-container {
display: flex;
flex-flow: row;
justify-content: space-between;
}
.flex-item {
height: 6vw;
line-height: 6vw;
text-align: center;
border: 1px solid #ccc;
flex: 0 0 6vw;
}
<div class="column">
<div class="flex-container">
<div class="flex-item">
L1
</div>
<div class="flex-item">
L2
</div>
<div class="flex-item">
L3
</div>
<div class="flex-item">
L4
</div>
<div class="flex-item">
L5
</div>
<div class="flex-item">
L6
</div>
</div>
</div>
Upvotes: 0