Search code examples
htmlcssvideohtml5-videosizing

How can I preserve the height of an HTML video based on its content?


This is my code:

.gallery {
  display: flex;
  overflow-x: auto;
  resize: both;
  background-color: rgb(200, 200, 200);
  padding: 10px;
  height: 200px;
}

.item {
  display: flex;
  flex: 0 0 auto;
  max-width: 100%;
}

.item img,
.item video {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  min-width: 0;
}

.description {
  margin-right: 30px;
  margin-left: 5px;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  text-align: center;
}
<div class="gallery">
  <div class="item">
    <video controls>
      <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
    </video>
    <div class="description">Video</div>
  </div>
  <div class="item">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Wald018.jpg/256px-Wald018.jpg">
    <div class="description">One</div>
  </div>
  <div class="item">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg/256px-Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg">
    <div class="description">Two</div>
  </div>
  <div class="item">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Swedish_Spruce_Forest.jpg/297px-Swedish_Spruce_Forest.jpg">
    <div class="description">Three</div>
  </div>
</div>

My question is based on this article. It works well with images, and also seems to work well with videos. But if for example the ratio of the browser window changes, then the container of a HTML video is bigger than the actual video. You can see it here in an abstract way: enter image description here

How can we let the video container always keep the size of the actual video?


Solution

  • We can use align-items: center to the .items class so that they aren't stretched, and then we can stretch it by adding height: 100% to the image and video selector then also add max-width: none to both .items and image and video selector, like this:

    .gallery {
      display: flex;
      overflow-x: auto;
      resize: both;
      background-color: rgb(200, 200, 200);
      padding: 10px;
      height: 200px;
    }
    
    .item {
      display: flex;
      flex: 0 0 auto;
      max-width: none;
      align-items: center;
    }
    
    .item img,
    .item video {
      max-height: 100%;
      object-fit: contain;
      min-width: 0;
      height: 100%;
      max-width: none;
    }
    
    .description {
      margin-right: 30px;
      margin-left: 5px;
      writing-mode: vertical-rl;
      transform: rotate(180deg);
      text-align: center;
    }
    <div class="gallery">
      <div class="item">
        <video controls>
          <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
        </video>
        <div class="description">Video</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Wald018.jpg/256px-Wald018.jpg">
        <div class="description">One</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg/256px-Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg">
        <div class="description">Two</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Swedish_Spruce_Forest.jpg/297px-Swedish_Spruce_Forest.jpg">
        <div class="description">Three</div>
      </div>
    </div>

    EDIT:

    I couldn't think of a way of using pure CSS, so I thought of using a bit of javascript for this. Basically, we could "imitate" the video dimensions and add it to an svg element, then we can use that element as the source of the width/height for the video, then we can add the video on top of that svg element, like this:

    const gallery = document.getElementsByClassName("gallery")[0].children
    
    for (var i = 0; i < gallery.length; i++) {
      if (gallery[i].getElementsByTagName("video").length > 0) {
        const originalVideo = gallery[i].getElementsByTagName("video")[0]
    
        originalVideo.addEventListener("loadedmetadata", function(e) {
          var width = this.videoWidth,
            height = this.videoHeight;
          const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
          svg.setAttribute("height", height)
          svg.setAttribute("width", width)
          const vidContainer = document.createElement('div')
          vidContainer.classList += 'video-container'
          const item = this.parentNode
          item.removeChild(this)
          vidContainer.appendChild(svg)
          vidContainer.appendChild(this)
    
          item.insertBefore(vidContainer, item.firstChild);
        }, false);
      }
    }
    .gallery {
      display: flex;
      overflow-x: auto;
      resize: both;
      background-color: rgb(200, 200, 200);
      padding: 10px;
      height: 200px;
    }
    
    .item {
      display: flex;
      flex: 0 0 auto;
      max-width: 100%;
    }
    
    .item img {
      max-width: 100%;
      max-height: 100%;
      object-fit: contain;
      min-width: 0;
    }
    
    .description {
      margin-right: 30px;
      margin-left: 5px;
      writing-mode: vertical-rl;
      transform: rotate(180deg);
      text-align: center;
    }
    
    .item svg {
      height: auto;
      width: auto;
      max-width: 100%;
    }
    
    .video-container {
      position: relative;
      display: flex;
    }
    
    .item video {
      position: absolute;
      left: 0;
      width: 100%;
      align-self: center;
    }
    <div class="gallery">
      <div class="item">
        <video controls>
          <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
        </video>
        <div class="description">Video</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Wald018.jpg/256px-Wald018.jpg">
        <div class="description">One</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg/256px-Ung_norsk_furuskog_og_morgent%C3%A5ke.jpg">
        <div class="description">Two</div>
      </div>
      <div class="item">
        <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Swedish_Spruce_Forest.jpg/297px-Swedish_Spruce_Forest.jpg">
        <div class="description">Three</div>
      </div>
    </div>