Slick carousel adaptive height not working when showing 2 slides - javascript

I am building a website with some sliders and using Slick for that. Usually, in regards to the slides when I am showing 1 slide at a time the adaptive height works but when showing 2 slides at the same time it doesn't work. Here is the issue replicated in a JSFiddle.
Here is the JavaScript:
var options = {
slidesToShow: 2,
slidesToScroll: 2,
dots: true,
arrows: false,
dotsClass: 'slick-dots slick-dots-black',
adaptiveHeight: true,
};
$('.slider').slick(options);
I've been googling this issue and it seems other people have similar issues but I couldn't find a solution.
Any ideas appreciated!

Yeah it does seem that slick will only allow adaptiveHeight on single sliding carousels.
In the docs on adaptiveHeight it says this...
Enables adaptive height for single slide horizontal carousels.
It's funny I never expected this behaviour from slick, I assumed adaptive height worked in all cases. But apparently not.
This is a little bit hacky but might cover a solution for your website to enable adaptive height on multi slide sliders. This essentially finds the tallest slides currently on display and adds a height to the .slick-list. Using css transition on this element gives the slick adaptiveHeight effect.
Also we have a .on('resize') event which re-runs the slider height checks incase the slide content is fluid and the slide heights change responsively.
Read my comments in script to see what is going on...
Also see fiddle here... https://jsfiddle.net/joshmoto/1a5vwr3j/
// my slick slider options
var options = {
slidesToShow: 2,
slidesToScroll: 2,
dots: true,
arrows: false,
dotsClass: 'slick-dots slick-dots-black',
adaptiveHeight: true,
};
// my slick slider as constant object
const mySlider = $('.slider').on('init', function(slick) {
// on init run our multi slide adaptive height function
multiSlideAdaptiveHeight(this);
}).on('beforeChange', function(slick, currentSlide, nextSlide) {
// on beforeChange run our multi slide adaptive height function
multiSlideAdaptiveHeight(this);
}).slick(options);
// our multi slide adaptive height function passing slider object
function multiSlideAdaptiveHeight(slider) {
// set our vars
let activeSlides = [];
let tallestSlide = 0;
// very short delay in order for us get the correct active slides
setTimeout(function() {
// loop through each active slide for our current slider
$('.slick-track .slick-active', slider).each(function(item) {
// add current active slide height to our active slides array
activeSlides[item] = $(this).outerHeight();
});
// for each of the active slides heights
activeSlides.forEach(function(item) {
// if current active slide height is greater than tallest slide height
if (item > tallestSlide) {
// override tallest slide height to current active slide height
tallestSlide = item;
}
});
// set the current slider slick list height to current active tallest slide height
$('.slick-list', slider).height(tallestSlide);
}, 10);
}
// when window is resized
$(window).on('resize', function() {
// run our multi slide adaptive height function incase current slider active slides change height responsively
multiSlideAdaptiveHeight(mySlider);
});
body {
background: skyblue;
margin: 0;
padding: 20px;
}
.slick-list {
transition: all .5s ease;
}
.aslide {
background: yellow;
}
<div class="slider">
<div class="aslide">1</div>
<div class="aslide">2<br/>2<br/>2</div>
<div class="aslide">3<br/>3<br/>3<br/>3<br/>3</div>
<div class="aslide">4<br/>4<br/>4</div>
<div class="aslide">5</div>
<div class="aslide">6<br/>6<br/>6</div>
<div class="aslide">7<br/>7<br/>7<br/>7<br/>7</div>
<div class="aslide">8<br/>8</div>
<div class="aslide">9<br/>9<br/>9<br/>9<br/>9<br/>9</div>
<div class="aslide">10<br/>10<br/>10</div>
<div class="aslide">11</div>
<div class="aslide">12<br/>12</div>
</div>
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js"></script>

Related

Slick Slider - slick-current class is not moving when navigating if all slides are shown

