How to keep Bootstrap Carousel paused until it enters the viewport

Please can anyone help?

I have a Bootstrap text-only carousel positioned about halfway down my page and what I’d like is for the carousel not to run until the viewer scrolls down and the carousel enters the viewport so the viewer will not miss the first of several slides.

Here is my test page. You’ll find the carousel by scrolling about halfway down. https://cleardirectionhypnotherapy.co.uk

Having only a very limited understanding of JS, I’ve already found and tried a couple of ways of doing this, but neither worked for me, although possibly because I’m not clear whether these scripts are strictly ‘plug-and-play’, and if not, how and where to make minor alterations to my HTML and the JS so that both can connect and do their stuff.

Here are the 2 methods I’ve already tried (and failed) to get working.

https://github.com/moagrius/isOnScreen

https://stackoverflow.com/questions/29733942/how-to-keep-bootstrap-carousel-paused-until-it-enters-in-the-viewport

Can anyone offer advice as to how this can be done with code examples and simple step-by-step instructions? Please share examples and how to integrate.

Until someone more knowledgeable in JS comes along you can use the Intersection observer to detect when the element is in the viewport and then instigate with js rather than the data attribute you are using.

Remove data-ride=“carousel” from here:

<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">

So it looks like this:

<div id="carouselExampleControls" class="carousel slide" >

Then add the following js in a script after your search.js in the html.

 $(document).ready(function() {
      const carousel = document.querySelectorAll(".carousel");
      let options = {
        root: null,
        rootMargin: "0px",
        threshold: 0.1
      };

      function calculateVisibleDiv(entries) {
        entries.map((entry, index) => {
          if (entry.isIntersecting) {
            let myCarousel = "#" + entry.target.id;
            $(myCarousel).addClass("active");
            $(myCarousel).carousel({
              interval: 2000
            });
            $(myCarousel).carousel('cycle');
          }
        });
      }
      let observer = new IntersectionObserver(calculateVisibleDiv, options);
      carousel.forEach((entry) => {
        observer.observe(entry);
      });
    });
 

I rolled it all into a codepen for testing and added some css animation just to make sure it was working.

The slider won’t start until its all visible in the page.

Note this is a once only thing as I assume once it started you wanted it to carry on but the code could be modified to make it stop if it was out of view but I didn’t thing that would be necessary.

Hmm it seems a little buggy on auto starting so I’ll have to revisit tomorrrow unless someone more informed drops by :slight_smile:

Thanks, Paul. I think perhaps this is a similar method to one I’d already tried (and failed) to get working by myself. I guess where I went wrong was not knowing how to modify my existing HTML to tie in with the JS so that both would work together. I’ll give your way a go and see how I get on, and if you get a chance to smooth out any bugs before I get back to you again please post back with updates.

By the way, you mention adding the link to the JS for this beneath the link to the search JS at the bottom of my page. Please can you confirm that the search JS is still necessary to include considering how I’ve now removed the search from the dropdown and all the s drop CSS from my stylesheet?

One other thing I forgot to mention is that when my page loads there is a split second where you can see the top navigation bar appear without the search. The top nav is not as high without the search and when the search loads it becomes higher. I’m guessing this slight delay is not a bug but more a case of the Google search bar being called in from an external source and taking a moment to appear, and also that my server is situated in the USA (Arizona, I think) and may also cause a slight delay?

For some reason, invoking it this way seems to cause it to start paused. It listens for a mouseout.
Insert this below your invocation (line 205):
$(myCarousel).carousel('cycle');

and it should start properly.

Loading the external search would almost certainly be the cause; but if you know how tall the search bar is going to be, you can stop the “it becomes higher” part by predefining the size of its container.

1 Like

Great, thanks that seems to fix it :slight_smile:

I’ve added it to the previous codepen.

As @m_hutley already pointed out you can hold the navbar open with a height (preferably min-height). I would add it to the larger screen media query like this:

@media screen and (min-width:992px){
  .navbar.fixed-top{
    min-height:88px;
  }
}

Thanks to m_hutley and once again, thanks to you, Paul. Regarding the part about the media query, not sharing the same level of knowledge of such matters as you guys, I’m not sure where I’d put a larger screen media query. Should this go in my stylesheet, or in the head of my page, precisely where, and exactly as written in the above reply?

You should put your changes to the bootstrap css in your own custom css file which will follow after all the bootsrap css files. Never directly make changes to any of the bootstrap css or you risk breaking the whole site.

I would stick the media query next to your original custom styles for that nav wherever it is that you have placed them. In that way it keeps the styles together although it does mean you have multiple media queries.

Alternatively set up one media query at the end of the css and put all the rules that go in that media together. For a small site its ok but on a large site you generally want your changes next to the original rules so that you can make sense of them. However everyone has their own take on this so its a choice you make.

