8

For the last 3 hours I've been trying to make a simple adjustment to Bootstrap 3's carousel transitions. I've tried changing the slide speed where this is the only thing that seems to have any effect:

.carousel-inner .item {
  -webkit-transition-duration: 2s;
  -moz-transition-duration: 2s;
  -o-transition-duration: 2s;
  transition-duration: 2s;
}

but it hides the 'leaving' content too soon, and I have no clue what property to modify to fix that.

I've also tried changing it to a fade transition with

.carousel-fade .item {
  opacity: 0;
  -webkit-transition: opacity 2s ease-in-out;
  -moz-transition: opacity 2s ease-in-out;
  -ms-transition: opacity 2s ease-in-out;
  -o-transition: opacity 2s ease-in-out;
  transition: opacity 2s ease-in-out;
  left: 0 !important;
}

.carousel-fade .active {
  opacity: 1 !important;
}

.carousel-fade .left {
  opacity: 0 !important;
  -webkit-transition: opacity 0.5s ease-in-out !important;
  -moz-transition: opacity 0.5s ease-in-out !important;
  -ms-transition: opacity 0.5s ease-in-out !important;
  -o-transition: opacity 0.5s ease-in-out !important;
  transition: opacity 0.5s ease-in-out !important;
}

.carousel-fade .carousel-control {
  opacity: 1 !important;
}

And just about every other snippet to do so that I've come across, but every single one always first removed the leaving content, showing a featureless background, before fading in the next. What am I missing? All I need is some plain CSS to override the existing transition details, but I don't know where to look any more.

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Valyrion
  • 2,342
  • 9
  • 29
  • 60
  • You should probably reset the original transitions, see also: http://bassjobsen.weblogs.fm/change-bootstraps-carousel-animantion/ – Bass Jobsen Jan 09 '15 at 15:50

2 Answers2

24

I think different aspects of bootstrap's carousel plugin give the effects you mention.

  1. Active items have display: block while not active items have display: none

    This can be solved by giving all items display: block and then setting the position to absolute with top: 0 and left: 0, resulting in the items overlapping. Setting opacity: 0; makes them invisible by default.

    Less:

    .carousel-inner > .item {
      opacity: 0;
      top: 0;
      left: 0;
      width: 100%;
      display: block;
      position: absolute;
    }
    

    One problem of the position: absolute is that the container does not get a height. The preceding can be solved by setting the position of the first item to relative (it is add the right position already). In Less code, it is as follows:

    .carousel-inner > .item {
      :first-of-type {
        position:relative;
      } 
    }
    
  2. Bootstrap uses translate3ds to change the position of the item in the space. You won't need these transformations, so reset them. Leveraging Less, code shown below:

    .carousel-inner > .item {
      transform: translate3d(0,0,0) !important;
    }
    
  3. The CSS transitions are triggered by adding and removing CSS classes with jQuery. The time between these class changes has been hardcoded in the carousel plugin code (Carousel.TRANSITION_DURATION = 600). So, after 600 ms, one item becomes active (having the .active class). That is the reason for the unexpected behavior if your css transition-duration is greater than 0.6 seconds.

The CSS class changes are as follows:

The active item has class .active -> .active.left -> none The next item has no class -> .next.left -> .active

So the .active.left and .next.left are important (or .prev.right and .active.right when you slide backwards).

Because all images are already stacked, you can use the z-index property to make an image in the stack visible, because we can change the opacity at the same time. You can use the following Less code to fade in the next slide:

.carousel-inner {
  > .next.left {
    transition: opacity 0.6s ease-in-out;
    opacity: 1;
    z-index:2;
  }
  > .active.left {
    z-index:1;
  }
}

To make sure that the controls are visible as well, use:

.carousel-control {
  z-index:4;
}

Putting all together, see the results in this demo, which uses the following Less code:

.carousel-inner {
 > .item {
  opacity: 0;
  top: 0;
  left: 0;
  width: 100%;
  display: block;
  position: absolute;
  z-index:0;
  transition: none;
  transform: translate3d(0,0,0) !important;
  &:first-of-type {
    position:relative;
  } 
  }
 > .active {
  opacity: 1;
  z-index:3;
}

 > .next.left,
 > .prev.right {
  transition: opacity 0.6s ease-in-out;
  opacity: 1;
  left: 0;
  z-index:2;
  }                                                                                                             
 > .active.left,
 > .active.right {
  z-index:1;
  }
}
.carousel-control {
z-index:4;
}

The above code can be compiled with the Less autoprefixer plugin plugin into CSS with the following command:

lessc --autoprefix="Android 2.3,Android >= 4,Chrome >= 20,Firefox >= 24,Explorer >= 8,iOS >= 6,Opera >= 12,Safari >= 6' code.less

which outputs:

.carousel-inner > .item {
  opacity: 0;
  top: 0;
  left: 0;
  width: 100%;
  display: block;
  position: absolute;
  z-index: 0;
  -webkit-transition: none;
       -o-transition: none;
          transition: none;
  -webkit-transform: translate3d(0, 0, 0) !important;
          transform: translate3d(0, 0, 0) !important;
}
.carousel-inner > .item:first-of-type {
  position: relative;
}
.carousel-inner > .active {
  opacity: 1;
  z-index: 3;
}
.carousel-inner > .next.left,
.carousel-inner > .prev.right {
  -webkit-transition: opacity 0.6s ease-in-out;
       -o-transition: opacity 0.6s ease-in-out;
          transition: opacity 0.6s ease-in-out;
  opacity: 1;
  left: 0;
  z-index: 2;
}
.carousel-inner > .active.left,
.carousel-inner > .active.right {
  z-index: 1;
}
.carousel-control {
  z-index: 4;
}
jiminy
  • 1,612
  • 3
  • 18
  • 21
Bass Jobsen
  • 48,736
  • 16
  • 143
  • 224
  • Wonderful solution! But... how can I increase the fade speed? Increasing the transition time it lost the smooth transition – Fred K Jun 10 '15 at 17:30
  • Also, another issue of this solution: using the control prev/next it doesn't change the slides. How can solve it? – Fred K Jun 11 '15 at 08:03
  • You should change the Carousel.TRANSITION_DURATION in the plugin and the `transition-duration`. In the demo prev / next works?? – Bass Jobsen Jun 11 '15 at 20:22
0

I was struggling with this and it was driving me insane - on Bootstrap's Introduction page, if you look under Components, it lists Carousel as one of the components requiring JS. I had to add their CSS stylesheet before all other stylesheets, then their Bootstrap / JS plugin bundle right before the closing body tag. Finally fixed the issue. I've linked them below in order, starting with the Introduction page.

https://getbootstrap.com/docs/5.1/getting-started/introduction/

Dharman
  • 30,962
  • 25
  • 85
  • 135