javascripthtmlcssmodal-dialogcrop

Crop modal images only when small + separate thumbnail image


EDIT: IMAGE OF WHAT I'M AFTER FOR CLARITY: [here] (https://thepasteldyke.neocities.org/misc/attempts.png)

I've been starting off with w3s's modal images, which led me to this site because it has a lot of problems as it turns out. I've managed to solve all my other problems thanks to other posts on here, but one remains. I have images of different sizes, so I want the small pictures to be cropped to the same size, and when you click on it the modal image shows the full thing. Ideally if there is a way to choose which section to show for individual images as well instead of just the starting point being the top left. I know there is a way to do this in the html style of the image but that messed up the big picture as well.

Originally I wanted to have a separate image as the thumbnail, so if anyone knows how that would work with modal images, let me know, though I need those two separate, as I was planning on using custom thumbnails only for some of what I'm doing. The most important part is getting them the same size while also displaying the text though.

I used this question to help with multiple images, and this one for help with descriptions.

As for the crop I haven't found anything that works entirely the way I want it to. The closest I've found is using a set size and overflow: hidden, but that also hides the description, and I no longer get rounded corners in the bottom. How do I fix this?

This is the entirety of my code: (codepen if you prefer)

var modal = document.getElementById('myModal');
// to all images -- note I'm using a class!
var images = document.getElementsByClassName('myImg');
// the image in the modal
var modalImg = document.getElementById("img01");
// and the caption in the modal
var captionText = document.getElementsByClassName("text");
// Go through all of the images with our custom class
for (var i = 0; i < images.length; i++) {
  var img = images[i];
  // and attach our click listener for this image.
  img.onclick = function(evt) {
    modal.style.display = "block";
    // modalImg.src = this.src;
    modalImg.innerHTML = this.innerHTML;
    captionText.innerHTML = this.alt;
  }
}
var span = document.getElementsByClassName("close")[0];
span.onclick = function() {
  modal.style.display = "none";
}
body {font-family: Arial, Helvetica, sans-serif;}

*,*:before, *:after{box-sizing: border-box;}
body{
  margin: 0;
  padding: 0;
  font-family: Arial;
}

.myImg{
  cursor: pointer;
  transition: 0.3s;
  display: inline-block;
  vertical-align: top;
  width: 300px;
  min-height: 200px;
  padding: 5px;
}

.myImg:hover {
  opacity: 0.7;
}
.myImg img{
  max-width: 100%;
  border-radius: 5px;
  
}
.modal {
  display: none;
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  padding-top: 50px;
  /* Location of the box */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: hidden;
  overflow-y: auto;
  /* Enable scroll if needed */
  background-color: rgb(0, 0, 0);
  /* Fallback color */
  background-color: rgba(0, 0, 0, 0.9);
  /* Black w/ opacity */
}

.modal-content {
  margin: 0 auto 20px auto;
  display: block;
  width: 80%;
  max-width: 700px;
  height: 80%;
}
.modal-content img{
  width: 100%;
  display: block;
}
.modal-content .text{
  font-size: 16px;
  color: #f1f1f1;
  padding: 10px;
}
.modal-content{
  animation-name: zoom;
  animation-duration: 0.6s;
}

@keyframes zoom {
  from {
    transform: scale(0)
  }
  to {
    transform: scale(1)
  }
}
.close {
  position: absolute;
  top: 15px;
  right: 35px;
  color: #f1f1f1;
  font-size: 40px;
  font-weight: bold;
  transition: 0.3s;
}
.close:hover,
.close:focus {
  color: #bbb;
  text-decoration: none;
  cursor: pointer;
}
@media only screen and (max-width: 700px) {
  .modal-content {
    width: 100%;
  }
}
<div class="myImg">
  <img src="https://thepasteldyke.neocities.org/art/artfight/2023/3artho.png" alt="one">
  <div class="text">One</div>
</div>
<div class="myImg">
  <img src="https://thepasteldyke.neocities.org/art/artfight/2023/gloomy_dollette_1.png" alt="two">
  <div class="text">Two</div>
</div>
<div class="myImg">
  <img src="https://thepasteldyke.neocities.org/art/artfight/2023/cherryxroll2.gif" alt="three">
  <div class="text">Three</div>
</div>

<!-- Modal Elements -->
<div id="myModal" class="modal">
  <span class="close">&times;</span>
  <div class="modal-content" id="img01"></div>
