Slick Slider - how to keep the active pagination (dot) always centered

Viewed 8504

I am trying to achieve something which I haven't seen done so far on the web. I want the active pagination dot in the slick slider to always be in the center.

This is the expected result:

Image of dots centered

In other words I would expect the page to load showing the first slide but the pagination dot for the first slide should be centered.

If a user clicks the next slide by swiping then the dot should move the middle again, with the active slide always being centered in the pagination. Any ideas on the best way to achieve this?

Here's an example and code of what i've done so far.

$('.slider').slick({
  infinite: true,
  dots: true,
  arrows: false
});
.slider {
  width: 200px;
}

.slide img {
  display: block;
  width: 100%;
  height: auto;
}

.slick-dots {
  display: flex;
  justify-content: center;
  margin: 0;
  padding: 1rem 0;
  list-style-type: none;
}

.slick-dots li {
  margin: 0 0.25rem;
}

.slick-dots button {
  display: block;
  width: 1rem;
  height: 1rem;
  padding: 0;
  border: none;
  border-radius: 100%;
  background-color: grey;
  text-indent: -9999px;
}

.slick-dots li.slick-active button {
  background-color: blue;
}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E=" crossorigin="anonymous"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css" />
<div class="slider">
  <div class="slide">
    <img src="http://placehold.it/200x100?text=1" />
  </div>
  <div class="slide">
    <img src="http://placehold.it/200x100?text=2" />
  </div>
  <div class="slide">
    <img src="http://placehold.it/200x100?text=3" />
  </div>
  <div class="slide">
    <img src="http://placehold.it/200x100?text=4" />
  </div>
  <div class="slide">
    <img src="http://placehold.it/200x100?text=5" />
  </div>
</div>

4 Answers

for that you have to add one more slider as per my snippet and the use Slider Syncing functionality to bind both slider.

here is an working example for that

$(document).ready(function() {
  $(".main_slider").slick({
    infinite: true,
    dots: false,
    arrows: false,
    asNavFor: '.slider_dots',
    slidesToShow: 1,
    slidesToScroll: 1,
  });
  $('.slider_dots').slick({
    infinite: true,
    slidesToShow: 3,
    slidesToScroll: 1,
    asNavFor: '.main_slider',
    arrows: false,
    dots: false,
    centerMode: true,
    focusOnSelect: true,
    centerPadding: '20%',
  });
});
.main_slider,
.slider_dots {
  width: 200px;
}

.slide img {
  display: block;
  width: 100%;
  height: auto;
}

.slick-dots {
  display: flex;
  justify-content: center;
  margin: 0;
  padding: 1rem 0;
  list-style-type: none;
}

.slick-dots li {
  margin: 0 0.25rem;
}

.slick-dots button {
  display: block;
  width: 1rem;
  height: 1rem;
  padding: 0;
  border: none;
  border-radius: 100%;
  background-color: grey;
  text-indent: -9999px;
}

.slick-dots li.slick-active button {
  background-color: blue;
}

.slider_dots .slider_navigators {
  height: 20px;
  background-color: #9E9E9E;
  border-radius: 50%;
  margin: 10px;
  transform: scale(0.4);
  outline: none;
  cursor: pointer;
}

.slider_dots .slider_navigators.slick-active {
  transform: scale(0.70);
}

.slider_navigators.slick-active.slick-current {
  transform: scale(1);
  background-color: #00f;
}
<!DOCTYPE html>
<html>

<head>
  <title>Demo Page</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>
</head>

<body>
  <div class="main_slider">
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
    <div class="slide">
      <img src="https://via.placeholder.com/350x150" />
    </div>
  </div>
  <div class="slider_dots">
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
    <div class="slider_navigators"></div>
  </div>
</body>

</html>

I hope you are getting your solution from my snippet code.

.on('beforeChange', function(event, slick, currentSlide, nextSlide){
  //appedn the bullet on center 
});

Something like this

Codepen

Here's an example that uses a bit of jQuery to manipulate the styles of the existing slide dots. Another example of the working code can be found here: https://codepen.io/edlucas/pen/XWJRmbb

The only caveat is that the <li> tags containing the dots must all be the same width for the math to work out. This solution will work with any number of dots in a single line.

const $slideShow = $('.slider');

function offsetDots(slideNum) {
  const $slickDots = $slideShow.find('.slick-dots'),
    numDots = $slickDots.find('li').length,
    dotWidth = $slickDots.find('li:first').outerWidth(true),
    offset = dotWidth * slideNum;
  
  // Offset the dots container to center current slide dot
  $slickDots.css('marginLeft', offset * -1 - Math.ceil(dotWidth / 2));
  
  // Clear existing secondary dot class
  $slickDots.find('li').removeClass('slick-secondary');

  // Add secondary dot class to preceeding slide dot
  if (slideNum > 0) {
    $slickDots.find('li:nth-of-type('+slideNum+')').addClass('slick-secondary');
  }

  // Add secondary dot class to next slide dot
  if (slideNum < numDots - 1) {
    $slickDots.find('li:nth-of-type('+(slideNum + 2)+')').addClass('slick-secondary');
  }
}

$slideShow.on('init', function(event, slick) {
  offsetDots(0);
});

$slideShow.on('beforeChange', function(event, slick, currentSlide, nextSlide) {
  offsetDots(nextSlide);
});

$slideShow.slick({
  infinite: true,
  dots: true,
  arrows: false
});
.demo-wrapper{
  width: 200px;
  position: relative;
}

.slide img {
  display: block;
  width: 100%;
  height: auto;
}

.slick-dots {
  position: absolute;
  left: 50%;
  display: inline-flex;
  margin: 0;
  padding: 1rem 0;
  list-style-type: none;
}

.slick-dots li {
  width: 12px;
  margin: 0 3px;
}

.slick-dots button {
  display: block;
  width: 6px;
  height: 6px;
  padding: 0;
  margin: 0 auto;
  border: none;
  border-radius: 100%;
  background-color: grey;
  text-indent: -9999px;
}

.slick-dots li.slick-active button {
  background-color: blue;
  width: 12px;
  height: 12px;
  margin-top:-4px
}

.slick-dots li.slick-secondary button {
  width: 8px;
  height: 8px;
  margin-top: -1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css" />

<div class="demo-wrapper">
<div class="slider">
  <div class="slide">
    <img src="https://loremflickr.com/200/200/lego?random=1" />
  </div>
  <div class="slide">
    <img src="https://loremflickr.com/200/200/lego?random=2" />
  </div>
  <div class="slide">
    <img src="https://loremflickr.com/200/200/lego?random=3" />
  </div>
  <div class="slide">
    <img src="https://loremflickr.com/200/200/lego?random=4" />
  </div>
  <div class="slide">
    <img src="https://loremflickr.com/200/200/lego?random=5" />
  </div>
</div>
</div>

If you need to achieve this properly, then you can try Abhishek Pandey solution.

If you just need to solve it quickly, then you can try shortcut approach like making the slider to start from slide 3 instead of slide 1

as your slider navigations are just dots with no numbers, site users doesn't going to recognize that slider is starting from slide 3

Related