Home > database >  Carousel slides appear beneath each other on click
Carousel slides appear beneath each other on click

Time:10-18

I'm using HTML/CSS and vanilla JS. I'm trying to create a simple carousel. However, whenever I click the 'next' button, the following slides show up under the last one. I'm not sure why this is happening. Code snippets are below. Can someone explain why this is happening?

By the way, I have not optimized this page for media queries yet, so it might look a little weird on smaller screens.

const buttons = document.querySelectorAll("[data-carousel-btn]");

buttons.forEach((button) => {
  button.addEventListener("click", () => {
    const offset = button.dataset.carouselBtn === "next" ? 1 : -1;
    const slidesContainer = button
      .closest("[data-carousel]")
      .querySelector("[data-carousel-slides");
    const slides = slidesContainer.querySelectorAll("[data-carousel-slide]");
    const activeSlide = slidesContainer.querySelector("[data-active]");
    const activeSlideIndex = [...slides].indexOf(activeSlide);
    const nextSlideIndex = activeSlideIndex   offset;
    if (nextSlideIndex < 0) {
      slides[slides.length   nextSlideIndex].dataset.active = true;
      return delete activeSlide.dataset.active;
    }
    if (nextSlideIndex >= slides.length) {
      slides[0].dataset.active = true;
      return delete activeSlide.dataset.active;
    }
    slides[nextSlideIndex].dataset.active = true;
    return delete activeSlide.dataset.active;
  });
});
.carouselContainer {
    width: 1000px;
    height: 500px;
    position: relative;

    display: flex;
    justify-content: center;

    border-style: dashed;
    border-color: #010043;
}

.carouselContainer>ul {
    padding: 0;
    margin: 0;
    list-style: none;
}

.slide {
    display: flex;
    width: 400px;
    height: 500px;
    justify-content: center;
    align-items: center;
    

    inset: 0;
    opacity: 0;
    transition-property: opacity;
    transition-duration: 200ms;
    transition-timing-function: ease-in-out;
    transition-delay: 200ms;

    border-style: dashed;
    border-color: var(--magenta6);
    

}

.slide[data-active] {
    opacity: 1;
    z-index: 1;
    transition-delay: 0ms;
}

.slideContent {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-direction: column;

    width: 300px;
    height: 425px;

 
    border-style: dashed;
    border-color: #010043;
}

.slideContent .slideImg {
    margin: 0;
    width: 200px;
    height: 200px;
    border-radius: 100px;
    z-index: 10px;
}

.slideContent .slideTxt {
    border: magenta;
    border-style: dashed;
    height: 500px;
}

.carousel-button {
    position: absolute;
    background: none;
    border: none;
    outline: none;
    font-size: 4rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    color: rgba(255, 255, 255, 0.5);
    cursor: pointer;
    padding: 0 0.5rem;
    border-radius: 0.25rem;
    background-color: rgba(0, 0, 0, 0.1);
    transition: 0.5s;
}

.carousel-button:hover,
.carousel-button:focus {
    background-color: rgba(0, 0, 0, 0.3);
    color: #fff;
}

.carousel-button[data-carousel-btn="prev"] {
    left: 1rem;
}

.carousel-button[data-carousel-btn="next"] {
    right: 1rem;
}
    <section  style="margin: 0 100px 100px 100px;">

        <h2>don't just take it from us!</h2>
        <div  data-carousel>

            <button  data-carousel-btn="prev">
                &#10094;
            </button>
            <button  data-carousel-btn="next">
                &#10095;
            </button>

            <div >
                <ul data-carousel-slides>
                    <li  data-carousel-slide data-active>
                        <div >
                            <div>
                                <img  src="./assets/imgPlaceholder.jpg">
                            </div>
                            <div >
                                <div >
                                    <p style="color:black;">hello</p>
                                </div>
                            </div>
                        </div>

                    </li>
                    <li  data-carousel-slide>
                        <div >
                            <div>
                                <img  src="./assets/imgPlaceholder.jpg">
                            </div>
                            <div >
                                <div >
                                    <p style="color:black;">hello</p>
                                </div>
                            </div>
                        </div>

                    </li>
                    <li  data-carousel-slide>
                        <div >
                            <div>
                                <img  src="./assets/imgPlaceholder.jpg">
                            </div>
                            <div >
                                <div >
                                    <p style="color:black;">hello</p>
                                </div>
                            </div>
                        </div>

                </ul>
            </div>



        </div>


    </section>

