glidejs / glide

A dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more
https://glidejs.com
MIT License
7.34k stars 770 forks source link

Auto Height #236

Open kirillminiaev opened 6 years ago

kirillminiaev commented 6 years ago

Is there an option to set the slider to auto-scale height with contents (similar to Adaptive Height in Slick Slider)? Right now, a gallery of different-sized images defaults to being as tall as the tallest image.

jedrzejchalubek commented 6 years ago

It's not build-in, you have to write a custom component. Here is a example code which I used in one of my recent projects (note: it uses an imagesloaded package). May be helpful:

import imagesloaded from 'imagesloaded'

export default function (Glide, Components, Events) {
  const AUTOHEIGHT = {
    mount () {
      Components.Html.track.style.transition = 'height 0.2s ease-in-out'

      imagesloaded(Components.Html.track, () => {
        AUTOHEIGHT.set()
      })
    },

    set () {
      Components.Html.track.style.height = `${Components.Html.slides[Glide.index].offsetHeight}px`
    }
  }

  Events.on(['run', 'resize'], () => {
    AUTOHEIGHT.set()
  })

  return AUTOHEIGHT
}
kirillminiaev commented 6 years ago

@jedrzejchalubek thank you! I am using Glide.js without a packager as a straight up script inclusion in my Wordpress site. How would I refactor your code to support my environment?

minlare commented 5 years ago

@jedrzejchalubek - Any chance of putting this in as a component which can be enabled/disabled via settings?

jenniferhail commented 5 years ago

Adding this before glide.mount(); worked for me:

glide.on('build.after', function() {
    var slideHeight = $('.glide__slide--active').outerHeight();
    var glideTrack = $('.glide__track').outerHeight();
    if (slideHeight != glideTrack) {
        var newHeight = slideHeight;
        $('.glide__track').css('height', newHeight);
    }
});

glide.on('run.after', function() {
    var slideHeight = $('.glide__slide--active').outerHeight();
    var glideTrack = $('.glide__track').outerHeight();
    if (slideHeight != glideTrack) {
        var newHeight = slideHeight;
        $('.glide__track').css('height', newHeight);
    }
})
FalkoJoseph commented 5 years ago

Adding this before glide.mount(); worked for me:

glide.on('build.after', function() {
  var slideHeight = $('.glide__slide--active').outerHeight();
  var glideTrack = $('.glide__track').outerHeight();
  if (slideHeight != glideTrack) {
      var newHeight = slideHeight;
      $('.glide__track').css('height', newHeight);
  }
});

glide.on('run.after', function() {
  var slideHeight = $('.glide__slide--active').outerHeight();
  var glideTrack = $('.glide__track').outerHeight();
  if (slideHeight != glideTrack) {
      var newHeight = slideHeight;
      $('.glide__track').css('height', newHeight);
  }
})

Works perfectly! Thanks @jenniferhail .

SimeonGriggs commented 4 years ago

Vanilla JS example if anyone's interested...

const carousel = document.querySelector('.glide');

if (carousel) {
    const glideCarousel = new Glide('.glide');

    // Automated height on Carousel build
    glideCarousel.on('build.after', function () {
        glideHandleHeight();
    });

    // Automated height on Carousel change
    glideCarousel.on('run.after', function () {
        glideHandleHeight();
    });

    // Mount!
    glideCarousel.mount({
        type: 'carousel',
    });

    // Resize height
    function glideHandleHeight() {
        const activeSlide = document.querySelector('.glide__slide--active');
        const activeSlideHeight = activeSlide ? activeSlide.offsetHeight : 0;

        const glideTrack = document.querySelector('.glide__track');
        const glideTrackHeight = glideTrack ? glideTrack.offsetHeight : 0;

        if (activeSlideHeight !== glideTrackHeight) {
            glideTrack.style.height = `${activeSlideHeight}px`;
        }
    }
}
kirillminiaev commented 4 years ago

@SimeonGriggs & @jenniferhail thank you! Just finished another project where I needed to refer back to this thread.

FWIW, if you want to make the height transition a little smoother, you can also add the following CSS code (after implementing your JS suggestions):

.glide__track {
    transition: height 250ms ease-in-out;
}
leandroruel commented 4 years ago

if anyone here is strugling with a error after using SimeonGriggs code (which works fine) is because you have to pass options object to glide instance as second parameter instead of inside mount method:

const carousel = document.querySelector('.glide');

if (carousel) {
    const glideCarousel = new Glide('.glide', {
        type: 'carousel',
    });

    // Automated height on Carousel build
    glideCarousel.on('build.after', function () {
        glideHandleHeight();
    });

    // Automated height on Carousel change
    glideCarousel.on('run.after', function () {
        glideHandleHeight();
    });

    // Mount!
    glideCarousel.mount();

    // Resize height
    function glideHandleHeight() {
        const activeSlide = document.querySelector('.glide__slide--active');
        const activeSlideHeight = activeSlide ? activeSlide.offsetHeight : 0;

        const glideTrack = document.querySelector('.glide__track');
        const glideTrackHeight = glideTrack ? glideTrack.offsetHeight : 0;

        if (activeSlideHeight !== glideTrackHeight) {
            glideTrack.style.height = `${activeSlideHeight}px`;
        }
    }
}
BrettC04 commented 3 years ago

if anyone wants to apply it in 'Slider' type glider.

const blogSlider = document.querySelector('.glide');

