kenwheeler / slick

the last carousel you'll ever need
kenwheeler.github.io/slick
MIT License
28.47k stars 5.89k forks source link

Equal height slides #179

Closed LMBE closed 10 years ago

LMBE commented 10 years ago

Be nice to have the option to set smaller slides to the height of the tallest.

LMBE commented 10 years ago

3c21f4fd695b25c131acb84018d3586e

kenwheeler commented 10 years ago

Lol! Can't you just do that with css?

LMBE commented 10 years ago

Not unless you use flex box. I've added a separate bit of js to loop through and set heights now. Great plugin btw!

kenwheeler commented 10 years ago

Thanks! Have you tried the top: 0; bottom: 0; trick?

LMBE commented 10 years ago

Not as far as I'm aware! It would if each slide was absolutely positioned but relative is applied inline. Another way would be to use table positioning, but that's just wrong.

kenwheeler commented 10 years ago

Lol

neilbaylorrulez commented 10 years ago

This is deinitely impossible with pure CSS (without flexbox or display table-cell, which each have their own implications) - I am using something like:

function updateRotatorHeight(selector) {
        var maxHeight = -1,
            $items;
        $items = $rotator.find(selector).each(function (i, item) {
            var height;
            item.style.height = '';
            $(item).children().first().css('paddingTop', '');
            if((item.curHeight = item.scrollHeight) > maxHeight) {
                maxHeight = item.curHeight;
            }
        }).each(function (i, item) {
            $(item).css('height', maxHeight).children().first().css('paddingTop', (maxHeight - item.curHeight) / 2);
        });

        rotatorHeight = maxHeight;
    }

//you should debounce this
$window.on('resize', updateRotatorHeight.bind(null, '.slick-track > li'));
akrawchyk commented 10 years ago

I see this in the context of onBeforeChange and onAfterChange has property listHeight which could be useful here. I believe that value corresponds to the height of the slick track, so it could be possible to update that value on multiple browser events and use it to equalize slide heights. For now, I solved this with a similar approach to @neilbaylorrulez:

jQuery('.js-slider').slick(slickOptions).each(function() {
  function equalizeHeights() {
    var $this = $(this);
    var $track = $this.find('.slick-track');
    var $slides = $track.children();

    // layout thrashing here, can't help it since we need to remove
    // min-height to have the layout recalculate the auto height of the
    // slick track
    $slides.css('min-height', '');
    var minSlideHeight = $track.height();
    $slides.css('min-height', minSlideHeight);
  }

  var equalizeSlideHeights = throttle(equalizeHeights.bind(this), 250, true);
  $window.on('DOMContentLoaded load resize', equalizeSlideHeights);
});
phylaxis commented 9 years ago

@akrawchyk I am attempting to use your solution, but get this error:

ReferenceError: Can't find variable: throttle

Do you have a throttle function you created, but is missing from your sample here?

akrawchyk commented 9 years ago

@phylaxis I think you can remove the throttle part and use $window.on('DOMContentLoaded load resize', equalizeHeights); instead if you don't need it. Regardless, here is the throttle function:

// performant throttle implementation http://jsperf.com/throttle
function throttle(fn, frequency) {
  'use strict';

  frequency = frequency || 100;
  var timeout = false;

  return function() {
    if (timeout) {
      return;
    }

    timeout = setTimeout(function() {
      timeout = false;
    }, frequency);

    fn.apply(this, arguments);
  };
}

Hope that helps :)

dewwwald commented 9 years ago

@LMBE Its not table positioning, it is table display properties, and its not bad, its not bulking up markup its only presentation.

lschneiderman commented 8 years ago

I do it this way:

var stHeight = $('.slick-track').height(); $('.slick-slide').css('height',stHeight + 'px' );

codedcontainer commented 8 years ago

@lschneiderman +1

nickfmc commented 8 years ago

@lschneiderman +1 Thanks for that simple solution, one limitation unless inside a function checking for change in the .slick-track height is that is will only size your height on page load not on mobile screen rotation for example.

ramonleenders commented 8 years ago

As said, that will only work on page load. I've used the "setPosition" event from Slick slider here.

$('.your-selector.').on('setPosition', function () { $(this).find('.slick-slide').height('auto'); var slickTrack = $(this).find('.slick-track'); var slickTrackHeight = $(slickTrack).height(); $(this).find('.slick-slide').css('height', slickTrackHeight + 'px'); });

Somehow my code is not formatting, that's why I'm using a blockquote instead.

mateuspaulino commented 8 years ago

Thanks a lot @ramonleenders and @lschneiderman

Jakobud commented 8 years ago

This should be included in the core code as an option. equalizeHeight: true/false or something like that.

JamesIves commented 8 years ago

Completely agreed @Jakobud

leggomuhgreggo commented 8 years ago

I know foIks have mentioned this already, but here's how to get it done with flexbox:

.slick-track{
    display: flex;

    .slick-slide{
        display: flex;
        height: auto;
        align-items: center; //optional
        justify-content: center; //optional
    }
}

pen

Alternatively, the JS @ramonleenders wrote will do the trick.

Hope this is helpful

shaynestatzell commented 7 years ago

Thanks @leggomuhgreggo additionally add flex-direction: column; to .slick-slide if slides contain multiple elements, this will stack them vertically.

rabelBB commented 7 years ago

Thanks @ramonleenders saved me lots of stress with that solution!

leggomuhgreggo commented 7 years ago

fiddle?

ramonleenders commented 7 years ago

Use my Javascript variant instead (posted 2 Apr), and drop the Flexbox code?

wking-io commented 7 years ago

You can have the function reload on page resize using this function. (Only runs when resize stops so it is not pushing a ton of JS calls)

var stHeight = $('.slick-track').height(),
      timeout = false, // holder for timeout id
      delay = 250; // delay after event is "complete" to run callback

function refreshSlickHeight() {
      $('.slick-slide').css('height', stHeight + 'px' );
}

// window.resize event listener
window.addEventListener('resize', function() {
      // clear the timeout
      clearTimeout(timeout);
      // start timing for event "completion"
      timeout = setTimeout(refreshSlickHeight, delay);
});
sabiao commented 7 years ago

front-end, finding job qq group: 365563094

artursopelnik commented 7 years ago

@ramonleenders if you use it with adaptiveHeight together...

var slickSlide = el.find('.slick-slide'); if (slickSlide.filter('.slick-active').length > 1) { slickSlide.css('height', 'auto').css('height', el.find('.slick-track').height() + 'px'); }

ramonleenders commented 7 years ago

Would be nice if a JS solution will be provided within the plugin itself. That way we don't need to search for workarounds NOR write the CSS. Only a boolean in the config and done.

@artursopelnik: the code you provide is working or it isn't? Not sure if you are asking or just suggesting code here haha. And if it does work, it also still works when adaptiveHeight is set to false?

giovannibr commented 7 years ago

Cmon @kenwheeler , it could be done just adding: _.$slideTrack.height(_.$slideTrack.outerHeight()); Inside your Slick.prototype.setDimensions function. Once the parent (track) has a defined height, the children (slides) already have the property height to 100%, and it works like charm. Maybe you can create a property "fixedHeight" that only works with "adaptativeHeight" false.

drducmanh commented 6 years ago

I use litle css to equal height. "align-items:stretch" property apply to parent

.slick-track{
    display: flex;
     align-items: stretch; 
     justify-content: center;
    .slick-slide{
        height: auto;       
    }
}

readmore about flexbox here https://css-tricks.com/snippets/css/a-guide-to-flexbox/

pjatx commented 6 years ago

@ramonleenders Thanks! Using a complex flexbox layout and the pure CSS solutions just blowup my slides.

verybigelephants commented 6 years ago

so will there be an option for this or no?

this is definitely a real word scenario that appears over and over

btw this is nice, but you have to include it in the resize function as well https://gist.github.com/proweb/7c872c02646659e45084c1d51dfc3018

LMBE commented 6 years ago

Hi all, it's me, the okay guy from 2014 and original poster.

After years of using this great plugin and seeing people revisit this post I thought I'd chime back in.

The reality is that Ken adding an equalize heights option to the plugin is an overhead that could be better integrated elsewhere in your code. Instead, setup a global function you can use umpteen times over on different modules and save yourselves some kb's. If you're using foundation use the data-equalize attributes, if you want something more custom try something like this.

After that add a little flexbox spice to your content to vertically align anything you might have inside your banner and the jobs a gooden.

Keep up the great work @kenwheeler I've used this hundreds of times now and it's never let me down

davidallenlewis commented 6 years ago

If you're just trying to vertically centre the slides with each other maybe they don't need to be equal height... maybe all you need it this:

.slick-track { display: flex; align-items: center; }

raffi-ecomz commented 6 years ago

i'm using adaptive height and have a bootstrap collapse element inside a slide. when the element expands the slick isn't changing its height to the new one so only a part of the element is visible. how can i make the whole element be visible?

Preen commented 6 years ago

I used https://www.npmjs.com/package/jquery-match-height and solved it with the help of @ramonleenders code:

$(el).on('setPosition', function () {
    $(el).find('.slick-slide').matchHeight();
})
karkraeg commented 6 years ago

Hi @Preen could you help me out where to insert https://www.npmjs.com/package/jquery-match-height and @ramonleenders code? I’m trying to archive equal height for all slides using SlickSlider in Wordpress (https://de.wordpress.org/plugins/slick-slider/).

