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

212 Views Asked by At

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?

3

There are 3 best solutions below

2
Damzaky On BEST ANSWER

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>

6
tcgconsolee On

SOLUTION 1

This uses js to forcefully set the max-height so that the controls are resized

window.addEventListener('load', () => {
            document.getElementsByClassName('gallery')[0].style.width = "800px"
        })
        function widthCheck() {
if(document.getElementsByClassName('gallery')[0].style.width.split("p")[0] - 330 < document.getElementsByClassName('gallery')[0].style.height.split("p")[0]) { 
  
                document.getElementsByTagName('video')[0].style.maxHeight = document.getElementsByClassName('gallery')[0].style.width.split("p")[0]/2 + "px"

                document.getElementsByTagName('video')[0].style.marginTop = document.getElementsByTagName('video')[0].style.maxHeight.split("p")[0]/((document.getElementsByClassName('gallery')[0].style.width.split("p")[0]/document.getElementsByClassName('gallery')[0].style.height.split("p")[0])/0.8) + "px"
            } else {
                document.getElementsByTagName('video')[0].style.maxHeight = "none"
                document.getElementsByTagName('video')[0].style.marginTop = "0px"
            }
            if(document.getElementsByClassName('gallery')[0].style.width.split("p")[0] < 80) {
                document.getElementsByClassName('gallery')[0].style.width = "80px"
            }
        }
setInterval(widthCheck)
.gallery {
  display: flex;
  overflow-x: auto;
  resize: both;
  background-color: rgb(200, 200, 200);
  padding: 10px;
  height: 200px;
  min-width: 80px;
  min-height: 30px;
}

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

I can provide an explanation if needed

SOLUTION 2

you can also fix this is by setting the object-fit property in the css to cover. This won't change the size of the audio controls, instead will make the video adjust its size accordingly.

I will put the code snippet below for what I just said

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

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

.item img,
.item video {
  max-width: 100%;
  max-height: 100%;
  object-fit: cover;
  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>

Since we can't change the size of the audio controls, this is the only way.

2
imhvost On

So that the video does not get cut off and does not lose its proportions, it is not necessary to stretch it. I would do something like this:

* {
  margin: 0;
  padding: 0;
}

.gallery {
  display: flex;
  overflow-x: auto;
  background-color: rgb(200, 200, 200);
  padding: 10px;
  height: 220px;
  column-gap: 16px;
}

.item {
  flex: none;
  display: flex;
}

.gallery-video-wrapper {
  position: relative;
  display: flex;
  overflow: hidden;
}

.gallery-video-bg {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  filter: blur(2px);
  object-fit: cover;
}

.gallery-video{
  position: relative;
  z-index: 1;
  margin: auto;
  max-height: 100%;
}

.item img {
  height:100%;
  overflow: hidden;
  margin: auto;
}

.description {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  text-align: center;
  padding: 0 8px;
}
<div class="gallery">
  <div class="item">
    <div class="gallery-video-wrapper">
      <video src="https://www.w3schools.com/html/mov_bbb.mp4" class="gallery-video-bg"></video>
      <video src="https://www.w3schools.com/html/mov_bbb.mp4" class="gallery-video" controls></video>
    </div>
    <div class="description">Video</div>
  </div>
  <div class="item">
    <img src="https://picsum.photos/260/220">
    <div class="description">One</div>
  </div>
  <div class="item">
    <img src="https://picsum.photos/200/240">
    <div class="description">Two</div>
  </div>
  <div class="item">
    <img src="https://picsum.photos/160/260">
    <div class="description">Three</div>
  </div>
</div>

P.S. You can synchronize the background video using javascript.