if (blogSlider) {
    const glideSlider = new Glide('.glide', {
        type: 'slider',
        perView: 4,
        rewind: false,
        bound: true,
        gap: 10
    });

    // Automated height on Carousel build
    glideSlider.on('build.after', function () {
        glideHandleHeight();
    });

    // Automated height on Carousel change
    glideSlider.on('run.after', function () {
        glideHandleHeight();
    });

    // Mount!
    glideSlider.mount();

    // Resize height
    function glideHandleHeight() {
        const glideTrackHeight = document.querySelector('.glide__track');
        const glideSlide = document.querySelectorAll('.glide__slide');
        var i;
        for (i = 0; i < glideSlide.length; i++) {
            glideSlide[i].style.height = glideTrackHeight.offsetHeight + 'px';
        }
    }
}
jonathanmoore commented 3 years ago

I recently ran into the same situation where I want to adapt the height of the slideshow to the image/content. The one thing that bugged me about the scripts above is that it calculated the height based on .glide__slide--active which is added quite delayed once the slider settles into place.

Building on a component taken from https://github.com/glidejs/glide/issues/401 I created a new ResizeSlider component that applies a new .glide__slide--next-active class instantly to the next slide you're transitioning to, and updates the track height based on that newly added class.

import { siblings } from '@glidejs/glide/src/utils/dom';

const classes = {
  glideSlideNextActive: 'glide__slide--next-active',
};

const selectors = {
  glideSlideNextActive: '.glide__slide--next-active',
  glideTrack: '.glide__track',
};

function ResizeSlider(Glide, Components, Events) {
  var Component = {
    mount() {
      this.changeActiveSlide();
      this.updateTrackHeight();
    },

    changeActiveSlide() {
      let slide = Components.Html.slides[Glide.index];
      slide.classList.add(classes.glideSlideNextActive);

      siblings(slide).forEach((sibling) => {
        sibling.classList.remove(classes.glideSlideNextActive);
      });
    },

    updateTrackHeight() {
      console.log('update track height');

      const activeSlide = document.querySelector(
        selectors.glideSlideNextActive
      );
      const activeSlideHeight = activeSlide ? activeSlide.offsetHeight : 0;

      const glideTrack = document.querySelector(selectors.glideTrack);
      const glideTrackHeight = glideTrack ? glideTrack.offsetHeight : 0;

      console.log(`Active slide: ${activeSlide} activeSlideHeight: ${activeSlideHeight}`)

      if (activeSlideHeight !== glideTrackHeight) {
          glideTrack.style.height = `${activeSlideHeight}px`;
      }
    },
  };

  Events.on('run', () => {
    Component.changeActiveSlide();
    Component.updateTrackHeight();
  });

  return Component;
};

const slider = new Glide(this.container, {
  type: 'carousel',
  animationDuration: 350
});

slider.mount({
  ResizeSlider: ResizeSlider,
});
shestakov-vladyslav commented 3 years ago

+++

vincurekf commented 2 years ago

Thank you @jonathanmoore, exactly what I needed. One thing I'd add, if you have more that one slider on a page, this will scale only the fist one.

Small changes are needed to make it work with multiple sliders:

Replace:

const activeSlide = document.querySelector(
    selectors.glideSlideNextActive
);

with:

const activeSlide = document.querySelector(
    Glide.selector + ' ' + selectors.glideSlideNextActive
);

and this:

const glideTrack = document.querySelector(selectors.glideTrack);

with:

const glideTrack = document.querySelector(Glide.selector + ' ' + selectors.glideTrack);

Now it will select the currently changed slider and resize it.

arsors commented 2 years ago

I needed an auto height option that supports multiple sliders as well as multiple slides in a single slider (perView >= 2). But also perView: 1 is supported. Here is my result:

Add this function:

function GlideAutoHeight(Glide, Components, Events) {
    const Component = {
        mount() {
            if (!Glide.settings.autoHeight) return;
            Components.Html.track.style.transition = 'height 200ms ease-in-out';
            this.updateTrackHeight();
        },

        updateTrackHeight() {
            if (!Glide.settings.autoHeight) return;

            const activeSlides = Components.Html.slides.filter((slide, index) => {
                return (index >= Glide.index && index <= (Glide.index-1) + Glide.settings.perView);
            });

            const newMaxHeight = activeSlides.reduce((maxHeight, slide) => {
                return Math.max(maxHeight, slide.offsetHeight);
            }, 0);

            const glideTrack = Components.Html.track;
            if (newMaxHeight !== glideTrack.offsetHeight) {
                glideTrack.style.height = `${newMaxHeight}px`;
            }
        },
    };

    Events.on('run', () => {Component.updateTrackHeight();});
    Events.on('update', () => {Component.updateTrackHeight();});
    Events.on('resize', () => {Component.updateTrackHeight();});

    return Component;
}

Add autoHeight as option (Default is false). Add GlideAutoHeight as extension.

document.querySelectorAll('.glide').forEach(glider => {
    new Glide(glider, {
        perView: 2,
        autoHeight: true,
    }).mount({
        GlideAutoHeight: GlideAutoHeight
    });
});

Cheers 🥂

SorinSu commented 1 year ago

@arsors it is not working entirely. You need to rework the activeSlides

return (index >= Glide.index && index <= (parseInt(Glide.index-1) + parseInt(Glide.settings.perView)));

arsors commented 1 year ago

@arsors it is not working entirely. You need to rework the activeSlides

return (index >= Glide.index && index <= (parseInt(Glide.index-1) + parseInt(Glide.settings.perView)));

@SorinSu In which case Glide.index and Glide.settings.perView is not an integer?

SorinSu commented 1 year ago

@arsors when index is 0 it returns "-11" type: slider perView: 1

arsors commented 1 year ago

@SorinSu Mh.. i don't have a test project anymore. I ask my self why the line should not like this: return (index >= parseInt(Glide.index) && index <= (parseInt(Glide.index-1) + parseInt(Glide.settings.perView))); Can you provide me a test project? Or a codepen?