0

I'm trying to maximize the size of an element (embedded video player iframe) within particular constraints:

  1. it should not be taller than 2/3 the height of its parent.
  2. it should not be wider than its parent.
  3. it should maintain its 16:9 aspect ratio

I'm currently achieving this with Javascript (0.5625 and 1.778 are decimal representations of the 16:9 aspect ratio):


function updateDimensions () {
    const video = document.querySelector('#video-player')
    const parentRect = document.querySelector("#parent").getBoundingClientRect()

    const maxHeight = parentRect.height * 0.667
    const maxWidth = Math.min(maxHeight * 1.778, parentRect.width) 

    video.setAttribute('width', maxWidth + 'px')
    video.setAttribute('height', maxWidth * 0.5625 + 'px')
  }

This code is run once on mount, and (debounced) on every resize.

It really seems like this should be CSS' job though, it would probably be more efficient as CSS, and feels like something that should be achievable with calc(), min(), custom properties (variables) and aspect-ratio in CSS, but I just can't work out how.

This is how far I got:

#video-player {
  --parent-height: ???
  /* 1. should not be higher than 2/3 of its parent */
  --max-video-height: calc(var(--parent-height) * 0.667)
  /* 2. should not be wider than its parent */
  --video-width: min(calc(var(--max-video-height) * 1.778), 100%)

  width: var(--video-width)   
  /* 3. should maintain its 16:9 aspect ratio */
  /* height can be calculated with either: */
  height: calc(var(--video-width) * 0.5625)
  /* or: */
  aspect-ratio: 16 / 9 
}

The way that I've written it, it all hinges on getting the parent height into a variable.

Is there a way to do so? Or is there another way to write this in CSS to achieve what the Javascript code does?

NOTE: I had previously been using a wrapper div and the #video-container { padding-top: 56.25% } hack to maintain the video's aspect ratio, but having the container set to position: relative seemed to conflict with my attempts to align it with align-self: center; justify-self: center; (it's a grid item). I guess I could wrap the wrapper in another wrapper and put that in the grid, but the Javascript code does exactly what I want to the element in question, without the need for extra divs.

1
  • Not thoroughly tested, but this should do the trick: video { aspect-ratio: 16/9; width: 100%; max-height: 66.6667% }. Given that the parent has some width/height constraints. Commented Jul 2, 2022 at 22:02

1 Answer 1

1

Depending on how your video is being added (<iframe> or <video>), this should be all you need:

#video-player { height: 100%; max-height: 66.6667%; aspect-ratio: 16/9; }

Working sample on codepen

Also worth being aware of how well supported aspect-ratio is. You can see that here on the caniuse website.

Sign up to request clarification or add additional context in comments.

2 Comments

Works great! I guess that I can use this, with a CSS.supports('aspect-ratio') check to determine if the JS function should run or not. (Of course, CSS.supports itself isn't supported in IE, but oh well, should expand my coverage a little) developer.mozilla.org/en-US/docs/Web/API/CSS/supports
@cameralibre, that's great! I wouldn't worry about IE, Microsoft has officially retired it as of 15 June 2022. I'm not sure if you need it, but you could use the feature detection library 'Modernizr' if you needed a way to detect if your function should run. Helpful to know about it even if you don't use it now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.