No need for jQuery with this scrolling image gallery

I recently created a horizontal scrolling image gallery with thumbnails underneath. The goal is to click on a thumbnail and have the corresponding image scroll into view.

Here's the HTML setup:

<div class="images_container">
  <img id="image_1" src="/image1.jpg">
  <img id="image_2" src="/image2.jpg">
  <img id="image_3" src="/image3.jpg">
</div>

<div class="images_container thumbnails">
  <a href="#image_1"><img src="/image1.jpg" class="thumbnail"></a>
  <a href="#image_2"><img src="/image2.jpg" class="thumbnail"></a>
  <a href="#image_3"><img src="/image3.jpg" class="thumbnail"></a>
</div>

And here's the CSS used:

.images_container {
  overflow-x: scroll;
  overflow-y: hidden;
  max-height: 50rem;
  white-space: nowrap;
}

.images_container.thumbnails {
  max-height: 10rem;
}

.images_container img {
  vertical-align: top;
  height: 50rem;
}

.images_container.thumbnails img {
  height: 10rem;
}

While this setup functions well, there is an issue with jumping to the correct image when clicking on a thumbnail. Sometimes, if the image is slightly within the visible viewport, it won't jump directly to it. This can be frustrating for users trying to navigate quickly.

To solve this problem, I am looking into using JavaScript to smoothly scroll the entire image into view upon clicking its thumbnail. Since jQuery isn't available for this project, I'll need to rely solely on JavaScript to implement this feature.

Answer №1

If you want to achieve this without altering the CSS, one solution is to add an ID in the HTML and then call a scrollTo function:

<script>

    function scrollTo(image_id){
        var topLeft = document.getElementById(image_id).offsetTop;
        document.getElementById('container').scrollLeft = topLeft;
    }


</script>
<div id="container" class="images_container">
  <img id="image_1" src="/image1.jpg" height="500px" width="500px">
  <img id="image_2" src="/image2.jpg"  height="500px" width="500px">
  <img id="image_3" src="/image3.jpg"  height="500px" width="500px">
</div>

<div class="images_container thumbnails">
  <a href="#image_1"><img src="/image1.jpg" class="thumbnail" onclick="scrollIntoView('image_1')"></a>
  <a href="#image_2"><img src="/image2.jpg" class="thumbnail" onclick="scrollIntoView('image_2')"></a>
  <a href="#image_3"><img src="/image3.jpg" class="thumbnail" onclick="scrollIntoView('image_3')"></a>
</div>

Answer №2

In order to maintain a cleaner DOM structure, I have come up with a solution that only requires the addition of some JavaScript code.

var elements = document.getElementsByClassName("thumbnail");
for (var index = 0; index < elements.length; index++) {
   elements[index].onclick = function(event) {
      event.preventDefault();
      event.stopPropagation();
      var id = this.parentNode.href.substr(this.parentNode.href.lastIndexOf('/') + 2);
      var value = document.getElementById(id).getBoundingClientRect().left;
      document.getElementsByClassName("images_container")[0].scrollLeft += value;
   }
}

Check it out on jsfiddle

Answer №3

My approach to creating a scrolling gallery involves minimal use of JavaScript. By replacing the .active class with the :target pseudo-selector, you can eliminate the need for JavaScript entirely. I prefer using JavaScript in this scenario for easier demonstration through a fiddle.

function removeClass(element, className) {
  var classes = element.className.split(' ');
  var key = classes.findIndex(function(name) {
    return name == className
  });
  classes.splice(key, 1);
  element.className = classes.join(' ');
}

function addClass(element, className) {
  var classes = element.className.split(' ');
  classes.push(className);
  element.className = classes.join(' ');
}

setInterval(function() {
  var current = document.querySelector('.images .image.active');
  var next = current.nextElementSibling;

  if (!next) {
    next = document.querySelector('.images .image:first-child');
  }

  removeClass(current, 'active');
  addClass(next, 'active');
}, 1500);
body {
  margin: 0;
  padding: 0;
  width: 500px;
  height: 500px;
}

.images {
  width: 100%;
  height: 100%;
  position: relative;
  overflow-x: hidden;
}

.image {
  width: 100%;
  height: 100%;
  top: 0px;
  position: absolute;
  left: -100%;
  float: left;
  transition: 1s;
}

.image.active {
  left: 0%;
}

.image.active ~ .image {
  left: 100%;
}

.black {
  background-color: black;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}

.yellow {
  background-color: yellow;
}
<div class='images'>
  <div class='image black active'></div>
  <div class='image red'></div>
  <div class='image blue'></div>
  <div class='image yellow'></div>
</div>

The concept is based on setting the div.images container dimensions and positioning the images inside it accordingly. Initially, all .image elements are set to left: -100% to keep them off-screen to the left. The .image.active class is then set to left: 0 to display the image on screen. Using the ~ selector, we define that sibling elements appearing after the current one (.image.current ~ .image) should be positioned at left: 100%, moving them completely off-screen to the right. With the addition of a transition effect, we achieve a purely CSS-based scrolling gallery where JavaScript simply manages the active image which can be replaced by :target for alternative functionality.

