'Why is my auto-play image carousel with manual buttons and fade "jumping"?

What I want:

So I am developing an image carousel that automatically rotates between 3 images using a crossfade. It also has left and right arrow buttons to be able to manually flip through them as well. Everything starts fine until you click on one of the arrows.

The Problem:

When you manually switch to another image, the carousel begins to "jump." And what I mean by that is that the images begin to change dramatically faster, and the fade animation also stops (or becomes janky at best). Sometimes the images will also stop transitioning for a few seconds and then return to rapid changing.

What I think and what I've Tried:

Therefore I believe the manual buttons are messing with the fade CSS and the Auto play timing. I have tried changing up the animation times but have not found any solution to the fade animation time changes, nor to the overall time in the JavaScript file. I've also tried switching up methods and trying out other peoples' code but still cannot get it to work.

The HTML:

<div class="sliderContainer">

<!-- Header that lays on top of Hero Banner -->
<div class="topBanner">
    <div class="headerWrapper container">
        <h2><?php echo get_option('blogname'); ?></h2>
        <h1><?php echo get_option('blogdescription'); ?>
        <hr>
    </div>    
</div>

<!-- Slider -->
<div class="slider fade">
    <img src="<?php echo get_theme_mod('ab_hero_photo_one'); ?>" alt="<?php echo get_theme_mod('ab_hero_photo_one_alt_text'); ?>">
</div>

<div class="slider fade">
    <img src="<?php echo get_theme_mod('ab_hero_photo_two'); ?>" alt="<?php echo get_theme_mod('ab_hero_photo_two_alt_text'); ?>">
</div>

<div class="slider fade">
    <img src="<?php echo get_theme_mod('ab_hero_photo_three'); ?>" alt="<?php echo get_theme_mod('ab_hero_photo_three_alt_text'); ?>">
</div>

<a class="prev" onclick="plusSlides(-1)">&#10094;</a>
<a class="next" onclick="plusSlides(1)">&#10095;</a>

The CSS:

    .headerContainer .sliderContainer {
  position: relative;
}

//THE HEADER
.headerContainer .sliderContainer .topBanner {
  background: transparent;
  position: absolute;
  top: 0;
  width: 100%;
  z-index: 1;
  background-color: rgba(1, 2, 3, 0.5);
  min-height: 85px;
}
.headerContainer .sliderContainer .topBanner .headerWrapper {
  padding-top: 6px;
  text-align: center;
  margin: auto;
}
.headerContainer .sliderContainer .topBanner .headerWrapper h2 {
  font-size: 1.5em;
  color: #F8F8FF;
}
.headerContainer .sliderContainer .topBanner .headerWrapper h1 {
  font-size: 2em;
  transform: translateY(-17px);
  color: #F8F8FF;
}
.headerContainer .sliderContainer .topBanner .headerWrapper hr {
  width: 85%;
  margin: auto;
  transform: translateY(-8px);
  color: #F8F8FF;
}


//SLIDES
.headerContainer .sliderContainer .slider {
  display: none;
  max-height: 575px;
  width: 100%;
  overflow: hidden;
}
.headerContainer .sliderContainer .slider img {
  height: 575px;
  width: 100%;
  -o-object-fit: cover;
     object-fit: cover;
  -o-object-position: center;
     object-position: center;
}
.headerContainer .sliderContainer .active {
  display: inline-block;
}

//FADE ANIMATION
.headerContainer .sliderContainer .fade {
  opacity: 0;
  -webkit-animation-name: fade;
          animation-name: fade;
  -webkit-animation-duration: 5s;
          animation-duration: 5s;
  -webkit-animation-iteration-count: infinite;
          animation-iteration-count: infinite;
}
@-webkit-keyframes fade {
  0% {
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  75% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes fade {
  0% {
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  75% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

//BUTTONS
.headerContainer .sliderContainer .prev, .headerContainer .sliderContainer .next {
  position: absolute;
  cursor: pointer;
  top: 50%;
  width: auto;
  padding: 16px;
  margin-top: -22px;
  color: white;
  font-weight: bold;
  font-size: 18px;
  transition: 0.6s ease;
  border-radius: 0 3px 3px 0;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
.headerContainer .sliderContainer .next {
  right: 0;
  border-radius: 3px 0 0 3px;
}
.headerContainer .sliderContainer .prev:hover, .headerContainer .sliderContainer .next:hover {
  background-color: rgba(0, 0, 0, 0.8);
}
.headerContainer .sticky {
  position: fixed;
  top: 0;
  width: 100%;
}

The JS:

var slideIndex = 1;
showSlides(slideIndex);

function plusSlides(n) {
    showSlides(slideIndex += n);
}

function currentSlide(n) {
    showSlides(slideIndex = n);
}

function showSlides(n) {
    var i;
    var slides = document.getElementsByClassName("slider");
    if (n > slides.length) { slideIndex = 1 }
    if (n < 1) { slideIndex = slides.length }
    for (i = 0; i < slides.length; i++) {
        slides[i].style.display = "none";
    }
    slides[slideIndex - 1].style.display = "block";
}

var slideIndex = 0;
showSlides();

function showSlides() {
    var i;
   var slides = document.getElementsByClassName("slider");
   for (i = 0; i < slides.length; i++) {
       slides[i].style.display = "none";
   }
   slideIndex++;
   if (slideIndex > slides.length) { slideIndex = 1 }
   slides[slideIndex - 1].style.display = "block";
   setTimeout(showSlides, 5000); 
}

Can anyone help me understand why the timing is off and how to make the buttons and autoplay work together?

(Also, I cannot for the life of me make the images fade into each other. Currently they are fading in and out of white, but I would prefer if you can see the next image coming in as the current image is fading out and revealing it. But this is an optional fix at this point)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source