</div>

So essentially I need help turning this into two codes that are mostly the same, with slight differences being:

1, using this code, I want to crop the regular image so they're all the same size, but when you click it it's the full image. I also need the description to show up when the image is small. 2, using this code, I want to have a custom thumbnail that opens the full image up when you click it. Also with the description showing.

How do I do this? If you have additional code for me to put in somewhere, please specify where I would put it as I'm quite the beginner still.

I tried to use overflow but it hid the text as well as removed the rounded bottom corners. I've tried using style in the html of the image but it messed with the big image as well.

I found a similar thumbnail question from 7 years ago but it didn't work properly.


Solution

  • Here's a slight rewrite with smaller thumbnails and better JS to select your elements. Hopefully this will make sense and be easier to work with

    //Modal elements
    var modal = document.querySelector('#myModal');
    var closeModal = modal.querySelector(".close");
    var captionText = modal.querySelector(".text");
    var modalImg = modal.querySelector("img");
    
    // to all images -- note I'm using a class!
    var thumbnails = document.querySelectorAll('.thumb');
    
    // Go through all of the images with our custom class
    for (var i = 0; i < thumbnails.length; i++) {
      thumbnails[i].onclick = function(evt) {
        var thisThumbImg = this.querySelector('img');
        var thisThumbCaption = this.querySelector('.text');
        modal.style.display = "block";
        modalImg.src = thisThumbImg.src;
        captionText.innerHTML = thisThumbImg.alt;
      }
    }
    
    closeModal.onclick = function() {
      modal.style.display = "none";
    }
    body {font-family: Arial, Helvetica, sans-serif;}
    
    *,*:before, *:after{box-sizing: border-box;}
    body{
      margin: 0;
      padding: 0;
      font-family: Arial;
    }
    
    .thumb{
      cursor: pointer;
      transition: 0.3s;
      display: inline-block;
      padding: 5px;
      
      position: relative; /*Needed to manually position each image*/
    }
    
    .thumb:hover {
      opacity: 0.7;
    }
    
    .thumb-crop {
      overflow: hidden;
      height: 100px;
      width: 100px;
      border-radius: 5px;
    }
    
    .thumb img{
      width: 100%;
    }
    .modal {
      display: none;
      /* Hidden by default */
      position: fixed;
      /* Stay in place */
      z-index: 1;
      /* Sit on top */
      padding-top: 50px;
      /* Location of the box */
      left: 0;
      top: 0;
      width: 100%;
      /* Full width */
      height: 100%;
      /* Full height */
      overflow: hidden;
      overflow-y: auto;
      /* Enable scroll if needed */
      background-color: rgb(0, 0, 0);
      /* Fallback color */
      background-color: rgba(0, 0, 0, 0.9);
      /* Black w/ opacity */
    }
    
    .modal-content {
      margin: 0 auto 20px auto;
      display: block;
      width: 80%;
      max-width: 700px;
      height: 80%;
    }
    .modal-content img{
      width: 100%;
      display: block;
    }
    .modal-content .text{
      font-size: 16px;
      color: #f1f1f1;
      padding: 10px;
    }
    .modal-content{
      animation-name: zoom;
      animation-duration: 0.6s;
    }
    
    @keyframes zoom {
      from {
        transform: scale(0)
      }
      to {
        transform: scale(1)
      }
    }
    .close {
      position: absolute;
      top: 15px;
      right: 35px;
      color: #f1f1f1;
      font-size: 40px;
      font-weight: bold;
      transition: 0.3s;
    }
    .close:hover,
    .close:focus {
      color: #bbb;
      text-decoration: none;
      cursor: pointer;
    }
    @media only screen and (max-width: 700px) {
      .modal-content {
        width: 100%;
      }
    }
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://thepasteldyke.neocities.org/art/artfight/2023/3artho.png" alt="one" style="top: -10px">
      </div>
      <div class="text">One</div>
    </div>
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://thepasteldyke.neocities.org/art/artfight/2023/gloomy_dollette_1.png" alt="two"style="top: -20px">
      </div>
      <div class="text">Two</div>
    </div>
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://thepasteldyke.neocities.org/art/artfight/2023/cherryxroll2.gif" alt="three"style="top: -30px">
      </div>
      <div class="text">Three</div>
    </div>
    
    <!-- Modal Elements -->
    <div id="myModal" class="modal">
      <span class="close">&times;</span>
      <div class="modal-content" id="img01">
        <img>
        <div class="text"></div>
      </div>
    </div>

    If you want to use different images for thumbnails, you could save URL to the the full-sized image as a data attribute on the thumbnail image, like below. I just used some random images for thumbnails, but you get the idea.

    //Modal elements
    var modal = document.querySelector('#myModal');
    var closeModal = modal.querySelector(".close");
    var captionText = modal.querySelector(".text");
    var modalImg = modal.querySelector("img");
    
    // to all images -- note I'm using a class!
    var thumbnails = document.querySelectorAll('.thumb');
    
    // Go through all of the images with our custom class
    for (var i = 0; i < thumbnails.length; i++) {
      thumbnails[i].onclick = function(evt) {
        var thisThumbImg = this.querySelector('img');
        var thisThumbCaption = this.querySelector('.text');
        modal.style.display = "block";
        modalImg.src = thisThumbImg.getAttribute('data-full-img');
        captionText.innerHTML = thisThumbImg.alt;
      }
    }
    
    closeModal.onclick = function() {
      modal.style.display = "none";
    }
    body {font-family: Arial, Helvetica, sans-serif;}
    
    *,*:before, *:after{box-sizing: border-box;}
    body{
      margin: 0;
      padding: 0;
      font-family: Arial;
    }
    
    .thumb{
      cursor: pointer;
      transition: 0.3s;
      display: inline-block;
      vertical-align: top;
      padding: 5px;
    }
    
    .thumb-crop {
      overflow: hidden;
      height: 100px;
      width: 100px;
      border-radius: 5px;
    }
    
    .thumb:hover {
      opacity: 0.7;
    }
    .thumb img{
      max-width: 100%;
      border-radius: 5px;
      
    }
    .modal {
      display: none;
      /* Hidden by default */
      position: fixed;
      /* Stay in place */
      z-index: 1;
      /* Sit on top */
      padding-top: 50px;
      /* Location of the box */
      left: 0;
      top: 0;
      width: 100%;
      /* Full width */
      height: 100%;
      /* Full height */
      overflow: hidden;
      overflow-y: auto;
      /* Enable scroll if needed */
      background-color: rgb(0, 0, 0);
      /* Fallback color */
      background-color: rgba(0, 0, 0, 0.9);
      /* Black w/ opacity */
    }
    
    .modal-content {
      margin: 0 auto 20px auto;
      display: block;
      width: 80%;
      max-width: 700px;
      height: 80%;
    }
    .modal-content img{
      width: 100%;
      display: block;
    }
    .modal-content .text{
      font-size: 16px;
      color: #f1f1f1;
      padding: 10px;
    }
    .modal-content{
      animation-name: zoom;
      animation-duration: 0.6s;
    }
    
    @keyframes zoom {
      from {
        transform: scale(0)
      }
      to {
        transform: scale(1)
      }
    }
    .close {
      position: absolute;
      top: 15px;
      right: 35px;
      color: #f1f1f1;
      font-size: 40px;
      font-weight: bold;
      transition: 0.3s;
    }
    .close:hover,
    .close:focus {
      color: #bbb;
      text-decoration: none;
      cursor: pointer;
    }
    @media only screen and (max-width: 700px) {
      .modal-content {
        width: 100%;
      }
    }
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://picsum.photos/id/1/100/150/" data-full-img="https://thepasteldyke.neocities.org/art/artfight/2023/3artho.png" alt="one">
      </div>
      <div class="text">One</div>
    </div>
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://picsum.photos/id/2/100/150" data-full-img="https://thepasteldyke.neocities.org/art/artfight/2023/gloomy_dollette_1.png" alt="two">
      </div>
      <div class="text">Two</div>
    </div>
    <div class="thumb">
      <div class="thumb-crop">
        <img src="https://picsum.photos/id/3/100/150/" data-full-img="https://thepasteldyke.neocities.org/art/artfight/2023/cherryxroll2.gif" alt="three">
      </div>
      <div class="text">Three</div>
    </div>
    
    <!-- Modal Elements -->
    <div id="myModal" class="modal">
      <span class="close">&times;</span>
      <div class="modal-content" id="img01">
        <img>
        <div class="text"></div>
      </div>
    </div>