I opted for using div elements instead of img tags to demonstrate with background colors easily, but this approach also works effectively with images by placing an <img> tag within each

<div class='image'></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

Opening the media library in Wordpress through the Angular JS function triggered by an ng-click event

I have been working on a plugin where I need to select an image from the media library. However, despite having implemented the code correctly to call the media library window, I encounter an issue. When I click the button to select an image, nothing happe ...

Deciding whether an array forms a chain of factors

I am curious about the reasons why this code is failing some of the tests provided. It deliberately avoids using any ES6 code. Here is the given prompt: *A factor chain can be defined as an array where each preceding element serves as a factor for the su ...

Data is persisted in the database even when an error occurs

When a user submits their Permanent Account Number (PAN), I check if it already exists in the database. If it does, I receive an error message stating that the PAN number is already registered. However, if I ignore the error and proceed without changing th ...

Retrieve the attribute value from an HTML element in a JSON response using JavaScript

I received a JSON request result containing a blogger post. // API callback posts( { "version": "1.0", "encoding": "UTF-8", "entry": { "title": { "type": "text", "$t": "Vimeo Embed Video Post" ...

When retrieving the card in React, only the first element is affected by the .map function

There seems to be an issue with Arrays.map as it is only working for the first object in the array. Here is the main function: function App(){ return ( <div> <NavBar /> { data.map((prop) =&g ...

CryptoJS consistently produces identical hash values for distinct files

Utilizing CryptoJS to generate a hash value for uploaded files has presented me with a challenge. Despite my efforts, all files I upload seem to produce identical hash values. It appears that the issue lies within my "onFileChange" function, but pinpointin ...

Tips for executing specific javascript on small screens or mobile devices

I am currently in the process of developing a Vue web application that needs to be functional on all devices. I have certain code that should only run on small screens or mobile devices. Right now, I am using an if statement with $(window).width() to achie ...

Values in Vuex do not get updated by getters

I'm having trouble understanding the functionality of getters in Vuex. The issue arises when I log out the token and find that the state and localStorage are empty, but the getters still contain the old token value. In the created lifecycle hook, I ha ...

Extracting the console.log method from the console

Given that the console object has not been overridden and refers to a native object, the console.log method (and possibly others) is obtained from the console object with the following code: var log = obj.log = console.log; // instead of console.log.bind( ...

Tips on altering the location path when redirecting to a different page using window.location?

Is it a silly question to ask? I tried looking for the answer on Google but couldn't find it. I'm currently working on a website where users can upload photos or videos, using HTML, CSS, and JavaScript. On the homepage, when a user clicks on a ...

importing files from the local directory in Django

My issue involves a folder located in c:\images, where images are being updated by another application. I am attempting to have a Django application access and display these images on the admin site. The Django application is currently located in c:&b ...

Unable to call an object that may be 'undefined': Utilizing a function with a return object that includes asynchronous functions as properties

I have a function exported in my adapter.ts file: import type { Adapter } from "@lib/core/adapters"; export default function MyAdapter (): Adapter { return { async createUser (user: User) { ... }, async findUserByEmail (email ...

Ways to bypass HostListener in Angular 2

In the process of developing a page with animations triggered on scroll, I encountered the challenge of ensuring that the animations only occur when the corresponding element is visible on the viewport. Utilizing Angular2 for this task led me to investigat ...

Fetching Data Using Asynchronous API Calls

My goal is to retrieve all results consistently from the API, but I am encountering varying outcomes. The for loop seems to be skipping some requests and returning a random number of records. Can anyone provide assistance? I have experimented with using t ...

Seeking advice on removing the initial blank space from a dropdown value in Angular.js

I have a deeply thought-out logic that I would like to illustrate with an example. However, in order to present it effectively, I am looking for suggestions on how to simplify the process without relying too heavily on the controller. <select class="fo ...

DANGEROUS EVALUATION: Tips for Safe Replacement

Looking for a safer alternative to the code below which utilizes eval. The script creates pop-up windows based on different classes. /* exported popup_default , popup_help , popup_sitemap , popup_footerlinks */ var matchClass = ['popup_default' ...

"Despite the null date in Node.js, the validation for expiration dates less than Date.now() is still being enforced

I am currently working on implementing validation for evaluating the finish status. However, my validation is encountering a problem with the "null" value of expiresAt. It should indicate that the evaluation has been successfully completed. The issue lie ...

sinon: Techniques for stubbing an entire class as opposed to singular methods

I am faced with a situation where I have a class that instantiates another class in my test. My goal is to stub out the entire second class, ensuring that its constructor is never invoked. Consider the following scenario: Test.js class Test { construct ...

Include personalized headers to the 'request'

I have configured my express server to proxy my API using the following setup: // Proxy api calls app.use('/api', function (req, res) { let url = config.API_HOST + req.url req.pipe(request(url)).pipe(res) }) In this instance, confi ...

What is an alternative way to rewrite this regular expression without relying on the deprecated API?

My JavaScript code uses a regular expression, myRegexp, to match numbers in a string: var myRegexp = new RegExp('[0-9]+'); The code then extracts numbers from the string and returns an array: var string = '123:456'; var nums = []; wh ...