Embla-carousel: Breakpoints

Created on 13 Mar 2021  路  9Comments  路  Source: davidcetinkaya/embla-carousel

Breakpoints feature

I've been getting some indications that some users would like to see some kind of built-in solution for changing options based on different breakpoints.

Do you have any suggestions about how this should be implemented?
What kind of solution would you prefer?

Please share!

I'm going to ping some people here to get this discussion started. I hope you guys don't mind. @xiel, @nikrowell, @openscript, @RectoVersoDev, @readeral.

Cheers,
David

feature request resolved

Most helpful comment

Hey David (@davidcetinkaya) -

Nice work on the 6% bundle size reduction! I like Robin's (@openscript) idea of simply including that in the examples vs adding to the library. Happy to help set up an example if you'd like.

All 9 comments

I'd vote for leaving this out in favor of using window.matchMedia and reInit when breakpoint differences are needed. One of the biggest appeals of Embla is how lightweight and flexible it is.

Eventually I also did it with window.matchMedia as @nikrowell suggested. Maybe it's a good idea to write together a little guide, which outlines how to achieve it with Embla.

Thanks for the input @nikrowell and @openscript. Just to give you guys more context: With the latest v4.2.0 release, I managed to reduce the bundle size with 6% without sacrificing code readability.

We could either just celebrate that, or add a convenient breakpoint feature without adding back those 6%. My guess is that it could add like 2% back or so. What are your thoughts about this?

Hey David (@davidcetinkaya) -

Nice work on the 6% bundle size reduction! I like Robin's (@openscript) idea of simply including that in the examples vs adding to the library. Happy to help set up an example if you'd like.

Hi Nik (@nikrowell),

Thank you. I'm interested in seeing an example of how you would solve it. Please share your solution here if you don't mind. And I will share what I have in mind regarding a built-in solution for this. We can then compare and see the pros and cons (not just bundle size) of a built-in solution vs extending the carousel manually. Does that make sense?

Thank you in advance.

Best,
David

@davidcetinkaya makes sense - I may not get to this for a few days. Definitely interested in seeing your solution if you already had something in mind!

Hi Nik (@nikrowell), and everyone else interested in this.

No worries Nik, take your time 馃檪.

The idea I have is quite unconventional i think. Generally I'm not an advocate of unconventional solutions, but sometimes I think you need to dare to do something different if it brings great value to users. So please don't dismiss it just because it's unconventional 馃檪.

Some background

As of v4.2.0, with the new auto slide gap detection feature, Embla Carousel gives users a new level of freedom and convenience when setting up their carousels.

Declaring slide sizes for different breakpoints is really easy:

.embla__slide {
  flex: 100%; /* Default slide covers 100% of the viewport */
}
@media (min-width: 768px) {
  .embla__slide {
    flex: 50%; /* Breakpoint SM slide covers 50% of the viewport */
  }
}

...and declaring gaps for different breakpoints is equally easy:

.embla__slide {
  margin-right: 10px; /* Default slide gap */
}
@media (min-width: 768px) {
  .embla__slide {
    margin-right: 20px; /* Breakpoint SM gap */
  }
}

The missing part

Embla will pick up all changes in slide sizes and gaps because it automatically calls embla.reInit() when the window is resized. My suggestion, although unconventional, is to offer the same convenience for changing options, right were your CSS is.

The solution

Flickity has a feature called watchCss which allows users to enable/disable the carousel in your CSS using a psuedo selector:

You can enable and disable Flickity with CSS. watchCSS option watches the content of :after of the carousel element. Flickity is enabled if :after content is 'flickity'.

The solution I have in mind is to place options inside the content attribute of a pseudo element like so:

.embla:before {
  display: none;
  content: '{
    "slidesToScroll": 1,
    "draggable": true
  }';
}
@media (min-width: 768px) {
  .embla:before {
    content: '{
      "slidesToScroll": 2,
      "draggable": false
    }';
  }
}

The idea here is to merge the options provided in the pseudo element with the options you pass to the EmblaCarousel initializer:

const options = {
  containScroll: 'trimSnaps',
  loop: false
}
const embla = EmblaCarousel(emblaNode, options /* <-- merge with this */)

The code for parsing the pseudo options is pretty slim and straightforward:

function parsePsuedoOptions(containerNode) {
  let options = {};
  try {
    const json = window.getComputedStyle(containerNode, ":before").content;
    options = JSON.parse(json.slice(1, -1).replace(/\\/g, ""));
  } catch (error) {}
  return options;
}

As you can see, no need at all to use window.matchMedia or similar. And if some users don't want to use this and make use of window.matchMedia together with embla.reInit(), this will still be possible.

Let me know what you think.

Best,
David

@davidcetinkaya interesting solution! Given the small impact to bundle size, I'm not at all against this if you're learning towards including it. My idea with using window.matchMedia was pretty basic - create an instance and listener, and call reInit on breakpoint changes, merging options as needed. Not as simple / flexible when considering multiple breakpoints....

Thanks for discussing this Nik (@nikrowell), much appreciated 馃檪.

I've released the pseudo breakpoint options as an experimental feature with v4.3.0. If it turns out to be not appreciated at all, I'll consider removing it in the next major release.

馃敆 Link to docs

Cheers
David

Was this page helpful?
0 / 5 - 0 ratings

Related issues

patrickhuang94 picture patrickhuang94  路  3Comments

iamkevingreen picture iamkevingreen  路  3Comments

krikienoid picture krikienoid  路  6Comments

davemullenjnr picture davemullenjnr  路  5Comments

th-km picture th-km  路  5Comments