Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Add a fade plugin #39

Closed
dmorda opened this issue Dec 23, 2019 · 48 comments · Fixed by #871
Closed

[Feat]: Add a fade plugin #39

dmorda opened this issue Dec 23, 2019 · 48 comments · Fixed by #871
Assignees
Labels
feature request New feature or request plugin Issue is related to plugins resolved This issue is resolved

Comments

@dmorda
Copy link

dmorda commented Dec 23, 2019

Love the carousel and was able to get it working right away. The one thing that I need that it doesn't provide is a way to have a scroll option for single/multiple slides and a fade option to handle next/previous transition when it's just showing a single slide at a time.

Is that something that has been requested before?

@davidjerleke
Copy link
Owner

davidjerleke commented Dec 24, 2019

Hi Damon (@dmorda),
Merry Christmas, and thank you for opening this issue 🎅.

About:

A way to have a scroll option for single/multiple slides

Would you mind explaining what you mean a bit more in detail or provide an example? Because I need more information to answer this question, but I'm going to take a guess and ask if you've checked out the slidesToScroll option? Here's a CodeSandbox that demonstrates how you can achieve this.

The answer to your question about the fade option is no, it has not been requested yet. I'm not sure what you mean by fade option because it can be done in many different ways so would you mind explaining a bit further?
I'm guessing here too but maybe you can achieve this by hooking onto the classname toggling for selected slides? Please have a look at the documentation here.

Thank you in advance!

Best,
David

@davidjerleke davidjerleke added the feature request New feature or request label Dec 24, 2019
@dmorda
Copy link
Author

dmorda commented Dec 24, 2019

Thanks for the quick response and a Merry Christmas to you as well. What I'm trying to achieve is a Fade effect , as an example view this page and search for the word "Fade". That will provide an example of what I'm trying to accomplish.

Let me know if that helps!

@davidjerleke
Copy link
Owner

davidjerleke commented Dec 25, 2019

Hi again Damon (@dmorda),
Thank you for the clarification, it helps 👍.

The vision for Embla is carousels that move in a fluid and natural manner. The assumption here is that the carousel should be scrollable, and that doesn't play well with fade sliders that don't feel natural when dragging/swiping. This is why a fade option is not a part of the Embla vision and won't be incorporated into the Embla core.

But with that said, I've setup a CodeSandbox example for you, where I've created the fade effect just by tweaking some CSS.

I hope that you'll find it useful!

Best,
David

@davidjerleke davidjerleke added the not planned Won't be investigated unless it gets lots of traction label Dec 25, 2019
@dmorda
Copy link
Author

dmorda commented Dec 25, 2019

That small tweak now lets me re-use Embla for both the fade version of a carousel and the normal sliding version. Thanks so much, happy holidays!

@davidjerleke
Copy link
Owner

Hi Damon (@dmorda),

I’m glad to hear that 🙂. Thank you and happy holidays to you too!

Kindly,
David

@vntw
Copy link

vntw commented Apr 25, 2021

Hey @davidjerleke, sorry for digging up an old issue but I found your sandbox for a fade slider (thanks!). While playing around with it, I noticed that every slide is seen as "in view" by the slider and subsequently gets the selectedClass when the window is resized, meaning no more slides.

I added a reInit and resize listener to the sandbox here to fix this. If this is the correct change, it might make sense to update your original sandbox for future users that may find this?

Happy to hear your thoughts on this 🙂 Thanks!

@davidjerleke
Copy link
Owner

Hi @vntw,

Thank you for noticing this.

I added a reInit and resize listener to the sandbox here to fix this. If this is the correct change, it might make sense to update your original sandbox for future users that may find this?

Your suggestion does the trick, nice work 👍. I've updated the original CodeSandbox. I also added the skipSnaps: false; option because skipping slides when vigorous dragging occurs might lead to confusing UX for fade sliders. From the docs:

Allow the carousel to skip scroll snaps if it's dragged vigorously. Note that this option will be ignored if the dragFree option is set to true.

Thank you for your efforts!

Best,
David

@silllli
Copy link
Contributor

silllli commented Sep 20, 2021

Thank you @davidjerleke!

@davidjerleke
Copy link
Owner

davidjerleke commented Dec 5, 2021

Reopening this:

As of v.6 it’s possible to provide plugins to Embla. A Fade plugin will be added in the future:

  • #703

@davidjerleke davidjerleke reopened this Dec 5, 2021
@davidjerleke davidjerleke added upcoming A feature or bug fix is on its way for this issue and removed not planned Won't be investigated unless it gets lots of traction labels Dec 5, 2021
@davidjerleke davidjerleke removed the upcoming A feature or bug fix is on its way for this issue label Apr 9, 2022
@aKandzior
Copy link

Great solution with the fade effect!

I have an improvement suggestion for the CSS used in the SandBox.

I was applying the example CSS code to my project and noticed that since positon: absolute; is used to stack the slides, it is also required to set the slide height on the .embla__container.

In my case, I wanted the container to automatically use the height as defined by the slide markup itself. By changing the CSS to use display: grid; as per the code below, the height of the slides is still defined by the slide side markup.

