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

Variable height on vertical carousel? #1803

Open
richatsupersonicplayground opened this issue Oct 9, 2015 · 31 comments · May be fixed by #3565
Open

Variable height on vertical carousel? #1803

richatsupersonicplayground opened this issue Oct 9, 2015 · 31 comments · May be fixed by #3565

Comments

@richatsupersonicplayground

Hey,

I've been using Slick for a year or so on various projects, and it is truly amazing! However I've hit a bit of a problem on a vertical carousel.

It's a leaderboard showing scores - I need to show six at a time out of about 30, hence vertical is the way I need to go, although it's the first time I've used this setting.

The problem I've got is responsive - on large desktop each item starts out as 60px height each, dictated by a square image, but with text on one line, so the overall height of the container is 360px (6x60). The elements don't have a fixed height, it's the image the makes it 60px.

But when I scale down to mobile, and the text starts to wrap onto two lines making each item taller than 60px, the carousel doesn't resize - it stays at 360px, with that height measurement being applied by the plugin.

It's as if there needs to be a 'variableHeight' setting, similar to the variableWidth setting for horizontal carousels.

Is there a way around this currently?

@ahmadalfy
Copy link
Collaborator

Can you please create a jsfiddle showing the behavior?

@florianpilz
Copy link

I'm highly interested myself, since we need this functionality for a client. Will provide a fiddle next week.

@ethanclevenger91
Copy link
Contributor

ethanclevenger91 commented Apr 15, 2016

Yeah, seems to be same issue as at least #1852. I've already provided a fiddle here: https://jsfiddle.net/yypesh3d/7/

@wtran
Copy link

wtran commented Jul 19, 2016

vote for this feature

@iampuma
Copy link

iampuma commented Mar 24, 2017

Currently having this workaround:

// Calculate the heighest slide and set a top/bottom margin for other children.
// As variableHeight is not supported yet: https://github.com/kenwheeler/slick/issues/1803
var maxHeight = -1;
$('.slick-slide').each(function() {
  if ($(this).height() > maxHeight) {
    maxHeight = $(this).height();
  }
});
$('.slick-slide').each(function() {
  if ($(this).height() < maxHeight) {
    $(this).css('margin', Math.ceil((maxHeight-$(this).height())/2) + 'px 0');
  }
});

@joeRob2468
Copy link

@iampuma That workaround fixed my problem perfectly. Thanks! Hopefully something along those lines gets worked into the official branch at some point.

@IMPLATRIX
Copy link

IMPLATRIX commented Apr 17, 2018

Figured out how to let slick slider calculate the proper offset: currently slick uses the outer height of the first slider item and multiplies it with the slide index on each slide (getLeft function).

We've extended the getLeft function letting it count the sum of the outer heights of all previous slides:

if (_.options.vertical === false) {
    targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
} else {
     //targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
     var curIndex = _.currentSlide;
     var sum = 0;
     for (var i = 0; i < curIndex; i++) {
         sum = sum + _.$slides.eq(i).outerHeight(true);
    }
    targetLeft = (sum * -1) + verticalOffset;
}

@fleps
Copy link

fleps commented May 3, 2018

@IMPLATRIX I tested your code on a simple vertical slider where some slides have different height and didn't worked, while also breaking the slide change animation (i'm using centerMode and focusOnSelect)

@IMPLATRIX
Copy link

@fleps just tested it and it's also working with centerMode and focusOnSelect. You can see our workaround in action here: http://dev.riwa-architekten.de/innenarchitektur/einfamilienhaus-in-duesseldorf-urdenbach.html
Our animation also got broken and we fixed it with adding an extra CSS transition to our slider's .slick-track:

.vertical-image-slider .slick-track { transition: .5s linear; }

@fleps
Copy link

fleps commented May 3, 2018

@IMPLATRIX ah now I see. My case is different than yours, I have a vertical slider that is almost 100% height but my slides are not using the entier height, they little boxes and I show 3 at time clipped in the center, it's a totally different scenario =)

@whimsicaldreamer
Copy link

@iampuma is it possible to make your workaround responsive? On smaller viewports the margin becomes too big for contents with smaller heights.

@lucasskywalker
Copy link

slick

@zonky2
Copy link

zonky2 commented Sep 7, 2018

@lucasskywalker I try your code

        if (_.options.vertical === false) {
            targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
        } else {
-            targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
+            verticalOffset = 0;
+            for (var i = 0; i < slideIndex; i++) {
+                verticalOffset += _.$slides.eq(i).outerHeight(true);
+            }
+            console.log((verticalOffset * -1));
+            targetLeft = (verticalOffset * -1);
        }