So I’d put this

@media screen and (min-width:992px){
  .navbar.fixed-top{
    min-height:88px;
  }
}

in my custom stylesheet either underneath the styling for the navigation or at the very bottom of my stylesheet. Is this correct?

I think the only other media query that I had was the one you gave me relating to the s drop z index settings to catch the clicks which were different from mobile to desktop. As we are no longer running with the search in the drop-down that media query would be redundant and so I removed it along with all of the other sdrop-specific CSS. Was this right?

There was one other matter we briefly touched on earlier that I’m still not clear about and that is the search.js which was added to control the search in the drop-down.

Again, as we are no longer running our search bar in the dropdown presumably the search.js can also go?

Yes that can be removed now :slight_smile:

Thanks, Paul. I’ll make the changes to my page and get these uploaded as soon as I can. I’ll be in touch again when this has been done. Until then, thanks again, and enjoy your evening :slight_smile:

1 Like

Hi there :slight_smile:

I’ve added the media query to fix the height of the navbar and this appears to be working as expected. I’ve also removed the link for the search.js and I’ve added the updated HTML, CSS, and JS for my carousel directly from the codepen you created.

However, I’m not certain if the JS I’ve copied and pasted from the codepen includes

$(myCarousel).carousel('cycle');

because while the carousel most certainly doesn’t launch until it enters the viewport, the rotation doesn’t begin until I manually click the forward arrow.

Is this because the extra line of code isn’t included and, if yes, where in the JS should it be entered?

The other issue is that my actual slides will rotate too fast, not allowing sufficient time to be read. I’d like to add data-interval=“8000” (8 seconds delay for each slide) here

<div id="carouselExampleControls" class="carousel slide" data-interval="8000">

only this doesn’t work and the slides still change every couple of seconds so I’ve removed the data-interval again. Is there an easy fix for this?

Moving on, and looking at the HTML for Google search and the following div

<div class="gcse-search"></div>

gcse-search links to my stylesheet but no values have been assigned, and yet if I remove gcse-search from my HTML this breaks the search bar.

I just need to be clear on my understanding of why this is. Please can you explain?

Also, in my CSS I have the following block of code

.my-search {
  padding-top: 7px;
  padding-left: 10px;
  border-left: 0px solid #fff;
  margin-right:-50px;
}
.input-group input.gsc-input {
  width: 50px !important;
  transition: 0.5s ease;
}
.input-group input.gsc-input:focus {
  width: 100px !important;
}
.input-group .gsc-control-cse {
  border: none;
  background: transparent;
}
.my-search .input-group {
  background: transparent;
}
#gs_tti50 input {
  background-position: 100% 50% !important;
}
.navbar-custom.navbar-expand-lg .navbar-nav {
  align-items: center;
}
.gcse-search{
	border:0;
}

and yet from looking at my HTML I’m unable to identify divs that relate to some of this styling, so what exactly needs to stay and what needs to go so there is nothing unnecessary and everything still works as expected?

Any advice is appreciated.

No, that’s been missed out (I probably didn’t save my local codepen before you copied it). It should be this:

 $(document).ready(function() {
      const carousel = document.querySelectorAll(".carousel");
      let options = {
        root: null,
        rootMargin: "0px",
        threshold: 0.1
      };

      function calculateVisibleDiv(entries) {
        entries.map((entry, index) => {
          if (entry.isIntersecting) {
            let myCarousel = "#" + entry.target.id;
            $(myCarousel).addClass("active");
            $(myCarousel).carousel({
              interval: 2000
            });
            $(myCarousel).carousel('cycle');
          }
        });
      }
      let observer = new IntersectionObserver(calculateVisibleDiv, options);
      carousel.forEach((entry) => {
        observer.observe(entry);
      });
    });

That’s where google places all its html for your search bar. If you open developer tools and look at the page you will see that the div above has been replaced with loads of new html.

