Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Last active February 24, 2022 05:26
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save OliverJAsh/7f29d0fa1d35216ec681d2949c3fe8b7 to your computer and use it in GitHub Desktop.
Save OliverJAsh/7f29d0fa1d35216ec681d2949c3fe8b7 to your computer and use it in GitHub Desktop.
Flexbox gutters

Flexbox gutters

Problem

  • We use flexbox for our layout.
  • We want to add horizontal and vertical gutters inbetween these items.
  • Items wrap according to contents (flex-wrap: wrap), therefore we can't decide when/where to apply gutters using breakpoints.

Solution

In the future this will be possible using the {row,column}-gap (longhand) and gap (shorthand) properties. However this is not currently well supported.

A discussion of this problem can be seen at https://stackoverflow.com/questions/20626685/better-way-to-set-distance-between-flexbox-items and http://www.heydonworks.com/article/flexbox-grid-finesse#gutter-tactics.

The most common solution involves padding on the items and negative margins on the container, to offset any extraneous padding.

https://jsfiddle.net/OliverJAsh2/qm7tbvso/1/

Note that the choice of margin and padding, and the direction in which these are applied, is significant.

If we used margins for our gutter items instead of padding:

If we specified vertical gutters using top instead of bottom, previous content may be inaccessible due to overlap: https://jsfiddle.net/OliverJAsh2/xqm5h17r/6/.

Known issues

@gavinmcfarland
Copy link

I came across this gist on caniuse.com after I was looking for a way to conditionally add support for flex gap. The biggest issue I'm predicting is what happens when support is available for flex gap, but we have no way to check for it? If we use any of the workarounds and support flex gap at the same time both with will be applied without a way to conditionally check for support.

I created a PostCSS flex gap polyfill which surprisingly does a lot without affecting much of the authoring process. There are a few limitations but with someone with more JavaScript knowledge than me, we may be able to implement some fixes to overcome these limitations.

It doesn't use any surplus wrapper divs and the author doesn't need to do anything special for it to work. However, I need to find a way to not apply it when flex gap is supported.

https://github.com/limitlessloop/flex-gap-polyfill

I would very much welcome your thoughts, ideas possible alternates to provide a more reliable solution to this. At the moment it's quite advanced and it will allow to even use nested containers with gaps applied, however to make it more production-ready I might be able to offer an option to enable/disable this.

@blvz
Copy link

blvz commented Mar 27, 2020

@limitlessloop since @supports is broken for these kind of situations, I guess the only solution would be abusing queries to make it vendor/version specific. A hacky solution, nonetheless, that also can't be added beforehand.

/* firefox 64+  @media pointer + -moz-user-select: none */
/* safari 13+   flow-root + -webkit-initial-letter */
/* chrome 79+   width max() */
@media (pointer: coarse), (pointer: fine) {
  @supports (-moz-user-select: none) or
            ((display: flow-root) and (-webkit-initial-letter: 1)) or
            (width: max(1px, 2px)) {
    /* resets polyfill code and apply native solution */
  }
}

@gavinmcfarland
Copy link

Hi @blvz that's a good workaround. I heard recently that they may introduce a temporary property of flex-gap to help detect support. Fingers crossed they implement this :).

@Ambient-Impact
Copy link

@blvz @limitlessloop Looking at the support table for flexbox gap, it was only added in Safari 14.1 desktop and 14.8 on iOS. My first thought is that logical properties (i.e. margin-inline-start, etc.) are a much better check for Safari and Chrome, as they're either at or a bit after flexbox gap so you don't risk assuming gap works when in fact it does not. The one problem with this is that Firefox has logical property support going back farther than the others, so that can be fixed a bit more accurately by wrapping the whole thing in a check for the prefers-reduced-motion media feature, which was added in Firefox 63, the same version that added flexbox gap support.

@media (prefers-reduced-motion: no-preference), (prefers-reduced-motion: reduce) {
  @supports (margin-inline-start: 1em) {
    display: flex;
    flex-wrap: wrap;
    gap: 1em;
  }
}

I haven't actually tested this, so let me know if I've overlooked something. Browser comparison I used to figure this out.

@gavinmcfarland
Copy link

Hey @Ambient-Impact sounds promising let me know if you get around to testing it. Would be great to add to my flex gap polyfill if it works.

@Ambient-Impact
Copy link

@limitlessloop Alas I don't have access personally to iOS devices, and too broke for BrowserStack, but I'll see if I know anyone with one to borrow.

@gavinmcfarland
Copy link

BrowserStack is free for open source projects. I've just applied so I'll let you know if they accept and I get chance to test it.

@Ambient-Impact
Copy link

@limitlessloop Good to hear, thanks.

@blvz
Copy link

blvz commented Nov 17, 2021

@limitlessloop @Ambient-Impact yup! it did work on iOS 15.

@Ambient-Impact
Copy link

@limitlessloop @Ambient-Impact yup! it did work on iOS 15.

So it worked correctly to detect older versions of Safari that don't support it?

@blvz
Copy link

blvz commented Nov 18, 2021

@Ambient-Impact I tested on iOS 15 and it worked. I also tested on Safari 13 (macOS Mojave) and it didn't work.

@Ambient-Impact
Copy link

@Ambient-Impact I tested on iOS 15 and it worked. I also tested on Safari 13 (macOS Mojave) and it didn't work.

By "didn't work", do you mean that the gap property wasn't applied but the detection worked? According to Can I Use, it was only added in Safari desktop 14.1, so 13 wouldn't support it.

@Antosik
Copy link

Antosik commented Nov 30, 2021

supports combination for the Gap for display: flex support.
According to Can I Use, it is supported in Firefox 63, Safari 14.1, Chrome 84.

@supports (text-transform: full-size-kana) or (translate: 10px) or (content-visibility: auto)) {
    display: flex;
    flex-wrap: wrap;
    gap: 1em;
}

Why that combination

  • Firefox 63 64 - Didn't find the newly added CSS properties in FF v63, so I used a text-transform: full-size-kana that was added in FF v64 (Can I Use)
  • Safari 14.1 - CSS individual transform properties were added in Safari v14.1 (Can I Use)
  • Chrome 84 85 - As in a Firefox - didn't find anything related to CSS, so I used a content-visibility that was added in Chrome v85 (Can I Use)

@blvz
Copy link

blvz commented Dec 3, 2021

@Ambient-Impact yes, I meant the gap property wasn't applied.

@Ambient-Impact
Copy link

@blvz Thaks!

@Antosik Thanks for the more accurate detection. The one thing I would suggest is that if you want to target Firefox 63 exactly, it added support for the prefers-reduced-motion media feature, but that would require finding some property that Firefox supported at that time to the @supports block so that it gets used by Firefox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment