Better responsive iframe for embedded YouTube video

I started to include embedded music videos from YouTube on a couple of blog posts, just for fun.

This presented an interesting challenge; YouTube videos are embedded in iframes. You can give them a fixed height and width which ensures they display correctly but then they overflow the screen on a smaller viewport. Alternatively, you can specify a width of 100% which makes the width respond as intended but there’s no way to get the height to comply and maintain the correct aspect ratio.

I searched online and found a couple of solutions; neither of which I was keen on.

Extra HTML

The first common solution I found involved adding an additional div.wrapper around the iframe and applying CSS to both. Whilst this does work, I didn’t want to have to add extra HTML for stylistic purposes. I should be able to do this job using CSS only, on the main element.

Javascript 😒

The second solution involved the use of javascript which I wasn’t interested in. If I can get away with it, I don’t want to use any javascript on this site.

A better solution using calc()

After [a lot of] trial and error, I discovered a great use for calc(). The calc() function lets you perform calculations on CSS property values.

The clever part that makes this work is knowing the width of my main content containing block: 512px. I don’t need to worry about the iframe being responsive beyond this width. I know the width it should be. I can specify the appropriate height for a 16:9 widescreen aspect ratio.

I set width: 100%; as this should always be true even though I know the exact width it makes things simpler later. I then set height: calc((512px / 16) * 9);. Technically, I don’t have to do this. I could calculate the height manually as it won’t change when the width is above 512px but I’ve left the calculation in so you can see what changes later to make the magic happen. (512px / 16) * 9 equals the correct height for a 16:9 widescreen aspect ratio when I know the width is 512px.

When the viewport is narrower than 512px, I use a media query to make the iframe respond accordingly. The width is already set to 100% so I don’t need to worry about that. It’s the height I need to start responding at the correct size to maintain a 16:9 widescreen aspect ratio. The width of the viewport is suddenly very relevant to help achieve this. I am able to find out what the width of the viewport is by using vw as a measurement unit.

vw is equal to 1% of the width of the viewport and the browser knows what this is whenever it changes. I can use the measurement of 100vw in my calculation to track the width of the viewport and serve up the right height to maintain a responsive aspect ratio with height: calc((100vw / 16) * 9);

iframe {
  width: 100%;
  height: calc((512px / 16) * 9);
}
@media (max-width: 512px) {
  iframe {
    height: calc((100vw / 16) * 9);
  }
}

That’s it: a better responsive iframe for embedded YouTube videos using CSS only, on the element.