but doesn´t work - I have different gaps at top of slider

zwischenablage04

The code from here #1803 (comment) slide the first item and after them "jump" the netxt item at the top position :(

At another page https://www.gut-cert.de/home.html I use the carouFredSel (https://github.com/Codeinwp/carouFredSel-jQuery) - works... but I´ll change all sliders to slick

with the slick slider the problem is known since 2015 - a fix would be great

@lucasskywalker
Copy link

Hi! Can you send me the code you use in your project? proweb.090@gmail.com

@zonky2
Copy link

zonky2 commented Sep 9, 2018

@lucasskywalker I sended a email to you

@lucasskywalker
Copy link

lucasskywalker commented Sep 9, 2018

slick

@lucasskywalker
Copy link

lucasskywalker commented Sep 9, 2018

add new fixed for slick options => infinite = true, centerMode: false;

@zonky2
Copy link

zonky2 commented Sep 13, 2018

@lucasskywalker thanks for your code - are you doing PR, or should I do PR?

btw: is the project still supported by @kenwheeler ? over 700 issues are open and there are almost 150 PRs?

/*
        if (_.options.vertical === false) {
            targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
        } else {
            targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
        }
*/
// NEW
        if (_.options.vertical === false) {
              targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
            } else {
              verticalOffset = 0;
        
              for (let i = 0; i < slideIndex; i++) {
                verticalOffset += _.$slides.eq(i).outerHeight(true);
              }
        
              if (_.options.infinite === true) {
                Array.from(_.$slideTrack[0].children).forEach((slide) => {
                  if (slide.dataset.slickIndex < 0) {
                    verticalOffset += $(slide).outerHeight(true);
                  }
                });
              }
        
              targetLeft = verticalOffset * -1;
            }
//

zonky2 added a commit to zonky2/slick that referenced this issue Sep 16, 2018
@zonky2 zonky2 linked a pull request Sep 16, 2018 that will close this issue
@zonky2
Copy link

zonky2 commented Sep 16, 2018

PR: #3565

@alexcracea
Copy link

@zonky2 using your solution, thanks!

One issue discovered - the animation is broken whenever I try going "prev" over a slide with more height than the rest

@SahilMepani
Copy link

@zonky2 Your code throws syntax error in IE11.

@lucasskywalker
Copy link

lucasskywalker commented Nov 9, 2018

@zonky2 Your code throws syntax error in IE11.

Because i use forEach ("forEach" doesn't work in IE11 => rewrite to "for")!!! And learn JS (ES6)

@SahilMepani
Copy link

SahilMepani commented Nov 15, 2018

In case anyone looking for IE11 support for #1803 (comment). This is the updated code.

if (_.options.vertical === false) {
  targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
} else {
  verticalOffset = 0;

  for (let i = 0; i < slideIndex; i++) {
    verticalOffset += _.$slides.eq(i).outerHeight(true);
  }

  if (_.options.infinite === true) {
    var $slideCounts = Array.prototype.slice.call( _.$slideTrack[0].children );
    for (var i = 0; i < $slideCounts.length; i++) {
      if ($slideCounts[i].dataset.slickIndex < 0) {
        verticalOffset += $($slideCounts[i]).outerHeight(true);
      }
    }
  }

  targetLeft = verticalOffset * -1;
}

@kirkbross
Copy link

I have a vertical slider which gets taller if slide(s) get taller from text wrapping.

I'd like to keep the overall height fixed, even if the slides inside change height randomly on resize. I'm using center mode and infinite and it just doesn't seem do all the dynamic math for heights -- i.e. keeping the center slide centered even if the slide below or above got taller from text wrapping.

My only work around is to use fixed heights for all slides and ellipsis the text so nothing ever wraps.

Also, I don't think @kenwheeler maintains this anymore, though I am grateful for this wonderful, free tool.

@syinz1
Copy link

syinz1 commented Dec 18, 2019

/ Calculate the heighest slide and set a top/bottom margin for other children.
// As variableHeight is not supported yet: https://github.com/kenwheeler/slick/issues/1803
var maxHeight = -1;
$('.slick-slide').each(function() {
  if ($(this).height() > maxHeight) {
    maxHeight = $(this).height();
  }
});
$('.slick-slide').each(function() {
  if ($(this).height() < maxHeight) {
    $(this).css('margin', Math.ceil((maxHeight-$(this).height())/2) + 'px 0');
  }
});

Thanks man! this work for vertical mode!

@evanmwillhite
Copy link

These approaches above didn't work for me to have variable height slides, but I was able to get it to determine height correctly in my scenario by changing the following sections of code:

if (_.options.vertical === false) {
  if (_.options.centerMode === true) {
      _.$list.css({
          padding: ('0px ' + _.options.centerPadding)
      });
  }
} else {
  // OLD
  // _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow);
  // NEW
  let $verticalHeight = 0;
  _.$slides.each(function() {
    $verticalHeight = $verticalHeight + $(this).outerHeight(true);
  });
  _.$list.height(Math.ceil($verticalHeight));
  // END NEW
  if (_.options.centerMode === true) {
      _.$list.css({
          padding: (_.options.centerPadding + ' 0px')
      });
  }
}
if (_.options.vertical === false && _.options.variableWidth === false) {
  _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
  _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length)));

} else if (_.options.variableWidth === true) {
  _.$slideTrack.width(5000 * _.slideCount);
} else {
  _.slideWidth = Math.ceil(_.listWidth);
  // OLD
  // _.$slideTrack.height(Math.ceil($verticalHeight));
  // NEW
  let $verticalHeight = 0;
  _.$slides.each(function() {
    $verticalHeight = $verticalHeight + $(this).outerHeight(true);
  });
  _.$slideTrack.height(Math.ceil($verticalHeight));
}

