3

Here is a very basic Bootstrap 4 Carousel with 3 images.

I implemented the 2 available events: slide.bs.carousel and slid.bs.carousel.

I am able to get the image width in the slid event listener (when the carousel has completed its slide transition) but the image width is always 0 when I try to get it in the slide listener (I want to know the size of the next slide).

Why is that?

Here is a snippet. Watch the console.

jQuery('#carouselDemo').on('slide.bs.carousel', function(e) {

  console.log('SLIDE event');
  console.log('Image width: ' + e.relatedTarget.querySelector('img').clientWidth);
});

jQuery('#carouselDemo').on('slid.bs.carousel', function(e) {

  console.log('SLID event');
  console.log('Image width: ' + e.relatedTarget.querySelector('img').clientWidth);
});
.carousel {
  background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

<div id="carouselDemo" class="carousel slide" data-ride="carousel">
  <div class="carousel-inner">
    <div class="carousel-item active">
      <img src="https://via.placeholder.com/700x400">
    </div>
    <div class="carousel-item">
      <img src="https://via.placeholder.com/800x400">
    </div>
    <div class="carousel-item">
      <img src="https://via.placeholder.com/900x400">
    </div>
  </div>
  <a class="carousel-control-prev" href="#carouselDemo" role="button" data-slide="prev">
    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
    <span class="sr-only">Previous</span>
  </a>
  <a class="carousel-control-next" href="#carouselDemo" role="button" data-slide="next">
    <span class="carousel-control-next-icon" aria-hidden="true"></span>
    <span class="sr-only">Next</span>
  </a>
</div>

https://jsfiddle.net/upsidown/ruo0gt19/


Edit

I failed to mention that I need the next slide image client width, ie. the display width and not the original image width. Below is an example with larger images, forced to 100% max-width using the answer provided by @gaetanoM.

Note: I can't simply use the body or container element width as in my use case the carousel images are displayed in full-screen, with max-height 100% and therefore the width can vary and be smaller than the container width.

jQuery('#carouselDemo').on('slide.bs.carousel', function(e) {

    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    console.log('slide: Current element Width is: ' + fromelement[0].width);
    console.log('slide: Next element Width is: ' + toelement[0].width);

});

jQuery('#carouselDemo').on('slid.bs.carousel', function(e) {

    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    console.log('slid: Current element Width is: ' + fromelement[0].width);
    console.log('slid: Next element Width is: ' + toelement[0].width);
});
.carousel {
    background-color: grey;
}

.carousel-item > img {
  max-width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


<div id="carouselDemo" class="carousel slide" data-ride="carousel">
    <div class="carousel-inner">
        <div class="carousel-item active">
            <img src="https://via.placeholder.com/700x400">
        </div>
        <div class="carousel-item">
            <img src="https://via.placeholder.com/800x400">
        </div>
        <div class="carousel-item">
            <img src="https://via.placeholder.com/900x400">
        </div>
    </div>
    <a class="carousel-control-prev" href="#carouselDemo" role="button" data-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="sr-only">Previous</span>
    </a>
    <a class="carousel-control-next" href="#carouselDemo" role="button" data-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="sr-only">Next</span>
    </a>
</div>
Community
  • 1
  • 1
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131

2 Answers2

1

According to the updated answer the issue is on the next/prev element when sliding (It is hidden, so there is no clientWidth).

In order to overcome this a solution can be:

  • toggle visibility of this hidden element
  • get the clientWidth
  • immediately re-toggle visibility in order to accomodate everyting.

In the snippet each image has a different width in order to prove the result.

jQuery('#carouselDemo').on('slide.bs.carousel', function(e) {
    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    toelement.parent().toggleClass('active');
    console.log('slide: Current element Width is: ' + fromelement[0].width + ' / ' + fromelement[0].clientWidth);
    console.log('slide: Next element Width is: ' + toelement[0].width + ' / ' + toelement[0].clientWidth);
    toelement.parent().toggleClass('active');
});
jQuery('#carouselDemo').on('slid.bs.carousel', function(e) {
    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    fromelement.parent().toggleClass('active');
    console.log('slid: Current element Width is: ' + fromelement[0].width + ' / ' + fromelement[0].clientWidth);
    console.log('slid: Next element Width is: ' + toelement[0].width + ' / ' + toelement[0].clientWidth);
    fromelement.parent().toggleClass('active');
});
.carousel {
    background-color: grey;
}

.carousel-item > img.n1 {
    width: 100%;
    height: 100vh;
}
.carousel-item > img.n2 {
    width: 50%;
    height: 100vh;
}
.carousel-item > img.n3 {
    width: 75%;
    height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.js"></script>


<div id="carouselDemo" class="carousel slide" data-ride="carousel">
    <div class="carousel-inner">
        <div class="carousel-item active">
            <img class="n1" src="https://via.placeholder.com/700x400">
        </div>
        <div class="carousel-item">
            <img class="n2"  src="https://via.placeholder.com/800x400">
        </div>
        <div class="carousel-item">
            <img class="n3"  src="https://via.placeholder.com/900x400">
        </div>
    </div>
    <a class="carousel-control-prev" href="#carouselDemo" role="button" data-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="sr-only">Previous</span>
    </a>
    <a class="carousel-control-next" href="#carouselDemo" role="button" data-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="sr-only">Next</span>
    </a>
</div>

After reading How to get image size (height & width) using JavaScript? I would suggest to use the plain HTML img width or naturalWidth.

jQuery('#carouselDemo').on('slide.bs.carousel', function(e) {

    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    console.log('slide: Current element Width is: ' + fromelement[0].width);
    console.log('slide: Next element Width is: ' + toelement[0].width);

});

jQuery('#carouselDemo').on('slid.bs.carousel', function(e) {

    var fromelement = jQuery('#carouselDemo .carousel-inner img').eq(e.from);
    var toelement = jQuery('#carouselDemo .carousel-inner img').eq(e.to);

    console.log('slid: Current element Width is: ' + fromelement[0].width);
    console.log('slid: Next element Width is: ' + toelement[0].width);
});
.carousel {
    background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


<div id="carouselDemo" class="carousel slide" data-ride="carousel">
    <div class="carousel-inner">
        <div class="carousel-item active">
            <img src="https://via.placeholder.com/700x400">
        </div>
        <div class="carousel-item">
            <img src="https://via.placeholder.com/800x400">
        </div>
        <div class="carousel-item">
            <img src="https://via.placeholder.com/900x400">
        </div>
    </div>
    <a class="carousel-control-prev" href="#carouselDemo" role="button" data-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="sr-only">Previous</span>
    </a>
    <a class="carousel-control-next" href="#carouselDemo" role="button" data-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="sr-only">Next</span>
    </a>
</div>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
-1

It's because each fires at a different point. https://getbootstrap.com/docs/4.0/components/carousel/

slide.bs.carousel = This event fires immediately when the slide instance method is invoked.

slid.bs.carousel = This event is fired when the carousel has completed its slide transition.

So when you want the next image size, slid works because that image is loaded whereas the slide event fires before that next image is loaded. If you have to use the slide event vs slid for some reason, then you'll have to set a callback of some sort til after the event has completed.

Keith
  • 4,059
  • 2
  • 32
  • 56