<div id="___gcse_0"><div class="gsc-control-cse gsc-control-cse-es"><div class="gsc-control-wrapper-cse" dir="ltr"><form class="gsc-search-box gsc-search-box-tools" accept-charset="utf-8"><table cellspacing="0" cellpadding="0" role="presentation" class="gsc-search-box"><tbody><tr><td class="gsc-input"><div class="gsc-input-box" id="gsc-iw-id1"><table cellspacing="0" cellpadding="0" role="presentation" id="gs_id50" class="gstl_50 gsc-input" style="width: 100%; padding: 0px;"><tbody><tr><td id="gs_tti50" class="gsib_a"><input autocomplete="off" type="text" size="10" class="gsc-input" name="search" title="buscar" aria-label="buscar" id="gsc-i-id1" dir="ltr" spellcheck="false" style="width: 100%; padding: 0px; border: none; margin: 0px; height: auto; background: url(&quot;https://www.google.com/cse/static/images/1x/es/branding.png&quot;) left center no-repeat rgb(255, 255, 255); outline: none;"></td><td class="gsib_b"><div class="gsst_b" id="gs_st50" dir="ltr"><a class="gsst_a" href="javascript:void(0)" title="Borrar contenido del cuadro de búsqueda" role="button" style="display: none;"><span class="gscb_a" id="gs_cb50" aria-hidden="true">×</span></a></div></td></tr></tbody></table></div></td><td class="gsc-search-button"><button class="gsc-search-button gsc-search-button-v2"><svg width="13" height="13" viewBox="0 0 13 13"><title>buscar</title><path d="m4.8495 7.8226c0.82666 0 1.5262-0.29146 2.0985-0.87438 0.57232-0.58292 0.86378-1.2877 0.87438-2.1144 0.010599-0.82666-0.28086-1.5262-0.87438-2.0985-0.59352-0.57232-1.293-0.86378-2.0985-0.87438-0.8055-0.010599-1.5103 0.28086-2.1144 0.87438-0.60414 0.59352-0.8956 1.293-0.87438 2.0985 0.021197 0.8055 0.31266 1.5103 0.87438 2.1144 0.56172 0.60414 1.2665 0.8956 2.1144 0.87438zm4.4695 0.2115 3.681 3.6819-1.259 1.284-3.6817-3.7 0.0019784-0.69479-0.090043-0.098846c-0.87973 0.76087-1.92 1.1413-3.1207 1.1413-1.3553 0-2.5025-0.46363-3.4417-1.3909s-1.4088-2.0686-1.4088-3.4239c0-1.3553 0.4696-2.4966 1.4088-3.4239 0.9392-0.92727 2.0864-1.3969 3.4417-1.4088 1.3553-0.011889 2.4906 0.45771 3.406 1.4088 0.9154 0.95107 1.379 2.0924 1.3909 3.4239 0 1.2126-0.38043 2.2588-1.1413 3.1385l0.098834 0.090049z"></path></svg></button></td><td class="gsc-clear-button"><div class="gsc-clear-button" title="borrar resultados">&nbsp;</div></td></tr></tbody></table></form><div class="gsc-results-wrapper-overlay"><div class="gsc-results-close-btn" tabindex="0"></div><div class="gsc-positioningWrapper"><div class="gsc-tabsAreaInvisible"><div aria-label="refinement" role="tab" class="gsc-tabHeader gsc-inline-block gsc-tabhActive">Búsqueda personalizada</div><span class="gs-spacer"> </span></div></div><div class="gsc-positioningWrapper"><div class="gsc-refinementsAreaInvisible"></div></div><div class="gsc-above-wrapper-area-invisible"><div class="gsc-above-wrapper-area-backfill-container"></div><table cellspacing="0" cellpadding="0" role="presentation" class="gsc-above-wrapper-area-container"><tbody><tr><td class="gsc-result-info-container"><div class="gsc-result-info-invisible"></div></td><td class="gsc-orderby-container"><div class="gsc-orderby-invisible"><div class="gsc-orderby-label gsc-inline-block">Ordenar por:</div><div class="gsc-option-menu-container gsc-inline-block"><div class="gsc-selected-option-container gsc-inline-block"><div class="gsc-selected-option">Relevance</div><div class="gsc-option-selector"></div></div><div class="gsc-option-menu-invisible"><div class="gsc-option-menu-item gsc-option-menu-item-highlighted"><div class="gsc-option">Relevance</div></div><div class="gsc-option-menu-item"><div class="gsc-option">Date</div></div></div></div></div></td></tr></tbody></table></div><div class="gsc-adBlockInvisible"></div><div class="gsc-wrapper"><div class="gsc-adBlockInvisible"></div><div class="gsc-resultsbox-invisible"><div class="gsc-resultsRoot gsc-tabData gsc-tabdActive"><div><div class="gsc-expansionArea"></div></div></div></div></div></div><div class="gsc-modal-background-image" tabindex="0"></div></div></div></div>

It’s this new html that my css is referring to and sets the width of the input among other things. Without the css you would get the default search buttons appearance.

Thanks. This all makes sense. I’ve updated the JS for my carousel and rotation now begins as soon as it’s in the viewport. I’ve also set the slide duration to ‘8000’ in the JS. I’ve experimented with the rounded image, positioning it on my page in roughly the position I’d like it to appear. Unfortunately, as the viewport reduces in size my image doesn’t seem to respond in the same way as the image in the example I posted previously.

