Freddy
Freddy

Reputation: 857

How to make a 3D slick slider

Using slick, I'm trying to achieve a slider that looks like this:

enter image description here

In the above, the center slide is the default selected when slick initiates. Then, when an arrow is clicked, the slick-current class will shift onto a new div and css translate can be used to scale the image.

Here is my current code:

$(function(){

  $("#downloadNow__slick").slick({
    slidesToShow: 3,
    // initialSlide: 2,
    centerMode: true,
    centerPadding: "53px",
    arrows: true,
    dots: false,
    infinite: true,
    cssEase: 'linear',
  });

});
.downloadNow {
  background: grey;
  padding: 60px 0px;

  &__wrapper {
    position: relative;
  }
  
  .downloadNowCard{
    background: white;
    padding: 100px;
  }


  .slider {
    max-width: 1110px;
    margin: 0 auto;
  }

  .slick-track {
    padding-top: 53px;
    padding-bottom: 53px;
  }

  .slick-slide {
    text-align: center;
    transition: transform 0.3s ease-in-out;
  }


  .slick-slide.slick-current {
    transform: scale(1.35);
    position: relative;
    z-index: 1;
  }

  .slick-slide img {
    width: 100%;
  }


}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js" integrity="sha512-XtmMtDEcNz2j7ekrtHvOVR4iwwaD6o/FUJe6+Zq+HgcCsk3kj4uSQQR8weQ2QVj1o0Pk6PwYLohm206ZzNfubg==" crossorigin="anonymous"></script>


<section class="downloadNow">
  <div class="downloadNow__wrapper">


    <div class="downloadNow__slides" id="downloadNow__slick">
      <div class="downloadNowCard">Card 1</div>
      <div class="downloadNowCard">Card 2</div>
      <div class="downloadNowCard">Card 3</div>
    </div>
   

  </div>
</section>

Current issues:

  1. Cannot achieve row layout (flex on wrapper not playing nicely)
  2. If I uncomment out initialSlide: 2, the slider breaks. I'm trying to get the center slide as the active slide with this.
  3. Slick not changing slide

Upvotes: 4

Views: 8705

Answers (2)

Fennec
Fennec

Reputation: 1872

For a smooth 3D Effect you need to play with shadows, by increasing/decreasing the shadow you get a visual illusion of a popping out/in box, for the animation effects play with css transition use only transform for better performance.

You don't need external libraries to achieve this, the example below is a pure HTML/CSS/Javascript slider.

Edit: add some explanatory comments to the example.

// Button click events
const buttons = document.querySelectorAll('b')
buttons.forEach((button, i) => 
  button.onclick = () => slide(i)
)

// Slide function
function slide(right) {
  // Get the SLider elements
  const container = document.querySelector('div');
  const slider = document.querySelector('ul');
  const items = document.querySelectorAll('li');
  const featured = document.querySelector('.featured');
  
  // Get the featured item
  const featuredIndex = [...items].indexOf(featured);
  
  // Set the move if not right then left
  const move = right ? 1 : -1;
  
  // Check the slider limits 
  // if right and index 0: do nothing 
  // if left and last item: do nothing
  if((!right && !featuredIndex) 
   || (right && featuredIndex === items.length -1))
    return;

  // Get the next item element
  const nextIndex = featuredIndex + move;
  const nextItem = items[nextIndex]
  
  // Remove "featured" class from last item 
  featured.classList.remove("featured");
  
  // Add "featured" class the next item
  nextItem.classList.add("featured");
  
  // Get the container size 
  const { width: containerSize } = container.getBoundingClientRect();
  
  // Get the next item size and position
  const itemSize = containerSize / 3; // Display only 3 items 
  const itemPosition = itemSize * (nextIndex + 1); // Current position
  
  // Compute the slider next position
  const position = containerSize - itemPosition - itemSize;
  
  // Move the slider on its X axis using css transform and transitionX
  slider.style.transform = `translateX(${position}px)`
}
body{
 background: #ddd;
}

/* Some csss reboot */
ul, li{
  margin: 0;
  padding: 0;
  list-style-type: none;
}

/* Container */
div { 
  position: relative;
  width: 100%;
  overflow-x: hidden;
  transform: transitionX(0);
}

/* Preview/Next Buttons */
b {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0.5em;
  width: 20px;
  height: 20x;
  line-height: 20px;
  font-size: 1.2em;
  color: #666;
  cursor: pointer;
  transform: translateY(-50%) scale(1);
  transition: transform .1s ease-out;
}

b:last-child {
  left: unset;
  right: 0.5em;
}

/* Button animation on hover */
b:hover{
  transform: translateY(-50%) scale(1.3);
}

/* Slider */
ul {
  position: relative;
  padding: 2em 0;
  display: flex;
  width: 100%;
  height: 150px;
  transform: translateX(0);
  transition: transform .3s ease-out;
}