Thanks for your help!

flewid-cd commented 6 years ago

@karbecker You need to write the above code but I guess that if you use a plugin it might have its own actions on when/where to trigger and initialize slick-slider. So I would ditch that plugin and just use slick manually with jquery match height.

karkraeg commented 6 years ago

Thanks @flewid-cd! That’s true, the plugin acts as a wrapper to load slick-slider. Will try to use it manually.

jschaefer-workmatrix commented 6 years ago

If you are using griddy slick slider (I am using a responsive setup w/ variable grids calculated by slide count via slidesPerRow) the following may help:

$.fn.equalHeightSlickSlider = function() {
    var
        $slider = $(this),
        $slides = $('.slick-slide', $slider),
        $slideitems = $('> div', $slides),
        slideCount = $slides.first().find('> div').length,
        slideHeight = 0
    ;

    console.log(slideHeight);

    $slides.each(function(){
        slideHeight = Math.max($(this).outerHeight(), slideHeight); 
        slideCount = Math.max(slideCount, $(this).children().length);
    });

    $slideitems.height(slideHeight / slideCount);       

    return $(this);
}

var $slider = $('.slick-slider');

var equalizeSliderHeights = function(){

  var
  frequency = 250,
    timeout = false
    ;

  return function() {
    if (timeout) {
      return;
    }

    timeout = setTimeout(function() {
      timeout = false;
    }, frequency);

    $slider.equalHeightSlickSlider();
  };
};

$(window).on('DOMContentLoaded load resize', equalizeSliderHeights());  

Inspired by @akrawchyk (thanks).

Can also by found here: https://gist.github.com/jschaefer-workmatrix/346ec9f1c6fae6e12408b060a5ed0eb1

m-ret commented 6 years ago

I use a function someone mentioned above and it works cool:

    var handleEqualHeightSlides = function () {
        var slickTrackHeight = $('.slick-track').height();
        $('.slick-slide').css('height', slickTrackHeight  + 'px' );
    }

And if you want to call it on resize or orientation change, there you go:

    var handleEqualHeightSlides = function () {
        var slickTrackHeight = $('.slick-track').height();
        $('.slick-slide').css('height', slickTrackHeight  + 'px' );
    };

    var reInitSlickOnResize = function () {
        $slick.slick('resize');
        handleEqualHeightSlides();
    };

    $(window).on('resize orientationchange', reInitSlickOnResize);
JurajVajda commented 5 years ago

The flexbox solution doesn't work in Edge, also some vanilla JS solution would be nice - if still anyone knows what that is :)

mikemfleming commented 5 years ago

@JurajVajda here is how i would go about a vanilla solution. It's definitely missing something in the makeEqualHeight function because the carousel seems to resize itself. But it's basically how I would go about it.

    var productCarousel = document.getElementById('productCarousel')
    var productCarouselHeight = productCarousel.offsetHeight
    var productCarouselSlides = Array.prototype.slice.call(
        document.getElementsByClassName('productCarousel-slide')
    )

    productCarouselSlides.forEach(makeEqualHeight)

    function makeEqualHeight (element) {
        element.style.height = `${productCarouselHeight}px`
    }
JurajVajda commented 5 years ago

Thanks..ended up using Es6 Js class for it in the end.

aronmoshe-m commented 5 years ago

I used https://www.npmjs.com/package/jquery-match-height and solved it with the help of @ramonleenders code:

$(el).on('setPosition', function () {
    $(el).find('.slick-slide').matchHeight();
})

Thanks, @Preen. This was exactly what I needed.

abstractpenguin commented 5 years ago

Updating @leggomuhgreggo's code with .slick-initialized got it to work for me:

.slick-initialized .slick-track{
    display: flex;

    .slick-slide {
        display: flex;
        height: auto;
        align-items: center; //optional
        justify-content: center; //optional
    }
}

Original codepen

yyanmak commented 5 years ago

.slick-initialized .slick-track{ display: flex; .slick-slide { display: flex; height: auto; align-items: center; //optional justify-content: center; //optional } }

Somehow this one not working for me, after I added in, the height is equal now, but the width become not 100%

peterlockhart commented 4 years ago
.slick-track{
  display: flex !important;
}

.slick-slide {
  height: inherit !important;
}

This did the trick for me.

andrewhawkes commented 4 years ago

I've worked around this loads of times with Flexbox but I've run into an issue today again and my usual fix didn't work.

This SCSS ended up being enough for me:

  .slick-track{
    display: flex;

    .slick-slide {
      height: auto;

      > div {
        height: 100%;
      }

    }
  }
csakiistvan commented 4 years ago

@andrewhawkes thank you, it is works.

ff-marcos commented 4 years ago

@andrewhawkes Thank you!