Tips for navigating between slides on a CSS carousel?

I am currently in the process of creating a CSS-based carousel

.carousel {
    -webkit-scroll-snap-type: x mandatory;
    -ms-scroll-snap-type: x mandatory;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    overflow-x: scroll;
    scrollbar-width: none;
    -ms-overflow-style: none;
    width: 500px;
    display: flex;
    flex-direction: row;
    outline: 1px #000 solid;
}

.slide {
    background-color: #ccc;
    width: 100%;
    height: 100px;
    scroll-snap-align: start;
    flex-shrink: 0
}

.prev {
translatex(-500px)
}

next {
translatex(500px)
}
<div class="carousel">
<div class="slide">1</div>
<div class="slide">2</div>
<div class="slide">3</div>
</div>

<button type="button">prev</button>
<button type="button">next</button>

Everything runs smoothly on newer browsers. However, I am wondering if there is a way to incorporate previous and next arrows into it. I presume this will require some JavaScript functionality to advance to the subsequent slide, but how can I accurately determine which slide is the current one using this method?

Answer №1

It's incredible how this brought back memories of some old carousel code that I had stashed away back in 2017! It's been a while.

I spent some time figuring it out again. It seems like there is some resize code to ensure that the images fit nicely inside the container. For instance, even though the images are 512px wide, they need to scale down to fit into a 300px wide container.

The code includes a show method that can be linked to buttons. This method requires two parameters: an integer to specify the number of images to move (negative for backward movement) and a boolean value to indicate if the carousel should wrap around when reaching the end.

By manipulating the margin offset, the code displays each "slide", showcasing a CSS transition effect that animates the slides smoothly.

var Slides;
(function(Slides) {
  let slides_container = document.querySelector(".slides-container");
  let slides = document.querySelector(".slides");
  let images = slides.querySelectorAll("img");
  let img_idx = 0;
  for (let ix = 0; ix < images.length; ix++) {
    images[ix].addEventListener("load", function() {
      scaleElementToAncestor(this, slides_container);
    });
  }

  function show(next, wrap) {
    if (!slides.children[img_idx + next]) {
      if (!wrap)
        return;
      img_idx = img_idx + next;
      if (img_idx < 0)
        img_idx = slides.children.length - 1;
      if (img_idx > slides.children.length - 1)
        img_idx = 0;
    } else {
      img_idx = img_idx + next;
    }
    let offset = 0;
    for (let ix = 0; ix < img_idx; ix++) {
      offset += slides.children[ix].clientWidth;
    }
    slides.style.marginLeft = -offset + "px";
  }
  Slides.show = show;

  function scaleElementToAncestor(el, ancestor) {
    const max_width = ancestor.clientWidth;
    const max_height = ancestor.clientHeight;
    const initial_width = el.clientWidth;
    const initial_height = el.clientHeight;
    let width = (max_height * initial_width) / initial_height;
    let height = (max_width * initial_height) / initial_width;
    if (width > max_width)
      width = (height * initial_width) / initial_height;
    if (height > max_height)
      height = (width * initial_height) / initial_width;
    el.style.width = width + "px";
    el.style.height = height + "px";
  }
})(Slides || (Slides = {}));
.slides-container {
  font-size: 0;
  width: 300px;
  height: 150px;
  overflow: hidden;
  white-space: nowrap;
  margin: 0 auto;
}

.slides {
  display: inline-block;
  -webkit-transition: margin-left 0.5s;
  transition: margin-left 0.5s;
}

