Search code examples
cssiframescaleviewportcss-transforms

Calculating the scale value to transform an iframe to cover it's content in the viewport


I'm trying to make the object-fit: cover (or background-size: cover if it were an image) using an iframe with a vimeo video. As vimeo adjusts the video size according to the iframe width/height/aspect-ratio I thought that using the transform: scale property could be achieved.

Right know I have this logic to scale an iframe with a vimeo video, in most of the cases does the job (covers the screen) but it's not perfect:

const w = window.innerWidth
const h = window.innerHeight
const ratioVideo = 640 / 360
const ratioScreen = w / h

const calculatedRatio = ratioVideo / ratioScreen
// minimum scale value
const minRatio = 1.45

scaleVideo = calculatedRatio > minRatio ? calculatedRatio : minRatio

And then I have:

<iframe :style="`transform:scale(${scaleVideo})`"..>

but it won't fill completely the viewport, expecially when the viewport ratio is < 1 (landscape with much more width than height)

How would be the right calculation (of the minimun scale transform value) for every resolution? I guess i have the separete the portrait/landscape but can't find the key

Any thoughts?

-EDIT-

Here is a codepen with my current code if it helps to understand (in vanilla js because i'm using vuejs in my environment)

-UPDATE-

This updated codepen almost achieves what i mean, but for reason i have to add a small percentage to the caculated ratio, I guess it's becuase the scroll bars or something? code preview:

let calculate = function () {
  const w = window.innerWidth
  const h = window.innerHeight
  const ratioVideo = 640 / 360
  const ratioScreen = w / h

  if (ratioScreen > ratioVideo) {
    calculatedRatio = ratioScreen / ratioVideo
  } else {
    calculatedRatio = ratioVideo / ratioScreen
  }

  /* a little % more */
  calculatedRatio = calculatedRatio * 1.07 
  document.documentElement.style.setProperty('--s', calculatedRatio);
}

Solution

  • If you remove centering code from CSS, your demo works. See this pen

        .video {
          position: relative;
          width: 100%;
          height: 100%;
          overflow: hidden;
        }
    
        :root {
          --s: 1;
        }
    
        .video__player {
          position: absolute;
          width: 100%;
          height: 100%;
          transform: scale(var(--s));
        }
    
    let calculate = function () {
      const w = window.innerWidth
      const h = window.innerHeight
      const ratioVideo = 640 / 360
      const ratioScreen = w / h
    
      const calculatedRatio = Math.max(ratioScreen, ratioVideo) / Math.min(ratioScreen, ratioVideo);
    
      document.documentElement.style.setProperty('--s', calculatedRatio);
      console.log(calculatedRatio)
    }
    
    calculate()
    window.onresize = () => {
      calculate()
    }
    

    Explanation: your iframe is set at 100% width/height, meaning it's technically already centered to the viewport. When using transform: scale function without specifying transform-origin, default value will be 50% 50% meaning it will scale from center of that element and not top left corner.