skip to Main Content

This is a slideshow HTML that’s generated with 3 images and shown are the Prev << and Next >> buttons.

<div class="wp-block-gallery">
    <div class="wpcookie-slide"> 
        <img decoding="async" loading="lazy" src="image1.jpg" alt="image"> 
    </div>
    <div class="wpcookie-slide"> 
        <img decoding="async" loading="lazy" src="image2.jpg" alt="image"> 
    </div>
    <div class="wpcookie-slide"> 
        <img decoding="async" loading="lazy" src="image3.jpg" alt="image">
    </div>
    <span class="wpcookie-controls wpcookie-left-arrow"> << Prev </span> 
    <span class="wpcookie-controls wpcookie-right-arrow"> Next >> </span> 
</div>

I want to hide the << Prev & Next >> buttons when there’s just 1 image in the slideshow. It creates a bad UX for the users to show the arrows when there’s only 1 image in the slideshow.

Here’s the JS code that generates the slideshow:

document.querySelectorAll(".wp-block-gallery")?.forEach( slider => {
    var src = [];
    var alt = [];
    var img = slider.querySelectorAll("img");
    /*Code by MKS Starts */
    var singleImage = img.length === 1; 
    var leftArrow = document.querySelector('.wpcookie-controls.wpcookie-left-arrow'); 
    var rightArrow = document.querySelector('.wpcookie-controls.wpcookie-right-arrow'); 
    rightArrow.style.pointerEvents = 'none';
    leftArrow.style.pointerEvents = 'none';
    /*Code by MKS Ends*/
    img.forEach( e => { src.push(e.src);   if (e.alt) { alt.push(e.alt); } else { alt.push("image"); } })
    let i = 0;
    let image = "";
    let myDot = "";
    src.forEach ( e => { image = image + `<div class="wpcookie-slide" > <img decoding="async" loading="lazy" src="${src[i]}" alt="${alt[i]}" > </div>`; i++ })
    i = 0;
    src.forEach ( e => { myDot = myDot + `<span class="wp-dot"></span>`; i++ })
    let dotDisply = "none";
    if (slider.classList.contains("dot")) dotDisply = "block";    
    const main = `<div class="wp-block-gallery">${image}<span class="wpcookie-controls wpcookie-left-arrow"  > << Prev </span> <span class="wpcookie-controls wpcookie-right-arrow" > Next >> </span> <div class="dots-con" style="display: ${dotDisply}"> ${myDot}</div></div> `       
    slider.insertAdjacentHTML("afterend",main  );
    slider.remove();
})

document.querySelectorAll(".wp-block-gallery")?.forEach( slider => { 
var slides = slider.querySelectorAll(".wpcookie-slide");
var dots = slider.querySelectorAll(".wp-dot");
var index = 0;

slider.addEventListener("click", e => {if(e.target.classList.contains("wpcookie-left-arrow")) { prevSlide(-1)} } )
slider.addEventListener("click", e => {if(e.target.classList.contains("wpcookie-right-arrow")) { nextSlide(1)} } )
function prevSlide(n){
  index+=n;
  console.log("prevSlide is called");
  changeSlide();
}
function nextSlide(n){
  index+=n;
  changeSlide();
}
changeSlide();
function changeSlide(){   
  if(index>slides.length-1)
    index=0;  
  if(index<0)
    index=slides.length-1;  
    for(let i=0;i<slides.length;i++){
      slides[i].style.display = "none";
      dots[i].classList.remove("wpcookie-slider-active");      
    }
    slides[index].style.display = "block";
    dots[index].classList.add("wpcookie-slider-active");
}
 } )

3

