It turned out there are some precalculated fixed values in the carousel-inner
and the slider-photo-wrapper
elements.
I decided I limit the height based on the tallest landscape and overwrite the values of these elements.
Issues I faced with:
- I had to be sure that the images loaded before I work with them otherwise I couldn't get their
width
and height
- How can I get the size of a scaled image? Finally I bypassed it and used the original size because I needed only the ratio of the
width
to the height
to calculate the maximum height
based on the width of the carousel container
- I couldn't use
getBoundingClientRect()
because it returns 0 for images which aren't displayed (display: hidden) and only the first image is displayed in the Bootstrap Carousel
We call CarouselNormalization.init($carousel)
from the main code where we loop through the galleries:
// carousel.js
var Carousel = (function($, viewport) {
function init() {
var $carousels = $('.carousel');
$.each($carousels, function() {
var $carousel = $(this);
swipeHorizontalMobile($carousel, viewport);
imageNavListener($carousel);
updateArrowVisibility(0, $carousel);
// fixes the size of the carousel images/containers mainly for mobile devices
CarouselNormalization.init($carousel);
});
}
// implementation of the rest of the code
return {
init: init
};
})(jQuery, ResponsiveBootstrapToolkit);
The code below was written in Pair programming with my colleague and we used some of the ideas of Normalize Twitter Bootstrap Carousel Slide Heights.
// carousel_normalization.js
/**
* changes the maximum height of the carousel containers based on the tallest landscape image
* and prevents to have big margins above and below landscape images in small resolution
*/
var CarouselNormalization = (function ($) {
var $carousel,
$photoWrappers,
$imgs;
function init($inputCarousel) {
$carousel = $inputCarousel;
$imgs = $carousel.find('.item img');
if ($imgs.length < 1) {
return;
}
$photoWrappers = $carousel.find('.item .slider-photo-wrapper');
var imgsLoadedCount = 0;
$imgs.one('load', function () {
imgsLoadedCount++;
if (imgsLoadedCount < $imgs.length) {
return;
}
normalizeHeights();
$(window).on('resize orientationchange', function () {
normalizeHeights();
});
}).each(function () {
if (this.complete) {
$(this).trigger('load');
}
});
}
/**
* finds the tallest landscape
* uses its height as maximum height for the 'slider-photo-wrapper' defined in the css and for the 'carousel-inner'
*/
function normalizeHeights() {
var widths = [];
var heights = [];
var maxWidth = $carousel.width();
$imgs.each(function () {
var width = $(this).prop('naturalWidth');
var height = $(this).prop('naturalHeight');
if (width > height) {
widths.push(width);
heights.push(height);
}
});
if (widths.length < 1 || heights.length < 1) {
return;
}
var tallestLandscapeHeight = Math.max.apply(null, heights);
var tallestLandscapeWidth = widths[heights.indexOf(tallestLandscapeHeight)];
var maxHeight = maxWidth * tallestLandscapeHeight / tallestLandscapeWidth;
$photoWrappers.css('height', maxHeight);
$carousel.find('.carousel-inner').css('height', maxHeight);
}
return {
init: init
};
})(jQuery);