Ein Produkt-Slider mit dem Shopify-Theme Dawn

Technisches

A product slider with the Shopify theme Dawn

Dawn has been Shopify’s default theme for almost a year now; it brings a number of improvements and advanced options, but also has one drawback that people tend to grumble about in the forums: In the default product view, the images are just shown all together, with strange gaps and, depending on the aspect ratios and viewports, bizarre spacing issues.

Consequently, every now and then the wish for a „classic“ slider that only shows one large picture and a bunch of thumbnails below comes up. Unfortunately, the first instructions that came out often stop working after a few (not controllable by the user) updates of the theme by Shopify. Most remaining instructions rely on a complete external JavaScript library or custom apps. This seems overkill to me, which is why I created a simple solution that we’ve been using over at Ceramics Studio Kleistone for a while now.

Our goal is a slider with small thumbnails under the images without wild jumps when clicking through.

Preparations

To make the changes, we need to switch to Shopify’s code editor. To do this, click on „Online Store“ on the left, then in the overview page click on „Actions“ and then „Edit Code“. An editor window will open with a directory structure on the left and the file view on the right. Now search for „main-product“ in the form field at the top left. The „main-product.liquid“ should now appear in the list view. Left click once, then the content of this file will be displayed large in the code editor on the right.

Example of a view of the code editor in Shopify.

Important! Now click once in the file editor, select everything (Ctrl + A on Windows, Command + A on MacOS) and copy the contents to a text file in Notepad, for example, and save it. This is the lifeboat in case something goes wrong! If this is necessary, go the other way around: in Notepad select everything, copy, in the editor select all contents of the file, delete, paste contents.

I recommend making the following changes during a quiet period – not shortly after a newsletter mailing or social media campaign. After all, in the meantime, there will be exactly no photos on the page.
The changes

Find the following place in the file:

<slider-component class="slider-mobile-gutter">

and change it so that the old „slider“ is no no longer shown:

<slider-component class="slider-mobile-gutter"  style="display: none;">

Now, right above this, insert the following:

 <style>
        .product-gallery {
          display: flex;
          flex-wrap: wrap;
          position: relative;
        }

        .product-gallery > img {
          display: none;
          height: 400px;
          width: 100%;
          max-width: 760px;
          object-fit: contain;
        }

        .product-gallery img:first-of-type {
          display: block;
        }

        .product-gallery button {
          height: 24px;
          width: 24px;
          position: absolute;
          z-index: 5;
 	  top: calc(50% - 38px);
          cursor: pointer;
          color: #fff;
          -webkit-appearance: none;
          -moz-appearance: none;
          appearance: none;
          box-shadow: none;
          border-radius: 0;
          border: 0;
          background: none;
          padding: 0;
        }
        
        .product-gallery svg {
          fill: rgb(96, 95, 90);
        }

        .product-gallery .prev {
          left: 5px;
          transform: rotate(180deg)
        }

        .product-gallery .next {
          right: 5px;
        }

        .product-gallery.initialized > img {
          display: none;
        }

        .product-gallery.initialized > img.active {
          display: block;
        }

        .product-gallery .thumbs {
          padding-top: 8px;
          width: 100%;
        }

        .product-gallery .thumbs img {
          cursor: pointer;
          margin-right: 8px;
          display: inline-block;
          max-height: 50px;
        }
      </style>
      <div class="product-gallery grid">
         {%- for media in product.media -%}
              <img src="{{ media | img_url: '720x' }}" />
          {%- endfor -%}
      </div>
      <script>
        const productGalleryContainer = document.querySelector(".product-gallery");
        const images =  productGalleryContainer.querySelectorAll("img");
        const imageArray = Array.from(images);
        const imageSources = imageArray.map(img => {
         return img.getAttribute("src");
        });

        const thumbContainer = document.createElement("div");
        thumbContainer.setAttribute("class", "thumbs");
        productGalleryContainer.append(thumbContainer);

        const svgArrow = '<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-submit" viewBox="0 0 1024 1024"><path d="M1023.998 511.724v-6.44a4.818 4.818 0 00-1.605-3.215l-.005-.005c0-1.61-1.61-1.61-1.61-3.22s-1.61-1.61-1.61-3.22c-.89 0-1.61-.72-1.61-1.61L652.074 115.649c-6.058-5.789-14.286-9.354-23.346-9.354s-17.288 3.564-23.358 9.366l.013-.013c-6.101 5.61-9.909 13.631-9.909 22.541s3.81 16.931 9.888 22.52l.022.02 307.522 318.793H32.201C14.416 479.522 0 493.939 0 511.723s14.417 32.201 32.201 32.201h887.145L605.384 862.717a32.062 32.062 0 00-8.429 21.72c0 9.19 3.851 17.481 10.025 23.347l.014.013c5.61 6.101 13.631 9.909 22.541 9.909s16.931-3.81 22.52-9.888l.02-.022 363.874-370.315c0-1.61 0-1.61 1.61-3.22.89 0 1.61-.72 1.61-1.61 0-1.61 1.61-1.61 1.61-3.22h1.61v-3.22a4.81 4.81 0 001.608-3.203l.002-.017v-11.27z"></path></svg>'

        const prevButton = document.createElement("button");
        prevButton.innerHTML = svgArrow;
        prevButton.classList.add("prev");
        prevButton.addEventListener("click", (e) => {
          e.preventDefault();
          const activeImage = productGalleryContainer.querySelector("img.active");
          let currentIndex = [...activeImage.parentNode.children].indexOf(activeImage);

          if (currentIndex === 0) {
            currentIndex = images.length;
          }
          images.forEach((image, index) => {
             image.classList.toggle("active", index === currentIndex - 1);
          })
        })
        productGalleryContainer.append(prevButton);


        const nextButton = document.createElement("button");
        nextButton.innerHTML = svgArrow;
        nextButton.classList.add("next");
        nextButton.addEventListener("click", (e) => {
          e.preventDefault();
          const activeImage = productGalleryContainer.querySelector("img.active");
          let currentIndex = [...activeImage.parentNode.children].indexOf(activeImage);

          if (currentIndex + 1 === images.length) {
            currentIndex = -1
          }
          images.forEach((image, index) => {
             image.classList.toggle("active", index === currentIndex + 1);
          })
        })
        productGalleryContainer.append(nextButton);


        imageSources.forEach((imageSource, index) => {
          const thumb = document.createElement("img");
          thumb.setAttribute("src", imageSource);
          thumb.addEventListener("click", (e) => {
            e.preventDefault();
            images.forEach(image => {
              image.classList.toggle("active", image.getAttribute("src") === imageSource);
            })
            const correspondingImage = document.querySelector(`.product-gallery > img[src='${imageSource}']`);
            correspondingImage.classList.add("active");
          })
          thumbContainer.append(thumb);
        })
        images[0].classList.add("active");
        productGalleryContainer.classList.add("initialized");
      </script>

Yes, this is a relatively large block of code, but this ensures that we don’t have to fiddle with multiple files. The actual extra work for the browser for the repeatedly load styles and scripts is minimal.

Hit the „Save“ button and that’s it! The following modifications are possible for people who are confident with some CSS:

.product-gallery > img {
   ... /* keep everything before the following line */
   object-fit: contain; /* try'cover' instead of 'contain'*/
}

 .product-gallery button {
         ... /* keep everything before the following line */
         color: #fff; /* this can be any other HTML/hex color */
         ...
}

This guide was created for Dawn version 2.1.0. I hope this helps others trying to get a product slider into their Shopify themes!

Previous

Comments are closed.