0

I have an image gallery with a main image and some thumbnail images on the right side of the main image. I want to set the height of the thumbnails div the same as the main image. The problem is, this image is always different so it doesn't have a static height. Tried to use javascript to get it's height then give it to the thumbnails div, but it doesn't do anything.

<div class="gallery">
<a href="images/1.jpg">
<div class="main-image">
<img class="card-img-top" id="modal-img-top" src="images/1.jpg" alt="Fő kép">
</div>
<div class="image-container" id="image-thumbnails">
<img src="images/1.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor2.jpg" alt="Egy kép a hirdetésről">
<img src="images/2.jpg" alt="Egy kép a hirdetésről">
<img src="images/1.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor2.jpg" alt="Egy kép a hirdetésről">
<img src="images/2.jpg" alt="Egy kép a hirdetésről">
</div>
</a>

<a href="images/motor.jpg"></a>
<a href="images/motor2.jpg"></a>
<a href="images/2.jpg"></a>
<a href="images/1.jpg"></a>
</div>
<script type="text/javascript">
   const img = new Image();
   img.onload = function() {
       alert(this.width + 'x' + this.height);
       document.getElementById("image-thumbnails").style.height = this.height;
       }
img.src = document.getElementById("modal-img-top").getElementsByTagName('img');
</script>
Mower
  • 177
  • 2
  • 10
  • You also need to put the unit, like `this.height + 'px'`. `img.src = document.getElementById("modal-img-top").getElementsByTagName('img')` What is this line supposed to do? – Lain Oct 07 '20 at 10:53
  • I'd like to select the main image with this line. – Mower Oct 07 '20 at 10:54
  • Currently you try to assign a *HTMLCollection* (=`getElementsByTagName()`) to a string property (=`src`). Which means your `img.src` will end up as *base + [object Object]* and no valid image. – Lain Oct 07 '20 at 10:58
  • Would a grid layout help? See [Equal height rows](https://stackoverflow.com/questions/44488357/equal-height-rows-in-css-grid-layout) – ATD Oct 07 '20 at 11:21
  • I just put ```document.getElementById("image-thumbnails").style.height = this.height + 'px';``` but still nothing happens. – Mower Oct 07 '20 at 11:29

2 Answers2

1

Edit: Ok let's have another try.

The main issue is to size your main image which should stay in its ratio and be wrapped in its parent. After trial and error there seems to be no easy method to archive this. I also tried object-fit property, but event this is not working as you want to. So here are my two solutions.

Solution 1: The most easy way is to use a div with the background-image property instead of an img. As you see in the solution below, the main-image is a div now. You could also use the element .image-wrapper as the background image. But I wrapped a main-image into it to get some padding between these two elements.

Solution 2: Instead of using the background-image property you can still use a img, but you'll need some javascript and calculations. The calculation is done by the function calculateMainImage. It is not too complex, but it needs some lines. The strategy is this:

  1. Get the dimensions of the main image and its parent element
  2. Assume that the image fits into its parent (in css: width: 100%). So calculate the image dimensions for this assumption.
  3. If the calculated height is greater than the height of the parent, the image won't fit into the parent. So now set the image's height to the height of its parent and recalculate the width.

This function is also called when the document is ready (initialization) and when the window resizes (window.onresize).

enter image description here

let mainImage = document.querySelector('.main-image');
let thumbnails = document.querySelectorAll('.thumbnail');
thumbnails.forEach(thumbnail => {
  thumbnail.addEventListener('click', () => {
    let backgroundImage = 'url(' + thumbnail.src +')';
    mainImage.style.backgroundImage = backgroundImage;
  });
});
.gallery{
  position: relative;
  width: 100%;
  height: 400px;
  background: #dedede;
  display: grid;
  grid-template-columns: 70% 30%;
}

.image-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #aaa;
  padding: 12px;
  box-sizing: border-box;
}

.main-image{
  position: relative;
  width: 100%;
  height: 100%;
  background-image: url("https://via.placeholder.com/350x150");
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.thumbnail-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  padding: 12px;
  box-sizing: border-box;
}

.thumbnail-wrapper > .thumbnail:not(:last-child){
  margin-bottom: 12px;
}

.thumbnail{
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  margin-left: auto;
  margin-right: auto;
  cursor: pointer;
}
<section class="gallery">
  <!-- Main image -->
  <div class="image-wrapper">
    <div class="main-image">
    </div>
  </div>
  <!-- Thumbnails -->
  <div class="thumbnail-wrapper">
    <img class="thumbnail" src="https://via.placeholder.com/350x150">
    <img class="thumbnail" src="https://via.placeholder.com/200x100">
     <img class="thumbnail" src="https://via.placeholder.com/140x100">
     <img class="thumbnail" src="https://via.placeholder.com/350x65">
     <img class="thumbnail" src="https://via.placeholder.com/350x150">
     <img class="thumbnail" src="https://via.placeholder.com/200x100">
     <img class="thumbnail" src="https://via.placeholder.com/140x100">
  </div>
