How do you make an image clickable so that a different image of the same size replaces it with each click? (on a website page)

I have multiple images on each page. I want to be able to click on an image and have a different image replace it (a totally different image, not an image already featured on the page). I would like to be able to click the image multiple times and have different hand-selected images replace the following image after each click.

For example, there is an image of a dog. I want to be able to click the image and have it become an image of a cat. Then I want to click it again and have it become an image of a mouse. The image that would show up would depend on how many times the image has been clicked. I want all the images to be the same size.

How do I do this?

I’ve moved your question to the JS forum, as that’s normally what you’d use to do this. (It might be possible with some fancy CSS, but JS is the more reliable way to do it.)

There are several ways to do that, depending on your particular needs.

  1. Do you want all differently sized images to be squashed or stretched to be the same size?
  2. Or, do you want to have images of the same size stored in the same array, so that only those from the appropriate array are chosen?
  3. Or, do you want to search through all of the images for other ones that have the same width and height as the one that was clicked?

All three are different solutions that require a different approach for each one. Which way do you want all the images to be the same size?

Hi there wavery229,

and a warm welcome to these forums. :sunglasses:

Your problem seemed appropriate for testing a CSS Solution,
just to tease @ralphm, who moved it here from another place. :mask:

<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">

<title>untitled document</title>

<!--<link rel="stylesheet" href="screen.css" media="screen">-->

<style media="screen">
body {
    background-color: #f0f0f0;
    font: 1em/1.62em verdana, arial, helvetica, sans-serif;
 }

#images {
    position:relative;
 }

#images input {
    position:absolute;
    left: -999em;
 }

#images label {
    position: absolute;
    width: 50%;
    padding-top: 29.5%;
    top: 0;
    left: 50%;
    transform: translate(-50%, 0);
    border: 0.06em solid #666;
    box-shadow: 0.5em 0.5em 0.5em rgba(0, 0, 0, 0.1);
    background-image: url(http://coothead.co.uk/images/four-images.jpg);
    background-size: 200% auto;
    cursor: pointer;
 }

#lab0 {z-index: 4;}
#lab1 {z-index: 3;}
#lab2 {z-index: 2;}
#lab3 {z-index: 1;}

#r0:checked~ #lab0 {
    z-index: 0;
 }
#r0:checked~ #lab1{
    background-position: -100% 0;
 }

#r1:checked~ #lab1{
    z-index: 0;
 }
#r1:checked~ #lab2{
    z-index: 5;
    background-position: 0 -100%; 
 }

#r2:checked~ #lab2{
    z-index: 0
 }
#r2:checked~ #lab3{
    z-index: 5;
    background-position: -100% -100%; 
 }

#r3:checked~ #lab3{
    z-index: 0
 }
</style>

</head>
<body>
<div id="images"> 
 <input id="r0" name="r" type="radio">
 <input id="r1" name="r" type="radio">
 <input id="r2" name="r" type="radio">
 <input id="r3" name="r" type="radio">

 <label id="lab0" for="r0"></label>
 <label id="lab1" for="r1"></label>
 <label id="lab2" for="r2"></label>
 <label id="lab3" for="r3"></label>
</div>

</body>
</html>

coothead

2 Likes

I need all the images to be the same size. Right now I have saved all the images I’ll be using. They need to be cropped to the standard image size for the site, which I am planning on doing once I figure out how to do this.

I’m going to have rows of images on each page. The images show different dog breeds. I want the user to be able to click on the image for a breed and have a different dog from that breed replace the original image. I want the user to be able to click the image again and a different image of the dog breed replaces it. All images must be the same size and must be in an exact order.

I have saved about ten example pictures of dogs from each breed already. I want the user to be able to click on the initial cover image for each dog breed on the page and have several more example images of the breed show with each click. The size of the image doesn’t change, just the image itself in order to show different example images of each dog breed.

If you could help me with this, it would be greatly appreciated. Thanks

That sounds relatively easy.

Have an array of images for each breed, and shuffle the array.
When an image is clicked, show the image that’s at the top of the list then move it to the bottom.

Here’s some example code:

<p>Click dog to show a different dog of the same breed.</p>
<div class="breeds">
  <div id="greatdane" class="breed"></div>
  <div id="schnauzer" class="breed"></div>
