Who doesn’t like getting new CSS features supported in browsers? Nobody, I think. Recently, lots of folks are excited for the support of gap
property for flexbox in Chromium browsers (Chrome, Edge). The gap
property is an attempt to have the same property for CSS grid and flexbox. It will be responsible for the spacing (gutters) between columns and rows.
Before digging into the details, I want to explain briefly how grid-gap
or gap
works. Simply, it adds spacing between columns and rows. See the video below:
Initially, the gap was done using grid-gap
.
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
However, it’s being replaced by gap
property instead. And it works like the below:
.wrapper {
/* CSS grid styles */
gap: 1rem;
}
No need to use the prefix grid-
.
Shedding light on the problem
I created a very abstract demo of two wrappers, grid
and flex
, respectively. I used gap
to define the spacing between the child items.
<div class="grid-wrapper">
<div class="item"></div>
<!-- 5 more items -->
</div>
<div class="flex-wrapper">
<div class="item"></div>
<!-- 5 more items -->
</div>
/********* CSS Grid *********/
.grid-wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
/********* CSS Flexbox *********/
.flex-wrapper {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.flex-wrapper .item {
flex: 0 0 calc(33% - 1rem);
}
As you see, the gap works perfectly for both CSS grid and flex - on the browsers that support them. However, for the non-supporting browsers like old versions of Chrome and Safari, the result will look like the figure below.
Browser support for Grid and Flexbox gap
Even though the property is the same, but the support for it differs in grid vs flexbox. This is confusing. Consider the below support tables.
Flexbox gap
support
Grid gap
support
For more information on the support, please check flexbox gap and grid gap on CanIUse.
The flexbox gap
is fairly new, so how we can use it in real-life projects? Taking into consideration that we should detect the support for it first.
Detecting support for flexbox gap
For CSS flexbox, the gap
property was first supported in Firefox, and then Chromium announced that the property is now supported. Great news, but I have an important question.
How can we detect if the gap
for flexbox is supported or not?
You might be thinking about using CSS @supports
? I’m sorry to let you know that it’s not possible to detect gap
with CSS @supports
rule. As per the discussion in this CSSWG thread, it seems that there is no way to detect that.
/* This won't work.. */
@supports (gap: 10px) {
.element {
display: flex;
gap: 10px;
}
}
The above won’t work.
While reading the thread, I noticed some interesting and possible suggestions for that problem.
Combine using with
A suggestion by @Dan503 is to combine two conditions.
@supports (gap: 10px) with (
display: flex
) {
div {
display: flex;
gap: 10px;
}
}
Combine using and
A suggestion by Bramus.
@supports (display: flex; gap: 1em) {
.warning {
display: none;
}
}
In the meantime, it’s not possible to detect if the gap
for flexbox is supported or not.
Using Javascript
For now, we have no option but to use Javascript to detect if flexbox gap
is supported. I got the idea of creating a wrapper and two child items, and then to apply flex
and gap
on them. Thankfully, I found that this is already done by someone smarter than me in Modernizr. Thanks to Chris Smith.
function checkFlexGap() {
// create flex container with row-gap set
var flex = document.createElement("div")
flex.style.display = "flex"
flex.style.flexDirection = "column"
flex.style.rowGap = "1px"
// create two, elements inside it
flex.appendChild(document.createElement("div"))
flex.appendChild(document.createElement("div"))
// append to the DOM (needed to obtain scrollHeight)
document.body.appendChild(flex)
var isSupported = flex.scrollHeight === 1 // flex container should be 1px high from the row-gap
flex.parentNode.removeChild(flex)
return isSupported
}
The script works in a way that it creates a flexbox wrapper with flex-direction: column
, and row-gap: 1px
. If the height of the content is equal to 1px
, this means that flexbox gap
is supported.
See the visual explanation below.
As per MDN:
The Element.scrollHeight read-only property is a measurement of the height of an element’s content, including content not visible on the screen due to overflow.
By getting the scrollHeight
value of the parent element, we can check if the flexbox gap
is supported or not.
Adding flexbox gap
fallback
I tried to check if the support detection for flexbox gap
is added in Modernizer or not, but it looks like something is off in the latest build.
Usually, Modernizr adds a class to the <html>
to indicate that a property is supported or not. Given that we already have the function, we can check if it’s true
or false
, and add a class to the <html>
element based on that.
if (checkFlexGap()) {
document.documentElement.classList.add("flexbox-gap")
} else {
document.documentElement.classList.add("no-flexbox-gap")
}
Now, we can use the class .flexbox-gap
to enhance an experience and use the gap
property. Here is a simple example:
.flex-wrapper {
display: flex;
flex-wrap: wrap;
}
.flex-wrapper .item {
flex: 0 0 calc(33.33% - 1rem);
margin-left: 1rem;
margin-bottom: 1rem;
}
/* If flexbox gap is supported, do the following */
.flexbox-gap .flex-wrapper {
gap: 1rem;
}
.flexbox-gap .flex-item {
margin-left: 0;
margin-bottom: 0;
}
You can check all the code above in this demo
I’m writing an ebook
I’m excited to let you know that I’m writing an ebook about Debugging CSS.
If you’re interested, head over to debuggingcss.com and subscribe for updates about the book.