I have a simple slider with Slick.js (https://kenwheeler.github.io/slick/)
The slider arrows are hidden by default when all slide-items are shown because its not necessary to slide. So i use custom arrows with a click function that call .slick('slickNext') or .slick('slickPrev') and its working fine. But my issue is when all slide-items are shown and I call the functions to slide next or previous the .slick-current class on the active slide-item is not switching anymore.
My goal is that the .slick-current class still moves when I click the buttons.
An example: https://jsfiddle.net/0nprbj95/2/ Appreciate your help!
One solution to ensure that Slick is moving the .slick-current class is to hold the state of the current slide index and then use the slick('goTo') method to force Slick to move the class to this slide.
This may not give exactly the behavior that you want because Slick will still shift the slides in its "viewport", but you might be able to tweak the behavior from there.
$(document).ready(function(){
var currentSlide = 0;
var numSlides = document.getElementsByClassName('slide-item').length;
$('.slider-items-wrapper').slick({
slidesToShow: 4,
slidesToScroll: 1,
mobileFirst: true,
infinite: true,
arrows: false,
});
$('.button-prev').click(function(){
// wrap to last slide when clicked on first slide
currentSlide = (currentSlide - 1 + numSlides) % numSlides;
$('.slider-items-wrapper').slick('goTo', currentSlide);
});
$('.button-next').click(function(){
// wrap to first slide when clicked on last slide
currentSlide = (currentSlide + 1) % numSlides;
$('.slider-items-wrapper').slick('goTo', currentSlide);
});
});
Full JSFiddle: https://jsfiddle.net/c3amxzk1/1/

"bxslider jquery" change the slide mode at specified width

like the title i'm using bxslider at my website, actually i'm using vertical thumbnail slide now, but the problem is, it's look ugly when at mobile width, so i want to change it like normal slider with arrow. can you help me how to do that? here is the things i want:
1. at normal using vertical thumb slide
2. when the width triggered at specify width, the thumb is hide (maybe display none at css)
3. Do destroyslider for stopping the vertical thumb slider and change it to normal slider with arrow
4. when the width is normal again, it will switch again to vertical thumb slider
ok here is my jquery:
var mainImage;
$(window).load(function() {
mainImage = $('.product-gallery').bxSlider({
infiniteLoop: false,
hideControlOnEnd: true,
pager: false,
controls: false,
auto: false,
minSlides: 1,
maxSlides: 1,
moveSlides: 1,
mode: 'fade',
adaptiveHeight: true
});
$('.product-gallery-thumbs ul').bxSlider({
infiniteLoop: false,
hideControlOnEnd: true,
pager: false,
auto: false,
minSlides: 4,
maxSlides: 4,
moveSlides: 1,
slideWidth: '100%',
mode: "#{options['product_thumbnail_direction']}",
slideMargin: 10,
onSliderLoad: function(currentIndex) {
$('.product-gallery-thumbs ul li').eq(0).addClass('active')
}
});
$('.product-gallery-thumbs ul li').each(function() {
$(this).click(function() {
$(this).addClass('active').siblings().removeClass('active');
mainImage.goToSlide($(this).index());
});
});
});
when do destroy :
mainImage.destroySlider();
here is normal slider with arrow:
mainImage.bxSlider({
mode: 'fade',
captions: true,
slideWidth: 600
});
UPDATE :
I try to did this, when do destroy is work, but when switching to normal arrow slider it doesn't work. Hope you guys can help me fix this
$(document).ready(function(){
setMaxWidth(767px);
mainImage.destroySlider();
function setMaxWidth(767px) {
mainImage.bxSlider({
mode: 'fade',
captions: true,
slideWidth: 600
});
})
bx.reloadSlider() Method
The method destroySlider() returns bxSlider as it was initially so don't use it if you want to change bxSlider after a reload, instead use reloadSlider(). Besides the obvious (reloading bxSlider), you can load a different set of options. Note: There are 2 Object Literals:
var cfgA = {...} and var cfgB = {...}
Each of them has key/value pairs (or properties) that are from the bxSlider API. When calling .bxSlider(), simply load one of configurations:
var bx = $('.bx').bxSlider(cfgA);
onSliderResize Callback
As far as slider plugins go, bxSlider isn't the most stable and it can get buggy as browsers update and bxSlider stagnates at v.4.2.12, but there's one thing bxSlider excels in is callbacks. I've written complex programs that are controlled by bxSlider callbacks because they are reliable and never break. In this demo onSliderResize call the function reloadBX(currentIndex). **Note: ** the absence of parenthesis on reloadBX():
onSliderResize: reloadBX
reloadBX(currentIndex)
This is the heart of the Demo. For demonstration purposes I've bound the function to a convenient button. When testing the Demo, you should expect the following by either clicking the RELOAD button, or resizing bxSlider:
Toggling between cfgA and cfgB
Relocates to the position index bxSlider was on before the reload.
Shifts images to adjust at reload to avoid images being stuck halfway.
Details commented in Demo
Demo
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>bxSlider Reload</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/bxslider/4.2.12/jquery.bxslider.css">
<style>
img {
margin: auto;
display: block;
max-width: 100%;
}
</style>
</head>
<body>
<button class='reload'>RELOAD</button>
<ul class='bx'>
<li>
<img src="https://i.imgur.com/DrEwPH0.jpg">
<img src="https://i.imgur.com/MEPxbq4.jpg">
</li>
<li>
<img src="https://i.imgur.com/6qGdA1e.gif">
</li>
<li>
<img src='https://i.imgur.com/DsM6J8U.gif'>
</li>
<li>
<img src="https://i.imgur.com/sbxyLKX.png">
</li>
<li>
<img src="https://i.imgur.com/DheohWR.gif">
</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/bxslider/4.2.12/jquery.bxslider.min.js"></script>
<script>
// Cfg flag
var AB = 'A';
// Index counter
var idx = 0;
// cfgA
var cfgA = {
mode: 'horizontal',
slideWidth: 320,
adaptiveHeight: true,
onSliderResize: reloadBX
};
// cfgB
var cfgB = {
mode: 'fade',
captions: true,
slideWidth: 160,
adaptiveHeight: true,
onSliderResize: reloadBX
};
// Reference bxSlider instance
var bx = $('.bx').bxSlider(cfgA);
/*
Resize Callback
*/ // Called on resize event
function reloadBX(current) {
// Store current index
idx = current;
// Determine what configuration bx is in
if (AB === "A") {
/* if bx is in cfgA...
|| reload slider with cfgB
*/
bx.reloadSlider(cfgB);
// Shift all img to the left
$('img').css('transform', 'translateX(-25%)');
// Switch cfg flag to B
AB = "B";
// Otherwise...
} else {
// Reload slider with cfgA
bx.reloadSlider(cfgA);
// Shift all img to the right
$('img').css('transform', 'translateX(0)');
// Switch cfg flag to A
AB = "A";
}
// Go back to the index before reload
bx.goToSlide(idx);
}
// Added a reload button for convenient testing
$('.reload').click(function(e) {
// Get the current index and store it
idx = bx.getCurrentSlide();
/* Need to use the .call() function so that the context
|| is changed to bxSlider
*/
reloadBX.call(this, idx);
});
</script>
</body>
</html>

jQuery Scrollify - first section ignores offset

First time using jquery-scrollify. I have a page with a border around it and each section is meant to start 24px from top of page so it starts below the border. Without scrollify my CSS does this fine. Once I implement scrollify, even with the correct offset option, the page is always scrolled so that the top of this first section is right at the top of the page. Once I start scrolling to lower sections, they are respecting the offset and aligning properly. It seems the offset options is ignored for the first section? Is there any way to make the offset apply to the first section / start of page?
HTML
<section class="hero-home">
<div class="slide" style="background-image: url('/img/hero-home1.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home2.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home3.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home4.jpg')"></div>
</section>
JS
var scrollOffset = -24;
$.scrollify({
section: ".slide:visible",
offset: scrollOffset,
easing: "easeOutQuint",
scrollSpeed: 800,
scrollbars: true,
setHeights: false,
updateHash: false,
touchScroll: true
});
The -24 offset is to account for a fixed position frame I have at top of the page. When a new "section" is scrolled to the top, it should stop 24px from top of page rather than right at the top, otherwise it goes under the frame.
The first "section" starts in the right place before I initiate scrollify (my CSS on a containing element has top padding equal to height of the frame). However once scrollify is added, the page is scrolled down 24px so that the first "section" appears right at the top of page. The "offset" options corrects this on all subsequent sections (2nd, 3rd, and 4th section appear at the right place when I scroll down) but the 1st section's initial position is incorrect and ignores the offset option value.
I struggled with this issue as well, to fix this issue you want to provide some handling in the before event.
Solution Example
$(document).ready(function() {
$.scrollify({
section : ".fp-section",
offset:-200,
setHeights:false,
//Add the offset for the first element here:
//snapToElm is the list of element pages
before:function(indexPosition,snapToElm){
if(indexPosition===0){
snapToElm[0].css({"margin-top":"200px"});
}
if(indexPosition>0){
snapToElm[0].css({"margin-top":"0"});
}
},
afterRender:function(){
//set the first element initially to the desired offset
$($(this.section)[0]).css({"margin-top":"200px"});
// stuff to do once scrollify has rendered the list
}
})
});
$.scrollify({
section: "section",
interstitialSection: ".fourth-view,footer",
easing: "easeOutExpo",
scrollSpeed: 1100,
offset:0,
scrollbars: true,
standardScrollElements: "",
setHeights: false,
overflowScroll: true,
updateHash: false,
touchScroll: true,
before: function () {
},
after: function () {
},
afterResize: function () {
},
afterRender: function () {
}
});
if ($.scrollify.current().hasClass('second-view')) {
$.scrollify.setOptions({offset: 0})
}
else {
$.scrollify.setOptions({offset: -64.5})
}
and also
$(window).on('scroll', function () {
if ($.scrollify.current().hasClass('second-view')) {
$.scrollify.setOptions({offset: 0})
}
else {
$.scrollify.setOptions({offset: -64.5})
}
});
remove offset for second section
Change the source code line 660 of jquery.scrollify.js
if(i>0) {
heights[i] = parseInt($this.offset().top) + settings.offset;
} else {
heights[i] = parseInt($this.offset().top);
}
Change to
heights[i] = parseInt($this.offset().top) + settings.offset;
The version of jQuery Scrollify is 1.0.20
I tried the solution below but finally I just added the "section / slide class" to my header or navbar (<header class="slide navbar otherclasses..."></header>) that make my navbar the first element, it may not fit anyone but in my case its by far the most confortable for my users.
Edit : you need to set setHeights: false otherwise its not going to work well.

How do I deal with cloned slides to create a seamless html5 video slider in SlickJS?

I'm using slickJS to create a slider with HTML5 video backgrounds for each slide. Here's my SlickJS init code:
$homeSlider.slick({
adaptiveHeight: true,
arrows: false,
autoplay: true,
autoplaySpeed: 4000,
dots: true,
fade: false,
initialSlide: startSlide,
lazyLoad : 'progressive',
onBeforeChange: beforeSlickChange
});
Everything's working fine except that when I reach the end of the list of slides and try to go to the next slide (this loops back to the first slide), Slick shows a cloned slide for a moment and then the real first slide. Because of this, I'm unable to get a seamless transition between the last and first slide going in either direction. When I click forward to the first slide from the last slide or to the last slide from the first slide, the dummy slide appears (with no video playing) and after about 500ms or so, the real slide takes its place with the video playing.
What I'd like to happen is for the video to be playing seamlessly when transitioning two slides. I tried playing the video on the cloned slide and then playing the real slide's video from a slightly later point so that when the cloned slide disappeared, the real slide's video would be at the same point and there would be no noticeable change. However, the amount of time it takes for the cloned slide to disappear seems inconsistent.
Does anyone have a solution for this problem? Changing the slider to fade instead of slide fixes this problem, but I'd like to keep the sliding behavior. Thank you!
I managed to solve this problem. What I did was to play the video on the cloned slide and the real slide and then set the currentTime property of the real slide to that of the cloned slide on the afterChange event. The code looks like this:
Init code:
$homeSlider.slick({
adaptiveHeight: true,
arrows: false,
autoplay: true,
autoplaySpeed: 4000,
dots: true,
fade: false,
initialSlide: startSlide,
lazyLoad : 'progressive',
onBeforeChange: beforeSlickChange,
onAfterChange: afterSlickChange
});
onBeforeChange handler:
function beforeSlickChange(slick, currentSlide, nextSlide) {
if(hasVideoBG(currentSlide) === true && isMobile(mobileQuery) === false) {
getSlideVideoByIndex(currentSlide).currentTime = 0;
getSlideVideoByIndex(nextSlide).currentTime = 0;
}
if(hasVideoBG(nextSlide) === true && isMobile(mobileQuery)=== false) {
if(nextSlide === 0) {
$homeSlider.find(".slick-cloned:eq(1) video").get(0).currentTime = 0;
$homeSlider.find(".slick-cloned:eq(1) video").get(0).play();
}
if(nextSlide === (getSliderCount() - 1)) {
$homeSlider.find(".slick-cloned:eq(0) video").get(0).currentTime = 0;
$homeSlider.find(".slick-cloned:eq(0) video").get(0).play();
}
getSlideVideoByIndex(nextSlide).play();
}
}
onAfterChange handler:
function afterSlickChange(slick, currentSlide) {
if(currentSlide === 0) {
var $slideVideo = $homeSlider.find(".slick-cloned:eq(1) video").get(0);
getSlideByIndex(currentSlide).find("video").get(0).currentTime = $slideVideo.currentTime
} else if(currentSlide === (getSliderCount - 1)) {
var $slideVideo = $homeSlider.find(".slick-cloned:eq(0) video").get(0);
getSlideByIndex(currentSlide).find("video").get(0).currentTime = $slideVideo.currentTime
}
}
Basically I am resetting the currentTime of both the real and cloned slide videos to 0 and playing them before the slide changes. After the slide changes, I'm setting the currentTime property of the real slide to that of the cloned slide. This makes it so that when the cloned slide disappears, the real slide is playing the same video at the same time and the transition is seamless.

bxSlider - Play/Pause all sliders on page

I have two sliders on a page. Called with the same set of times and settings. One slider is a image slider, the other a sort of caption for it. Both in drastically different areas of the html.
bxslider is creating a play/pause for each slideshow, but I want some way of having one button that pauses all slideshows on the current page. This is because the slideshows are relative to each other and must keep a:
Slider A - Slide 1 / Slider B - Slide 1
Slider A - Slide 2 / Slider B - Slide 2
Slider A - Slide 3 / Slider B - Slide 3
etc.
Right now, when I pause one slideshow, the other continues and when the play is pressed, they are no longer in sync.
.bxslider & .bxslider-content are both my bxslider classes.
Thanks!
<script type="text/javascript">
$(document).ready(function () {
$('.bxslider, .bxslider-content').bxSlider({
mode: 'fade',
auto: true,
ease: 'cubic-bezier(0.42,0,0.58,1)',
pager: false,
controls: false,
autoControlsCombine: true,
autoControls: true,
pause: 8000,
speed: 800
});
});
</script>
Try
var slider=$('.bxslider').bxSlider({
//code here
});
var slider1=$('.bxslider-content').bxSlider({
//code here
});
$(document).on('click','.pause',function(){
slider.stopAuto();
slider1.stopAuto();
});
$(document).on('click','.play',function(){
slider.startAuto();
slider1.startAuto();
});
Fiddle http://jsfiddle.net/CDvmk/

Categories