Bebbs
Bebbs

Reputation: 289

Scrolling image gallery without jQuery

I have a scrolling image gallery as follows. The CSS lays out the images in a row that scrolls horizontally. Underneath, I have a row of the same images, but as thumbnails. I want to be able to click on a thumbnail, and scroll the correct image into view.

HTML:

<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>

CSS:

.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;
}

This works up to a point, but jumping to the id of the image is problematic. If the larger image is even a few pixels into the visible viewport, it can't 'jump' to it, as it seems to be technically on the screen.

Is there a way I can use Javascript to 'scroll' the whole image into view when I click on it's corresponding thumbnail? I don't have access to jQuery on this project, but am happy to use JavaScript to make this work.

Upvotes: 2

Views: 2415

Answers (3)

Gareth Parker
Gareth Parker

Reputation: 5062

Here's my attempt at a no (well, minimal) JS solution to a scrolling gallery. You could, in fact, remove the Javascript all together if you replaced the .active class with the :target pseudo-selector, allowing you to click your thumbnails to do the scrolling. It's just easier for me to do it this way 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>

Essentially the way it works is by making the div.images container a certain height and width, and therefore all images inside it can be positioned as you want. We initially set all .image to left: -100%, so that they're completely off screen to the left. We then set .image.active as left: 0 so that it's on screen. We then use the ~ selector to say that all siblings that come after the current (.image.current ~ .image) should be left: 100%, so completely to the right. Add in a transition, and you have a completely CSS scrolling gallery. The JS only acts as a way to change what the current active image is, and you can replace that with :target if you want.

I used div's, instead of img tags because it's easier to provide a POC with div's and background colors, but it's worked well with images in the past. Just put an <img> tag inside those <div class='image'></div> tags

Upvotes: 0

JNF
JNF

Reputation: 3730

To keep DOM cleaner I got this solution which requires only adding js

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

See on jsfiddle

Upvotes: 0

Benjamin Poignant
Benjamin Poignant

Reputation: 1064

You can try this , no change in CSS, i add an id in html and call to 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>

Upvotes: 1

Related Questions