The image here https://ishadeed.com/ appears to remain fixed in exactly the same position (upper lefthand corner) regardless of the viewport size and also appears to maintain one larger fixed dimension until the viewport scales down to a certain size at which point it changes to a smaller fixed dimension. My image seems to move around the screen colliding with other elements even though I’ve tried position absolute, fixed, and relative.

Is there a way for me to achieve the same results?

Oh, and one other thing. When I checked the developer tools, and under the ‘console’ tab, it is reporting

This page uses the non standard property “zoom”. Consider using calc() in the relevant property values, or using “transform” along with “transform-origin: 0 0”.

Is this something I should be concerned about, and if yes, how do I fix it without breaking my page?

In the past, I’ve always used WC3 Validator to check my pages for errors. Is it better to use developer tools to check for errors, stick with the validator, or use both?

I’m a little confused :slight_smile:

That image in the link you showed is neither fixed or still. Its just a normal image that scrolls with the document. It’s not doing anything special at all except that a media query makes it smaller at a certain point. There is nothing different to that element than any other element on your page.

The image is in a column of its own with the content next to it in another column. Making columns is what bootstrap was designed for so please go the bootstrap page and try out their layout tutorials as there are specific things you have to do to create columns (e.g. most importantly use the .row and .col classes in the specific order as mentioned in the documentation. never change the left and right margins or padding on the container or on the row or colmns as these are all tied together). It’s all explained in detail on the bootstrap site so I won’t go into detail here.

I’ve put up a very rough example with the column in place.

However it needs refining because you did not have a closing article tag (I added one in for you but then that leaves the rest of the page a bit unstructured). It shouldn’t really have been an article tag anyway as it seems to be your main content.

Use both but be aware both are not perfect as the newer css properties are missing from the w3c validator and will throw an error in mistake. You still need to keep an eye on what’s going on and learn how to read the errors and eventually you will know which ones to ignore.

I couldn’t see where you were using zoom but its probably in the google search code and if so you can ignore it.:slight_smile:

Thanks, Paul. I’ve only just read your reply and will now go and read up some more about the Bootstrap rows and columns and experiment with this further. You mention the article tag, and how this is not the correct choice. Would I be better using ‘main’ because ‘article’ is meant to separate independent self-contained parts of an HTML document while ‘main’ is meant to indicate where the main part of the document?

1 Like

I’ve had another read about Bootstrap columns and rows and taken a look at my page to get a better idea of how I’d apply this to the section where I’d like my image to be positioned.

Ideally, I’d like the rounded image to be positioned in the upper right-hand corner of my header on top of the shaded background behind the text, approximately where I’ve added the row of XXXX on my test page, and for it to stay in this position no matter the dimensions of the viewport.

Here is the existing code for the header

<!-- Header -->
<header class="bg-primary py-5 mb-5 my-header"> 
<div class="container h-100">
<div class="row h-100 align-items-center">
<div class="col-lg-12"> 
<h1 class="display-4 text-white mt-5 mb-2">Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem &nbsp;&nbsp;&nbsp;&nbsp;XXXX</h1>
<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
<div class="img-credit">Lorem ipsum dolor sit amet</div>

To create a single column in which to position my image should I change <div class="col-lg-12"> to <div class="col-lg-11"> for all of the text and then add <div class="col-lg-1"> for my image?

I’ve experimented with this for a while but I’m still not able to get this to work or know exactly where to put the code for my new column so it sits to the extreme right of the text while still being on top of the mask or overlay behind the text.

Obviously, I’m missing the point here and there must be considerably more to making this work properly.

Please are you able to offer any further advice and code examples, and, how would doing this affect the CSS for what is already present?

Following up on my recent posts, and most importantly to say a very special thank you for all of your help with my Bootstrap carousel, Google Search Bar, and everything else I’ve asked assistance with. :smile:

Yesterday evening I spent more time reading up on the principles of the Bootstrap grid system and if my understanding is correct, placing my rounded image in the position I’d suggested would be no good because as the size of the viewport reduces so the columns stack and what’s to the right would go beneath what’s to the left, whereas placing my image to the left of my page as in the website I’d referred to, and also in your Codepen means that it’s in the left-most column and will always stay put without tiling regardless of the size of the viewport.

I realise it must be frustrating discussing such matters with someone like as me who has limited knowledge of the subject and for that, I apologise. With this in mind, I’ll be spending more time educating myself with the intention of being able to solve more of my problems relating to Bootstrap coding without the need to ask so many unnecessary questions. :slight_smile:

I’ll continue to work on my page following your advice, be sure to test thoroughly and check for errors using more than one tool, and will post back with updates.

Thanks again, Paul.

You can just float it there.

The text will wrap as required.:slight_smile:

Floats must come first. The floated element must be before the element you want to wrap in the html.