@Chousse
Copy link

Chousse commented Oct 21, 2020

None of your solutions work fine, if you want to have true adaptive height with a vertical:true you have to add this code in "setDimensions" method (line 2042):
if(_.options.adaptiveHeight === true){ _.$list.height(_.$slides.eq(_.currentSlide).outerHeight(true)); } else { _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow); }
also add adaptiveHeight:true with vertical:true.
you can add in CSS "transition: height 200ms ease; on slick-list for smoothing resize

@gfdesign
Copy link

@Chousse would you mind share your solution into JSFiddle or Codepen playground? :)

@Wiejeben
Copy link

Wiejeben commented Mar 9, 2021

In case someone is using Vue!

First make the VueSlickCarousel component available in $ref by adding ref="carousel"

After that apply the following to the script of your component:

mounted() {
    window.addEventListener('resize', this.recalculateHeight);

    this.$nextTick(this.recalculateHeight);
},
destroyed() {
    window.removeEventListener('resize', this.recalculateHeight);
},
methods: {
    recalculateHeight() {
        const slides = this.$refs.carousel.$refs.innerSlider.$refs.track.$children;

        // Reset
        slides.forEach(slide => slide.$el.style.height = 'auto');

        // Calculate
        const highest = Math.max(...slides.map(component => component.$el.getBoundingClientRect().height))

        // Apply
        slides.forEach(slide => slide.$el.style.height = highest);
    },
}

@suinly
Copy link

suinly commented Sep 9, 2021

Hi. I seem to have found a solution for slides of different heights. You need to add the following code to slick.js in getLeft function after line 1155:

if (_.options.vertical === true && _.options.variableHeight === true) {
    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow);
    targetLeft = targetSlide[0] ? targetSlide[0].offsetTop * -1 : 0;
}

And add the parameter to the carousel settings:

variableHeight: true

Who can test and pull request, please do so.

@YulZhak
Copy link

YulZhak commented Feb 3, 2023

Currently having this workaround:

// Calculate the heighest slide and set a top/bottom margin for other children.
// As variableHeight is not supported yet: https://github.com/kenwheeler/slick/issues/1803
var maxHeight = -1;
$('.slick-slide').each(function() {
  if ($(this).height() > maxHeight) {
    maxHeight = $(this).height();
  }
});
$('.slick-slide').each(function() {
  if ($(this).height() < maxHeight) {
    $(this).css('margin', Math.ceil((maxHeight-$(this).height())/2) + 'px 0');
  }
});

I had vertical slider.
For me in was need to add equal margin bottom for every slide item I need. So I added it by css.

.slider-item { margin-bottom: 40px; }

This I added to my custom script.
var maxHeight = -1; $('.your-slider .slick-slide').each(function() { if ($(this).height() > maxHeight) { maxHeight += $(this).height()+40; } }); $('.your-slider .slick-list').css('min-height', maxHeight-40 + 'px');

Sadly that we stiil don't have the options for this...

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

Successfully merging a pull request may close this issue.