Answers


  1. To hide the "Prev" and "Next" buttons when there’s only one image in the slideshow, you can add a check in your JavaScript code to determine the number of images. If there’s only one image, you can either remove the buttons or hide them using CSS.

    var singleImage = img.length === 1;

    Then grab the html element and update the css.

    Login or Signup to reply.
  2. Assuming that your HTML is accurate to your particular situation, then CSS could achieve this; explanatory comments are in the code below:

    /* generic reset, and removal of (some) browser defaults */
    *,::before,::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    /* ensuring the <HTML> element takes all availble space on
       the block (vertical, in most European languages) axis: */
    html {
      block-size: 100%;
    }
    
    /* setting the <body> to take all of the dynamic viewport
       block size (1dvb is equivalent to 1vh or 1% of the
       vertical space, in left-to-right, top-to-bottom languages): */
    body {
      block-size: 100dvb;
    }
    
    main {
      /* setting the size of the <main> element along its inline-
         axis to 80dvi (dynamic viewport inline size), with an
         absolute minimum size of 20rem and maximum size of 1200px: */
      inline-size: clamp(20rem, 80dvi, 1200px);
      /* margin auto on the inline axis: */
      margin-inline: auto;
    }
    
    .wp-block-gallery {
      display: flex;
      gap: 1rem;
      justify-content: space-between;
      padding: 1rem;
    }
    
    .wpcookie-controls {
      align-self: stretch;
      background-color: lavenderblush;
      display: grid;
      cursor: pointer;
      /* I've made this partially transparent for purposes of the
         demo, but in production "opacity: 0" or "display: none"
         may be preferable: */
      opacity: 0.4;
      padding: 0.5rem;
      place-content: center;
    }
    
    .wpcookie-left-arrow {
      border-radius: 1rem 0 0 1rem;
      /* moving the element to the first position of the layout order,
         without rearranging the DOM: */
      order: -1;
    }
    
    .wpcookie-right-arrow {
      border-radius: 0 1rem 1rem 0;
    }
    
    /* here we're selecting all .wpcookie-controls elements that follow
       a .wpcookie-slide element tha itself follows a previous
       .wpcookie-slide element, using the general sibling combinator
       (the '~' character, the 'tilde'): */
    .wpcookie-slide ~ .wpcookie-slide ~ .wpcookie-controls {
      opacity: 1;
    }
    <!-- the <main> is irrelevant to the demo, it just made it easier to inspect
         and copy the html in JS Fiddle: -->
    <main>
        <div class="wp-block-gallery">
          <div class="wpcookie-slide">
            <img decoding="async" loading="lazy" src="//picsum.photos/id/10/100/200" alt="image">
          </div>
          <div class="wpcookie-slide">
            <img decoding="async" loading="lazy" src="//picsum.photos/id/20/100/200" alt="image">
          </div>
          <div class="wpcookie-slide">
            <img decoding="async" loading="lazy" src="//picsum.photos/id/30/100/200" alt="image">
          </div>
          <span class="wpcookie-controls wpcookie-left-arrow">«Prev</span>
          <span class="wpcookie-controls wpcookie-right-arrow">Next »</span>
        </div>
        
        <div class="wp-block-gallery">
          <div class="wpcookie-slide">
            <img decoding="async" loading="lazy" src="//picsum.photos/id/40/100/200" alt="image">
          </div>
          <!-- please note the change of '<<' to the &laquo; entity, because
               "<" characters must be escaped in HTML, otherwise the browser
               (and prettifying scripts) can get confused about whether there's
               a new element, and since there's an actual character that can be
               used I prefer to use it: -->
          <span class="wpcookie-controls wpcookie-left-arrow">
            « Prev </span>
          <!-- it's unnecessary to escape the ">" characters, but for the
               purpose of 'balance' and continuity, and because there's a
               specific character available, I also replaced the ">>" with
               the &raquo; character entity: -->
          <span class="wpcookie-controls wpcookie-right-arrow"> Next &raquo; </span>
        </div>
    </main>

    JS Fiddle demo.

    References:

    Login or Signup to reply.
  3. I am not entirely sure what you want to achieve with your slider. But the way you implemented it looks overly complicated to me. Here is a shorter snippet proving some basic functionality to any number of galleries on the current page. The "prev" and "next" buttons will be hidden for any gallery containing less than 2 pictures.

    document.querySelectorAll(".wp-block-gallery").forEach(gal => {
      const pics = gal.querySelectorAll("div"), n=pics.length;
      let current = 0;
      const show = inc => {
        current = (current+n+inc)%n;
        pics.forEach((p, i) => p.style.display = current == i ? "" : "none");
      }
      gal.addEventListener("click", ev => ev.target.dataset.inc && show(+ev.target.dataset.inc));
      if (n<=1) gal.querySelectorAll(".wpcookie-controls").forEach(el=>el.style.display="none")
      show(0);
    })
    .wpcookie-controls {cursor:pointer}
    <h2>Gallery 1</h2>
    <div class="wp-block-gallery">
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/100/300/200" alt="image"> 
        </div>
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/102/300/200" alt="image"> 
        </div>
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/103/300/200" alt="image">
        </div>
        <span class="wpcookie-controls" data-inc="-1"> << Prev </span> 
        <span class="wpcookie-controls" data-inc="1"> Next >> </span> 
    </div>
    <h2>Gallery 2 (one picture only)</h2>
    <div class="wp-block-gallery">
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/104/300/200" alt="image"> 
        </div>
        <span class="wpcookie-controls" data-inc="-1"> << Prev </span> 
        <span class="wpcookie-controls" data-inc="1"> Next >> </span>     
    </div>
    <h2>Gallery 3</h2>
    <div class="wp-block-gallery">
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/108/300/200" alt="image"> 
        </div>
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/106/300/200" alt="image"> 
        </div>
        <div class="wpcookie-slide"> 
            <img decoding="async" loading="lazy" src="https://picsum.photos/id/107/300/200" alt="image">
        </div>
        <span class="wpcookie-controls" data-inc="-1"> << Prev </span> 
        <span class="wpcookie-controls" data-inc="1"> Next >> </span> 
    </div>

    I use delegated event handling on each gallery (gal). However, the added "click" event will only lead to an action if a data-inc attribute exists for the clicked element. In that case the value of that attribute (ev.target.dataset.inc) will be interpreted as an increment to be added to the current (="to be shown") index.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search