/* Items */
li {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4em;
  font-weight: 500;
  font-family: arial;
  color: #555;
  min-width: calc(100% / 3);
  background: #fff;
  border-radius: .5em;
  /* Animation */
  transform: translateX(10%) scale(0.5);
  box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%), 0 1px 5px 0 rgb(0 0 0 / 20%);
  transition: all .3s ease-out;
}

/* Featured Item */
.featured {
  z-index: 1;
  /* Animation  */
  transform: scale(1);
  box-shadow: 0 16px 24px 2px rgb(0 0 0 / 14%), 0 6px 30px 5px rgb(0 0 0 / 12%), 0 8px 10px -7px rgb(0 0 0 / 20%)
}

.featured + li {
  /* Offset the next element under the selected element */
  transform: scale(.5) translateX(-25%) !important;
}
<div>            <!-- Container -->
  <ul>           <!-- Slider -->
    <li>1</li>   <!-- Ithems -->
    <li class="featured">2</li>  
    <li>3</li>
    <li>4</li>  
    <li>5</li>  
    <li>6</li>  
    <li>7</li>  
    <li>8</li>  
    <li>9</li>  
    <li>10</li>  
  </ul>
  <b>ᐸ</b>       <!-- Preview button -->
  <b>ᐳ</b>       <!-- Next button -->
</div>

Upvotes: 2

Rok Benko
Rok Benko

Reputation: 22880

Here you go...


It took me some time to figure it out because of some strange behavior of the slick slider.

To begin with, the slick slider didn't work with newer versions of jQuery. After a lot of trial and error (and searching through older answers here on SO), I figured out it works only with the older version of jQuery for some strange reason. This is the main reason it didn't work for you too. I used older version of jQuery than you did and it still didn't work. It works with v1.12.3 (it might also work with some newer versions of jQuery, but I didn't test which is the latest compatible version).

To achieve a 3D effect, you can use box-shadow: 0.1vw 0.8vw 1vw rgba(0, 0, 0, 0.35);. With the current values (i.e. 0.1vw 0.8vw 1vw), you get a blurry shadow at the bottom and a little bit on the right side. The first value (i.e. 0.1vw) defines a horizontal offset. The second value (i.e. 0.8vw) defines a vertical offset. The third value (i.e. 1vw) defines blur radius so that the shadow is "smooth" (try to remove 1vw and you'll get the point).

Also, I managed to solve all your issues:

  • the row layout works,
  • the middle card is always an "active card" (a little bit bigger box, a little bit bigger font) and
  • arrows work too (but you have to use z-index: 100; to push them to the front).

$(document).on('ready', function() {

  $('.slider').slick({
    dots: true,
    centerMode: true,
    infinite: true,
    centerPadding: '60px',
    slidesToShow: 3,
    speed: 400
  });

});
html {
  height: 100%;
  overflow-x: hidden;
}

body {
  background: #F8F8F8;
  height: 100%;
  margin: 0;
}

.slider {
  width: 90%;
  left: 5%;
}

h3 {
  background: #fff;
  color: #202020;
  font-size: 3.5vw;
  line-height: 23vh;
  margin: 6.5vw;
  margin: 6.5vw;
  padding: 1vw;
  position: relative;
  text-align: center;
  box-shadow: 0.1vw 0.8vw 1vw rgba(0, 0, 0, 0.35);
}

.slick-center {
  transition: 0.2s ease-in-out;
  -webkit-transform: scale(1.3);
  -moz-transform: scale(1.3);
  transform: scale(1.3);
}

.slick-center h3 {
  font-size: 4vw;
}

.slick-prev,
.slick-next {
  z-index: 100 !important;
}

.slick-prev:before {
  transition: 0.2s ease-in-out;
  color: #303030 !important;
  font-size: 2vw !important;
  margin-right: -10vw;
}

.slick-next:before {
  transition: 0.2s ease-in-out;
  color: #303030 !important;
  font-size: 2vw !important;
  margin-left: -10vw;
}

.slick-dots li button:before {
  transition: 0.2s ease-in-out;
  font-size: 0.7vw !important;
}
<!DOCTYPE html>
<html lang='en'>

<head>
  <meta charset='UTF-8'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Document</title>
  <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js'></script>
  <link href='https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css' rel='stylesheet' />
  <link href='https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css' rel='stylesheet' />
</head>

<body>

  <div class='slider'>
    <div>
      <h3>1</h3>
    </div>
    <div>
      <h3>2</h3>
    </div>
    <div>
      <h3>3</h3>
    </div>
    <div>
      <h3>4</h3>
    </div>
    <div>
      <h3>5</h3>
    </div>
    <div>
      <h3>6</h3>
    </div>
  </div>

</body>

</html>

Upvotes: 2

Related Questions