.slides img {
  vertical-align: top;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<div class="container">
  <div class="row">
    <div class="slides-container">
      <!-- add class -->
      <div class="slides" onclick="Slides.show(1, true)">
        <!-- add class -->
        <!-- add click-handler, or not -->
        <img src="https://dummyimage.com/512x256/000/fff">
        <img src="https://dummyimage.com/512x128/f00/fff">
        <img src="https://dummyimage.com/512x256/0f0/000">
        <img src="https://dummyimage.com/256x256/00f/fff">
        <img src="https://dummyimage.com/512x256/999/000">
      </div>
    </div>
    <div style="margin-top: 1em; text-align: center;">
      <button onclick="Slides.show(-1, false)">Previous</button>
      <!-- add click-handler -->
      <button onclick="Slides.show(1, true)">Next</button>
      <!-- add click-handler -->
    </div>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to have a div show up and stay in place as you scroll down?

How can I make the div "full" sticky after scrolling down 200px, and revert to display none when scrolling back up? Is there a way to accomplish this using JavaScript? In the code snippet below, you will find three divs: header, header2, and header3. The ...

Enhancing user experience with Bootstrap's body padding and customizable scrollbars

Recently, I encountered an issue with the footer color in bootstrap. To fix this problem, I created a div and removed the extra padding from the body element. You can view the code snippet here: jsfiddle.net/wctGM/9/ However, when viewing the mobile ver ...

Managing Flicker Effect by Implementing Theme Switching and Using Local Storage in Next.js with Ant Design

I've been working on a new feature to switch themes (light/dark) dynamically in a Next.js application using Ant Design. Successfully integrating the theme switch with a toggle switch and useState hook, I'm faced with the challenge of storing the ...

Guide to linking an external URL with a lightbox image

I have created a gallery and an admin gallery page. In the admin gallery, there is a delete button that appears over the image. However, when I click on it, instead of showing the message "Are you sure?", it opens a lightbox. I suspect that the code for t ...

Save a canvas image directly to your WordPress media library or server

I'm working on integrating a feature that enables users to save a png created on a canvas element into the WordPress media library, or at least onto the server (which is an initial step before sharing the image on Facebook, as it requires a valid imag ...

Difficulty in adding a simple return to render an array in React for list creation

After establishing a basic object, I noticed that it contained an internal object named "orders" with an array of toppings like "Cheese" and "Bacon". To further explore this structure, I segregated the array and directed it to a function called renderToppi ...

Is there a way to differentiate the color of an active link from an inactive one, so users can easily identify which link they are currently viewing?

How can I customize the color of text for the active page on my website's sidebar? For example, I have two hyperlinks, one for HOME and one for ABOUT. When a user clicks on the HOME link, I want the text color to change to green while the ABOUT link r ...

What is the best way to implement "computeIfAbsent" or "getOrElseUpdate" functionality for a Map in JavaScript?

If we assume that m represents a Map<number, V> for a certain type V k is a number, how can we create an expression that can either retrieve an existing V for the key k, or generate a new v: V, insert it into the map for the key k, and result in v ...

Switching Perspective on Live ExpressJS Path -- Node.JS

I previously set up an express route with a template. Here's the code: app.get('/route', function route(req, res) { db.get('db_ID', function compileAndRender(err, doc) { var stream = mu.compileAndRender('theme-file.e ...

Font appearance varies between Chrome and Firefox browsers

I'm relatively new to the world of web development and have encountered an issue with a menu I created. The buttons in the menu have varying widths depending on the browser being used – Firefox or Chrome. In Firefox, the last button in the menu lin ...

Body overflow appears horizontal in Windows Operating System while it works fine in macOS

After implementing the code below from a helpful CSS Tricks article, my element spanned across the full width of the page, stretching beyond its parent's boundaries: width: 100vw; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin- ...

Configuring Jest unit testing with Quasar-Framework version 0.15

Previously, my Jest tests were functioning properly with Quasar version 0.14. Currently, some simple tests and all snapshot-tests are passing but I am encountering issues with certain tests, resulting in the following errors: console.error node_modules/vu ...

Repeating every 3 to 6 months on later.js commencing from a specified date

Currently, I am working on setting up recurring events every 3 and 6 months using the later.js library which can be found at https://github.com/bunkat/later. The code implementation looks like this: // Assuming my value.scheduled_date is set to 2018-09-0 ...

Transforming JSON in Node.js based on JSON key

I am having trouble transforming the JSON result below into a filtered format. const result = [ { id: 'e7a51e2a-384c-41ea-960c-bcd00c797629', type: 'Interstitial (320x480)', country: 'ABC', enabled: true, ...

Change the dropdown header behavior from hovering over it to clicking on it

This snippet of code is integrated into our header to showcase the cart. Currently, the dropdown appears when hovering over it. Is there a way to adjust this so that the dropdown shows up when onclick? <a href="#header-cart" class="skip-link skip-cart ...

The double click functionality does not seem to be functioning within the Backbone View

I am trying to detect double click event within a Backbone view var HomePage = Backbone.View.extend({ initialize: function(){ this.render(); }, render: function(){ var template = _.template($('#app1').html()); ...

Ways to conceal a button using Javascript

Due to my limited JavaScript experience, I am struggling with understanding the event flow. This was written in haste, and further editing may be needed. I am working on creating a stack of cards (Bootstrap cards) along with a load button. To keep it inde ...

Tips for maintaining consistent formatting of a div element across various sizes

Looking to create a Bootstrap Jumbotron that features a background image, text (h1 and p), and a call-to-action button that scales appropriately for different viewports without sacrificing formatting. Essentially, the goal is for the div to behave like an ...

Tips for emphasizing the currently pressed button element when clicked in Angular 2?

Here is the code snippet I am currently working with: <button *ngFor="let group of groupsList" attr.data-index="{{ group.index }}" (click)="processGroups(group.index)">{{ group.title }}</button> I am trying to figure out if it is possible to ...

experimenting with adding fresh choices to dropdown menu using ajax and jquery

When attempting to load a list of locations through ajax/jQuery, I encounter an issue. After typing a letter into the input field, the first response is displayed but subsequent responses are simply appended to it. I have tried using .html('') an ...