Normalize Twitter Bootstrap Carousel Slide Heights
Bootstrap carousel is fantastic, but its flexibility can be a challenge. Since each slide item is pretty much freeform HTML, varying slides can have varying heights. This is problematic when page content exists in normal flow after and beneath the carousel, since a shape-shifting carousel is constantly pushing content down or pulling it up on slide transition, making reading difficult—especially on mobile devices. I found that its possible to replicate the behavior of other carousels that dynamically set a consistent height for the whole carousel based on the tallest slide item found in the HTML.
You’ll want to execute jQuery akin to the following, after the carousel HTML exists on the page, or once the DOM is ready (either inside $(document).ready()* or at the end of the page body):
function carouselNormalization() {
var items = $('#carousel-example-generic .item'), //grab all slides
heights = [], //create empty array to store height values
tallest; //create variable to make note of the tallest slide
if (items.length) {
function normalizeHeights() {
items.each(function() { //add heights to array
heights.push($(this).height());
});
tallest = Math.max.apply(null, heights); //cache largest value
items.each(function() {
$(this).css('min-height',tallest + 'px');
});
};
normalizeHeights();
$(window).on('resize orientationchange', function () {
tallest = 0, heights.length = 0; //reset vars
items.each(function() {
$(this).css('min-height','0'); //reset min-height
});
normalizeHeights(); //run it again
});
}
}
*With older versions of jQuery at least, IE8 and below don’t respond to $(document).ready(), so you may need a workaround for that.
Related protips:
Written by Eddie Staples
Related protips
9 Responses
saved me some time, thank you Eddie. One thing you might mention for is you need to call 'carouselNormalization();' at the end of the function declaration.
A little cleaner
// Normalize Carousel Heights - pass in Bootstrap Carousel items.
$.fn.carouselHeights = function() {
var items = $(this), //grab all slides
heights = [], //create empty array to store height values
tallest; //create variable to make note of the tallest slide
var normalizeHeights = function() {
items.each(function() { //add heights to array
heights.push($(this).height());
});
tallest = Math.max.apply(null, heights); //cache largest value
items.each(function() {
$(this).css('min-height',tallest + 'px');
});
};
normalizeHeights();
$(window).on('resize orientationchange', function () {
//reset vars
tallest = 0;
heights.length = 0;
items.each(function() {
$(this).css('min-height','0'); //reset min-height
});
normalizeHeights(); //run it again
});
};
jQuery(function($){
$(window).on('load', function(){
$('#carousel-hero .item').carouselHeights();
});
});
great article! thanks so much!
Thank you!
This code makes the opposite:
takes the shortest image and sets that value as the maximum height.
All other slides appear cropped
HOW TO USE: change the carousel id (#carousel-single) and paste after your carousel
<script>
jQuery('.carousel').carousel({interval: 3000 });
// Normalize Carousel Heights - pass in Bootstrap Carousel items.
function carouselNormalization() {
var items = jQuery('#carousel-single .item'), //grab all slides
heights = [], //create empty array to store height values
shortest; //create variable to make note of the shortest slide
if (items.length) {
function normalizeHeights() {
items.each(function() { //add heights to array
heights.push(jQuery(this).height());
});
shortest = Math.min.apply(null, heights); //cache largest value
items.each(function() {
jQuery('.carousel-inner').css('height',shortest + 'px').css('overflow','hidden');
});
};
normalizeHeights();
jQuery(window).on('resize orientationchange', function () {
shortest = 0, heights.length = 0; //reset vars
items.each(function() {
jQuery('.carousel-inner').css('height','0'); //reset min-height
});
normalizeHeights(); //run it again
});
}
}
carouselNormalization();
</script>
I made another version that worked better for me. This one fixes the height of the carousel div to such a height that the biggest image fits in it.
Note that I use a custom way to measure images because, when they are hidden, they sometimes are 0px.
This version supports multiple carousel in one document and does not assume one 'id' is used
function normalizeSizesAllCarousels(){ jQuery('.carousel.slide').each(function(){//we loop all the present carousels normalizeSizesOneCarousel('#' + jQuery(this).attr('id')); }); } function normalizeSizesOneCarousel(idSelectorCarousel){ var images=jQuery(idSelectorCarousel + ' .carousel-inner .item img'); var availableWidht=jQuery(idSelectorCarousel).innerWidth(); var maxHeight=0; var imageHeight=0; var aspectRatio=1;//width/height images.each(function(){ aspectRatio=calcImgWidth(this)/calcImgHeight(this); imageHeight=availableWidht/aspectRatio; if(imageHeight>maxHeight){maxHeight=imageHeight;} }); jQuery(idSelectorCarousel).height(maxHeight); } function calcImgWidth(img){ var width=img.width; if (width>0){ return width; }else{ jQuery('body').append('<div id="tempContainer" style="visibility:hidden;position:absolute"></div>'); jQuery('#tempContainer').append(img.clone().attr('id',false)); width= jQuery('#tempContainer img').width; jQuery('#tempContainer').remove(); return width; } } function calcImgHeight(img){ var height=img.height; if (height>0){ return height; }else{ jQuery('body').append('<div id="tempContainer" style="visibility:hidden;position:absolute"></div>'); jQuery('#tempContainer').append(img.clone().attr('id',false)); height= jQuery('#tempContainer img').height; jQuery('#tempContainer').remove(); return height; } } jQuery(document).ready(function(){normalizeSizesAllCarousels();}); jQuery(window).on('resize orientationchange', function () {normalizeSizesAllCarousels();}); </code> </pre>
The resize event fires twice on my webpage, and I had to use "height" instead of "min-height", that's my version of your script:
$(window).load(function() {
$('.carousel').each(function(){
$(this).carouselHeights();
});
});// Normalize Bootstrap Carousel Heights
$.fn.carouselHeights = function() {
var items = $(this).find('.item'), // grab all slides
heights = [], // create empty array to store height values
tallest, // create variable to make note of the tallest slide
call;
var normalizeHeights = function() {
items.each(function() { // add heights to array
heights.push($(this).outerHeight());
});
tallest = Math.max.apply(null, heights); // cache largest value
items.css('height', tallest);
};
normalizeHeights();
$(window).on('resize orientationchange', function() {
// reset vars
tallest = 0;
heights.length = 0;
items.css('height', ''); // reset height
if(call){
clearTimeout(call);
};
call = setTimeout(normalizeHeights, 100); // run it again
});
};
</pre>
Does anyone have a working page with this working. I am struggling to get any of the above versions to work.
Thank you very much Eddie and also tonycronin for providing this efficient solution to Bootstrap's carousel height issue. The code from tonycronin worked great for me.