</div>

And the CSS to centre vertically and horizontally:

.breed {
  width: 200px;
  height: 150px;
  border: 1px solid black;
  position: relative;
}
img {
  max-width: 200px;
  max-height: 150px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

We want to get the dogs and shuffle them, which should look something like this:

var breeds = {
  greatdane: shuffle(getBreeds("greatdane")),
  schnauzer: shuffle(getBreeds("schnauzer"))
};

The shuffling can be easily done using a Fisher-Yates shuffle function.

The dogs can be stored in arrays as objects, so that we can keep track of several related pieces of information for each image:

function getBreeds(breedName) {
  if (breedName === "greatdane") {
    return [
      {alt: "great dane 1", src: "http://www.dogbreedinfo.com/images12/GreatDanealmost200%20lbsdogAlemao.JPG"},
      ...
      {alt: "great dane 10", src: "http://www.dogbreedinfo.com/images27/GreatDanePurebredDogJunior8Months2.JPG"}
    ];
  }
  if (breedName === "schnauzer") {
    return [
      {alt: "schnauzer 1", src: "http://cdn2-www.dogtime.com/assets/uploads/2011/01/file_22950_standard-schnauzer.jpg"},
      ...
      {alt: "schnauzer 10", src: "http://www.dogbreedslist.info/uploads/allimg/dog-pictures/Miniature-Schnauzer-3.jpg"}
    ];
  }
}

When it’s time to show a new dog, we’ll get one from the top of the list, show it, then push it back to the bottom of the list:

function showNewDog(container, breed) {
  var dog = breeds[breed].shift();
  container.innerHTML = "<img alt='" + dog.alt + "' src='" + dog.src + "'>";
  breeds[breed].push(dog);
}

When one of the breeds is clicked, we’ll show a new dog:

function initContainer(breedContainer) {
  var breed = breedContainer.id;
  breedContainer.addEventListener("click", function (evt) {
    var container = this;
    showNewDog(container, breed);
  });
  ...
}

And we’ll show a dog when the code first runs:

function initContainer(breedContainer) {
  var breed = breedContainer.id;
  ...
  showNewDog(breedContainer, breed);
}

And lastly, we’ll get run that initContainer() function on each breed section of the page:

var breedContainers = document.querySelectorAll(".breed");
Array.prototype.forEach.call(breedContainers, initContainer);

And a demo that I’ve put together showing how this all works together in practice.

3 Likes

The easiest way would be to have all images in a container right away, and just show/hide them onclick by cycling through them using .nextElementSibling and .firstElementChild, like

const container = document.querySelector('.img-container')

container.addEventListener('click', function cycleImg (evt) {
  const currentImg = evt.target;
  const nextImg = currentImg.nextElementSibling || this.firstElementChild
  
  currentImg.style.display = 'none'
  nextImg.style.display = 'block'
})

fiddle

A somewhat more sophisticated way would incorporate lazy loading, so that images only get appended to the DOM when they’re actually needed (for the first time), like

const container = document.querySelector('.img-container')
const imgs = [
  {src: 'http://lorempixel.com/400/400/cats/2', alt: 'Cat 2'},
  {src: 'http://lorempixel.com/400/400/cats/3', alt: 'Cat 3'},
  {src: 'http://lorempixel.com/400/400/cats/4', alt: 'Cat 4'}
]

container.addEventListener('click', function cycleImg (evt) {
  const currentImg = evt.target;
  const newImg = imgs.pop()
  var nextImg
  
  if (newImg) {

    // Create new img element from the array
    // and append it to the container
    nextImg = document.createElement('img')
    nextImg.src = newImg.src
    nextImg.alt = newImg.alt
    this.appendChild(nextImg)
  } else {

    // If all imgs in the array have been appended,
    // just proceed as in the first example
    nextImg = currentImg.nextElementSibling || this.firstElementChild
  }
  
  currentImg.style.display = 'none'
  nextImg.style.display = 'block'
})

fiddle

Ninja’d by @Paul_Wilkins :-)

2 Likes

I’m a complete novice to web design. What are containers and how do put a set of images in a container?

I’m also using the Genesis framework/ Brunch Pro theme if that is relevant

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.