.embla__container {
  transform: none !important; /* override Embla */
  display: flex;
}

.embla__slide {
  transform: none !important; /* required if loop is active */
  flex: 0 0 auto;
  width: 100%;
  height: 250px;
  opacity: 0;
  transition: opacity 1s;
  counter-increment: embla;
  border-radius: 0.5rem;
  font-size: 5rem;
}

.embla--is-ready .embla__container {
  display: grid;
}

.embla--is-ready .embla__slide {
  grid-row: 1;
  grid-column: 1;
}

@SunpieAgency
Copy link

SunpieAgency commented Mar 6, 2023

Great solution with the fade effect!
I have an improvement suggestion for the CSS used in the SandBox [...]```

I think best practice would be to do something like this:

.embla.fade.ready .embla__slide { position: absolute; } .embla__slide.is-selected { position: relative; }

This requires the classes module but works perfect for me. Height of the container is automatically adapted to your selected slide.

@davidjerleke davidjerleke added the plugin Issue is related to plugins label Nov 27, 2023
@davidjerleke davidjerleke changed the title Incorporate a fade option [Feat]: Incorporate a fade option Jan 25, 2024
@vettloffah
Copy link

The sandbox linked multiple times here doesn't load anymore. Does anyone have a copy of the code?

@davidjerleke
Copy link
Owner

davidjerleke commented Feb 27, 2024

@davidjerleke davidjerleke changed the title [Feat]: Incorporate a fade option [Feat]: Add a fade plugin Mar 2, 2024
@davidjerleke davidjerleke added the upcoming A feature or bug fix is on its way for this issue label Mar 2, 2024
@sarussss
Copy link
Contributor

Hi @davidjerleke.
I think we can modify function positionSlides

  function positionSlides() {
    const { scrollSnaps, slideRegistry } = emblaApi.internalEngine()
    const slides = emblaApi.slideNodes()
    scrollSnaps.forEach((scrollSnap, scrollSnapIndex) => {
      const slidesInSnap = slideRegistry[scrollSnapIndex]
      slidesInSnap.forEach((slideIndex) => {
        slides[slideIndex].style.transform = `translateX(${scrollSnap}px)`
      })
    })
  }

Replace

  function positionSlides() {
    emblaApi.slideNodes().forEach((slide, slideIndex) => {
      slide.style.transform = `translateX(${slideIndex * -100}%)`
    })
  }

What do you think, is this possible?
Demo

@davidjerleke
Copy link
Owner

@sarussss thank you for your input 👍. My solution works with slides that are less than 100% wide too - They will be centered and also works when slidesToScroll: 'auto'. That's the motivation for my solution.

@sarussss
Copy link
Contributor

sarussss commented Apr 26, 2024

@davidjerleke thank you for your feedback. I think it's not really necessary because when using fade, we will adjust the width in the parent element and fade only works well when there is only 1 slide in each viewport.

Don't care too much about these things, these are just some of my thoughts, because I don't understand Embla as deeply as you do, so if anything is incorrect, please forgive me.

P/S: Thanks for your hard work, the fade plugin is awesome.

Demo

@ItsFrankieD
Copy link

Out of curiosity, will the fade duration be adjustable? For both autoplay and next / previous trigger, I feel as though a duration adjustment is almost a necessity. Great work thus far!

@davidjerleke
Copy link
Owner

@ItsFrankieD yes, the default duration option for the carousel constructor changes the fade duration.

@davidjerleke
Copy link
Owner

Do you think it'll be possible to apply the lazy rendering solution discussed here while using this new plugin? Rendering only the slides in view is especially useful for performance when dealing with heavy content like images (note how in your example app above, all images are loaded even though only one is shown), custom components, or even videos where you want the player to be destroyed when it goes out of view.

@meirroth yes. The plugin will expose the slide opacity states with a method called opacities(). Not sure that opacities will be the final method name when released though so feel free to suggest a name. Let's say you want to load images for all slides that have an opacity greater than 0. You will be able to achieve that like this:

function loadImages(emblaApi) {
  const opacities = emblaApi.plugins().fade.opacities();

  opacities.forEach((opacity, snapIndex) => {
    if (opacity === 0) return // Not visible so bail here
    const slidesInSnap = emblaApi.internalEngine().slideRegistry[snapIndex];

    slidesInSnap.forEach((slideIndex) => { /* Load image for slideIndex */ })
  })
} 

emblaApi.on('scroll', loadImages);

@meirroth
Copy link
Contributor

meirroth commented May 5, 2024

@davidjerleke Thank you! I look forward to using this plugin on our homepage 😃

@davidjerleke
Copy link
Owner

davidjerleke commented May 7, 2024

@meirroth, @sarussss, @ItsFrankieD, @sitoexpress, @walton-alex, @AndreiMotinga, @mil920, @HIT2022 and anyone else interested, feel free to test the fade plugin here.

Let me know how it goes.

@mil920
Copy link

mil920 commented May 7, 2024

@davidjerleke Thanks i tested it and i adapted it to ts and put it on my shadcn carousel and it work well.

@davidjerleke
Copy link
Owner

@mil920 thanks for letting me know! The package is written in TypeScript so that won't be a problem once officially released.

@meirroth
Copy link
Contributor

meirroth commented May 7, 2024

Do you think it'll be possible to apply the lazy rendering solution discussed here while using this new plugin? Rendering only the slides in view is especially useful for performance when dealing with heavy content like images (note how in your example app above, all images are loaded even though only one is shown), custom components, or even videos where you want the player to be destroyed when it goes out of view.

@meirroth yes. The plugin will expose the slide opacity states with a method called opacities(). Not sure that opacities will be the final method name when released though so feel free to suggest a name. Let's say you want to load images for all slides that have an opacity greater than 0. You will be able to achieve that like this:

function loadImages(emblaApi) {
  const opacities = emblaApi.plugins().fade.opacities();

  opacities.forEach((opacity, snapIndex) => {
    if (opacity === 0) return // Not visible so bail here
    const slidesInSnap = emblaApi.internalEngine().slideRegistry[snapIndex];

    slidesInSnap.forEach((slideIndex) => { /* Load image for slideIndex */ })
  })
} 

emblaApi.on('scroll', loadImages);

@davidjerleke I tested again the Fade plugin you shared, and even tried it with the Vue wrapper and works perfectly.
Regarding the lazy rendering solution above, would it make sense from API perspective for slidesInView to return only the slides that is currently visible while using this plugin, as supposed to returning ALL the slides like it does now? I think that will keep the lazy rendering solution consistent between Fade and not Fade carousels.
https://stackblitz.com/edit/embla-carousel-nuxt-fade-lazy?file=app.vue

@davidjerleke
Copy link
Owner

davidjerleke commented May 10, 2024

Regarding the lazy rendering solution above, would it make sense from API perspective for slidesInView to return only the slides that is currently visible while using this plugin, as supposed to returning ALL the slides like it does now? I think that will keep the lazy rendering solution consistent between Fade and not Fade carousels.

@meirroth thanks for your ideas! I've updated the work in progress plugin here with the following:

Cleanup function

It's now in place so calling emblaApi.destroy() cleans up the inline styles and removes the event listeners that the fade plugin is using.

Slides in view

I was able to shift slides with 0 opacity out of view using transform and it doesn't seem to glitch at all. Try it out if you want and if you agree, this recreates parts of the core Embla functionality which is nice:

// Logging slides in view will work
emblaApi.on('slidesInView', (emblaApi) => {
  console.log(emblaApi.slidesInView())
})

However, I'm not sure it makes sense to try recreating the inViewThreshold option. Because when shifting slides with 0 opacity out of view and > 0 in view they will disappear/appear entirely in contrast to a scrolling carousel where slides gradually scroll into view.

@meirroth
Copy link
Contributor

However, I'm not sure it makes sense to try recreating the inViewThreshold option. Because when shifting slides with 0 opacity out of view and > 0 in view they will disappear/appear entirely in contrast to a scrolling carousel where slides gradually scroll into view.

@davidjerleke Not sure I follow 😬 But my lazy load implementation above works with your update, and 100% matches non fade carousels which is neat!

@sarussss
Copy link
Contributor

Hi @davidjerleke
Effect fade only work on desktop.
Mobile will run as a slide effect as usual.
Is there any way to achieve that?

@davidjerleke
Copy link
Owner

davidjerleke commented May 11, 2024

@sarussss I don’t have this problem. Are you sure you’ve double checked everything in your code? Try the app view link here. It’s working as expected for me.

@sarussss
Copy link
Contributor

Hi @davidjerleke.
I mean I want to do that:

  • Desktop: Use fade effect.
  • Mobile: Use effect slide.

It's not a bug, I want to do it with embla, but I don't know how to do it.

@davidjerleke
Copy link
Owner

@sarussss use the breakpoints option:

const emblaNode = document.querySelector('.embla')
const emblaApi = EmblaCarousel(emblaNode, { loop: true }, [Fade({
  breakpoints: {
    '(min-width: 768px)': { active: false }
  }
})])

@sarussss
Copy link
Contributor

@davidjerleke thank of ton.

@davidjerleke
Copy link
Owner

@sarussss don’t forget to grab the latest updates from the work in progress React sandbox. Just copy the plugin code from the sandbox and replace it with your current plugin code.

@davidjerleke
Copy link
Owner

Only code cleanup and creating the documentation page for the fade plugin left to do before release. All features done ✅.

davidjerleke added a commit that referenced this issue May 13, 2024
davidjerleke added a commit that referenced this issue May 15, 2024
davidjerleke added a commit that referenced this issue May 16, 2024
davidjerleke added a commit that referenced this issue May 16, 2024
@davidjerleke davidjerleke added resolved This issue is resolved and removed upcoming A feature or bug fix is on its way for this issue labels May 16, 2024
@silllli
Copy link
Contributor

silllli commented May 16, 2024

Awesome, thank you!

@davidjerleke
Copy link
Owner

davidjerleke commented May 17, 2024

Released in 8.1.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request plugin Issue is related to plugins resolved This issue is resolved
Projects
None yet
Development

Successfully merging a pull request may close this issue.