</section>

let gallery = document.querySelector('.gallery');
let container = document.querySelector('.container');
let mainImage = document.querySelector('.main-image');
let thumbnails = document.querySelectorAll('.thumbnail');

(function(){
  // Document ready
  calculateMainImage();
  // When window resizes
  window.addEventListener('resize', () => {
      calculateMainImage();
  });
})();


thumbnails.forEach(thumbnail => {
  thumbnail.addEventListener('click', () => {
    mainImage.src = thumbnail.src;
    // Fit image to container
    calculateMainImage();
  });
});

function calculateMainImage(){
  // Reset current dimensions
  mainImage.style.width = 'initial';
  mainImage.style.height = 'initial';
  // Container dimensions
  let containerWidth = container.getBoundingClientRect().width;
  let containerHeight = container.getBoundingClientRect().height;
  // Image dimensions 
  let width = mainImage.getBoundingClientRect().width;
  let height = mainImage.getBoundingClientRect().height;
  let ratio = width / height;
  // Calculate image dimensions when width: 100%
  let maxWidth = containerWidth;
  let maxHeight = maxWidth / ratio;
  // Check if image fits in parent
  if(maxHeight > containerHeight){
    // Scale image down. Recalculate image's width
    let newHeight = containerHeight;
    let newWidth = newHeight * ratio;
    setMainImageSize(newWidth, newHeight);
  }else{
    setMainImageSize(maxWidth, maxHeight);
  }
}

function setMainImageSize(width, height){
  mainImage.style.width = width + 'px';
  mainImage.style.height = height + 'px';
}
.gallery{
  position: relative;
  width: 100%;
  height: 400px;
  background: #dedede;
  display: grid;
  grid-template-columns: 70% 30%;
}

.image-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #aaa;
  padding: 12px;
  box-sizing: border-box;
}

.container{
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.main-image{
  position: relative;
  flex-grow: 0;
  flex-shrink: 0;
}

.thumbnail-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  padding: 12px;
  box-sizing: border-box;
}

.thumbnail-wrapper > .thumbnail:not(:last-child){
  margin-bottom: 12px;
}

.thumbnail{
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  margin-left: auto;
  margin-right: auto;
  cursor: pointer;
}
<section class="gallery">
  <!-- Main image -->
  <div class="image-wrapper">
    <div class="container">
      <img class="main-image" src="https://via.placeholder.com/200x100">
    </div>
  </div>
  <!-- Thumbnails -->
  <div class="thumbnail-wrapper">
    <img class="thumbnail" src="https://via.placeholder.com/350x150">
    <img class="thumbnail" src="https://via.placeholder.com/200x100">
     <img class="thumbnail" src="https://via.placeholder.com/140x100">
     <img class="thumbnail" src="https://via.placeholder.com/350x65">
     <img class="thumbnail" src="https://via.placeholder.com/350x150">
  </div>
</section>

Update

When you have several gallerys on your page and use use solution #1, then you need to add this JS snipped.

let gallerys = document.querySelectorAll('.gallery');
gallerys.forEach(gallery => {
    updateGalleryPictures(gallery)
});

function updateGalleryPictures(gallery) {
    // Get gallery's main image
    let mainImage = gallery.querySelector('.main-image');
    if (mainImage === null) return;
    // Get gallery's thumbnail images
    let thumbnails = gallery.querySelectorAll('.thumbnail');
    // Change the background-image property on click
    thumbnails.forEach(thumbnail => {
        thumbnail.addEventListener('click', () => {
            let backgroundImage = 'url(' + thumbnail.src + ')';
            mainImage.style.backgroundImage = backgroundImage;
        });
    });
    // Initialize background-image property using the 1st thumbnail image
    let firstThumbnail = thumbnails[0];
    if (firstThumbnail === null || firstThumbnail === undefined) return;
    let initialBackgroundImage = 'url(' + firstThumbnail.src + ')';
    mainImage.style.backgroundImage = initialBackgroundImage;
}

Update 2: Usage of baguetteBox

Step 1: Add the property overflow: hidden; to the class .image-wrapper and create a new class

.baguettebox-image{
    opacity: 0 !important;
}

Step 2: Change the structure of the main-image setup.

<div class="image-wrapper">
    <div class="main-image"> <!-- THis is the baguette box -->
        <a class="baguettebox-link" href="">
        <img class="baguettebox-image" src=""></a>
        </a>
    </div>
</div>

Step 3: Change the JS snipped of the 1st update to: Note that the baguette boxes are also initialized in this script. According to the documentation querySelectorAll is used, so all boxes (.main-image) should be initialized.

let gallerys = document.querySelectorAll('.gallery');
gallerys.forEach(gallery => {
    updateGalleryPictures(gallery);
});
// Initialize all baguette boxes
baguetteBox.run('.main-image');