CodePudding user response:

part of your problem is your ul element is unstyled, its child li elements are going to stack as they normally do on top of each other. giving the ul element display: flex; will put your li's side by side.

If I were you, I would review each nested element of my tree and figure out its purpose, then remove it if not necessary. for example, div.carouselSlides does not seem like its serving any purpose that the ul could not do itself, at least in this small example.

Also, looking at an established project for implementation ideas (or just using it) might be a good idea . https://swiperjs.com/ is very established with powerful config options

CodePudding user response:

Basically there should be 2 containers:

  1. The element that is the parent of the <button>s and the "frame" that holds each slide. In the example it is article.box.
  2. The element that is the parent of each div.slide in the example is section.frame.

Each container should be position: relative and all children of said containers should be position: absolute. Doing so will:

  1. provide precision positioning of the <button>s and section.frame within the perimeters of article.box
  2. allow all div.slide to hide underneath the visible layers (z-index:0 ) with z-index: -1 and be visible with .active class at z-index: 1.

The JavaScript is optional, it's just written better but function should be basically the same.

View in full page mode, the image placeholder service does not have dynamic images.

const data = [
  {img:"https://placem.at/people?random=1", cap:"People 1"},
  {img:"https://placem.at/places?random=1", cap:"Places 2"},
  {img:"https://placem.at/things?random=1", cap:"Things 3"}
];

const slides = genSlides(data);

const box = document.querySelector('.box')
const buttons = box.querySelectorAll("button");

buttons.forEach((button) => {
  button.addEventListener("click", function(event) {
    const offset = button.classList.contains("next") ? 1 : -1;
    const active = box.querySelector(".active");
    const actIdx = slides.indexOf(active);
    const nextIdx = actIdx   offset;
    active.classList.remove("active");
    if (nextIdx < 0) {
      return slides[slides.length   nextIdx].classList.add("active");
    }
    if (nextIdx >= slides.length) {
      return slides[0].classList.add("active");
    }
    return slides[nextIdx].classList.add("active");
  });
});

function genSlides(array) {
  const frame = document.querySelector(".frame");
  array.forEach(slide => {
    frame.insertAdjacentHTML("beforeend", `
      <div >
        <figure>
          <img src="${slide.img}" width="480">
          <figcaption >${slide.cap}</figcaption>
        </figure>
      </div>`);
  });
  const slides = Array.from(frame.querySelectorAll(".slide"));
  slides[0].classList.add("active");
  return slides;
}
.box {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  width: 96vw;
  min-height: 96vh;
  border: 3px dashed #000;
}

.frame {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-items: center;
  /* The element that is the parent of all .slide should be relative so the 
     slides, which are absolute positioned, can sit within .frame's perimeter */
  position: relative;
}

.slide {
  display: flex;
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
  /* All slides should be out of normal flow */
  position: absolute;
  /* All slides should be in the layer "under" the visible layer (z-index: 0 ) */
  z-index: -1; 
  opacity: 0;
  animation: opacity 0.7s ease-in;
}

.active {
  opacity: 1;
  z-index: 1;
}

figure {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-items: center;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border-style: 1px dashed #000;
}

img {
  object-fit: contain;
}

.cap {
  min-width: 100%;
  text-align: center;
  white-space: pre;
}

button {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 50%;
  z-index: 2;
  padding: 0 0.5rem;
  border: none;
  border-radius: 0.25rem;
  outline: none;
  font-size: 4rem;
  color: rgba(255, 255, 255, 0.5);
  background: none;
  background-color: rgba(0, 0, 0, 0.1);
  transform: translateY(-50%);
  transition: 0.5s;
  cursor: pointer;
}

button:hover,
button:focus {
  color: #fff;
  background-color: rgba(0, 0, 0, 0.3);
}

button:active {
  color: rgba(0, 0, 0, 0.5);
  background: none;
}

.prev {
  left: 1rem;
}

.next {
  right: 1rem;
}
<main>
  <h2>Content Title</h2>
  <article >
    <button >&#10094;</button>
    <button >&#10095;</button>
    <section ></section>
  </article>
</main>

  • Related