function updateGalleryPictures(gallery) {
    // Get gallery's thumbnail images
    let thumbnails = gallery.querySelectorAll('.thumbnail');
    // Change the background-image property on click
    thumbnails.forEach(thumbnail => {
        thumbnail.addEventListener('click', () => {
            updateMainImage(gallery, thumbnail.src)
        });
    });
    // Initialize background-image property using the 1st thumbnail image
    let firstThumbnail = thumbnails[0];
    if (firstThumbnail === null || firstThumbnail === undefined) return;
    updateMainImage(gallery, firstThumbnail.src)
    // Initialize baguette
}

function updateMainImage(gallery, src) {
    // Get main image and check if it exists
    let mainImage = gallery.querySelector('.main-image');
    if (mainImage === null) return;
    mainImage.style.backgroundImage = 'url(' + src + ')';
    // Get baguette elements
    let boxLink = gallery.querySelector('.baguettebox-link');
    let boxImage = gallery.querySelector('.baguettebox-image');
    // Update baguette elements href and src
    if (boxLink !== null && boxLink !== undefined) boxLink.href = src;
    if (boxImage !== null && boxImage !== undefined) boxImage.src = src;
}
michaelT
  • 1,533
  • 12
  • 41
  • Just tried to use this, but don't really understand how. Could you place my code into it or show me how to do it? – Mower Oct 07 '20 at 12:57
  • For this I need your css. Or you could post a codepen example, which I can edit. – michaelT Oct 07 '20 at 12:58
  • sure, in a min. – Mower Oct 07 '20 at 13:01
  • Can't edit the comment, so here it is: https://codepen.io/MowerQQ/pen/BazaRoR – Mower Oct 07 '20 at 13:06
  • Edited my answer. Please check out. – michaelT Oct 07 '20 at 13:41
  • Something is still not working. The thumbnails are really distorted and much higher than the main image. Is there any easier way to make a good looking image grid? For example like this https://www.hasznaltauto.hu/szemelyauto/bmw/525/bmw_525i_komfortbelso-xenon-szerv_konyv-1_tulaj-16268679, but I'd like to put the thumbnails next to the main image. – Mower Oct 07 '20 at 13:53
  • I do not get what you want to archieve exactly. You want one big image, and right next to this the thumbnails, is this correct? Should the thumbnails or the **container** of the thumbnails have the height of the image? Is this container scrollable? Should the thumbnail images stay in their original ratio? – michaelT Oct 07 '20 at 13:56
  • 1. Yes it's correct. The container of the thumbnails should have the height of the image. The thumbnails container is scrollable, and they should stay in their ratio if it's possible. – Mower Oct 07 '20 at 14:17
  • I could make an example where the container and the main image have a fixed/responsive width/height. I would recommend this because there is a problem when you change the height of the main image. When you do that, the whole container always changes its dimensions and would move other elements of your HTML, so the whole thing wouldn't be "move". – michaelT Oct 07 '20 at 14:25
  • The only problem with the fixed main image width/height is it's always different, because users will upload different image ratios – Mower Oct 07 '20 at 14:34
  • So now I have to different solutions. Please take a look at them. – michaelT Oct 07 '20 at 16:35
  • Thank you very much, the pure html+css solution is way better than I asked for. Accepted your answer! :D – Mower Oct 07 '20 at 17:14
  • sorry, I just ran into a problem. If I use a big size image, it ruins the whole gallery. For example: https://i.postimg.cc/HxYVdxM7/image.png – Mower Oct 07 '20 at 17:31
  • I can not reproduce the problem in my codepen. Please try it in my setup https://codepen.io/michaelkonstreu/pen/jOrOYja. If it should not work, I'ld need the image (or at least the original size of the image) for testing. – michaelT Oct 07 '20 at 17:51
  • For example these images: https://postimg.cc/gallery/WvFWXB2/f00c1a72 – Mower Oct 07 '20 at 18:15
  • It works for me, added a picture in the post above. But in your picture it seems that your gallery has another structure as mine, or something else, e.g. `width`,`height`, `max-width` ect. parameters are different. Which browser do you use? I tested it with chrome. Maybe have a look again at my posted codepen. As I said, I think your structure isn't the same, it seems that a parent element of your gallery has the `background-image` property. – michaelT Oct 07 '20 at 18:27
  • I'm using this gallery on a bootstrap modal so probably thats the problem. I'll try to fix it tomorrow. Thanks again. – Mower Oct 07 '20 at 18:43
  • 1
    Feel free to ask when you need help. – michaelT Oct 07 '20 at 18:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222699/discussion-between-mower-and-michaelt). – Mower Oct 08 '20 at 07:31
0
document.getElementById("image-thumbnails").style.height = '300px';
Dharman
  • 30,962
  • 25
  • 85
  • 135