Aspect ratio for video embeds
Use the aspect-ratio property to lock a video embed container to 16/9 — the modern replacement for the padding-top hack that is now universally supported.
Quick implementation
/* 16:9 responsive video wrapper */
.video-wrapper {
aspect-ratio: 16 / 9;
width: 100%;
overflow: hidden;
border-radius: var(--radius);
background: oklch(0.19 0.02 260); /* fallback while loading */
}
/* iframe or video fills the container */
.video-wrapper iframe,
.video-wrapper video {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* Fallback for very old browsers using @supports */
@supports not (aspect-ratio: 16 / 9) {
.video-wrapper {
position: relative;
padding-top: 56.25%; /* 9 / 16 × 100 */
height: 0;
}
.video-wrapper iframe,
.video-wrapper video {
position: absolute;
inset: 0;
height: 100%;
}
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer explaining responsive video embed techniques.
Goal: Create a responsive video embed container locked to a 16:9 aspect
ratio using the modern aspect-ratio CSS property, replacing the old
padding-top hack.
Technical constraints:
- Use aspect-ratio: 16 / 9 on the wrapper element with width: 100%.
- Do not use the padding-top: 56.25% hack as the primary approach.
- Provide a @supports not (aspect-ratio: 16 / 9) fallback using the
padding-top method for environments that do not support aspect-ratio.
- The iframe or video child should fill the wrapper completely using
width: 100%; height: 100%.
- Use oklch() for any color values — no hex or rgba.
- No JavaScript required.
Framework variant (pick one):
A) Vanilla CSS — a .video-wrapper class applied to a div that wraps
the iframe or video element, with a @supports block for the
padding-top fallback.
B) React component — VideoEmbed accepts a src prop and renders the
wrapper div with the iframe inside, applying aspect-ratio via
a CSS module or inline style.
Edge cases to handle:
- The container should not crop content if the video player controls
extend outside the intrinsic bounds — use overflow: hidden with care.
- For portrait or square videos, document how to change the ratio
(e.g., aspect-ratio: 1 for square, aspect-ratio: 9 / 16 for portrait).
- Note that setting both width and height attributes on the iframe as
well as the CSS ensures correct rendering in RSS readers and email.
- For lazy-loaded iframes (loading="lazy"), the aspect-ratio approach
prevents layout shift because the space is reserved before the iframe loads.
Return CSS only (or a React component if variant B is chosen).
Why aspect-ratio replaced the padding-top hack
For years, maintaining a 16:9 ratio on a responsive <iframe> embed required the padding-top percentage hack — padding-top: 56.25% on a zero-height container. This exploited the fact that percentage padding is calculated relative to the element's width, not its height. The iframe was then absolutely positioned to fill the padded box. It worked, but required multiple CSS rules and was unintuitive to anyone encountering it for the first time.
The aspect-ratio property replaces all of that with a single declaration: aspect-ratio: 16 / 9. The browser derives and maintains the height automatically whenever the width changes. No absolute positioning, no magic percentage numbers, no wrapper-within-wrapper markup. The result is cleaner HTML and CSS that communicates intent directly.
Because aspect-ratio is now in Baseline Widely Available — supported since Chrome 88, Firefox 89, Safari 15, and Edge 88 — the padding-top fallback is only needed when supporting very old browsers. A @supports not block limits the fallback to browsers that genuinely need it, keeping the primary code clean.
How aspect-ratio works
The aspect-ratio property accepts a ratio written as width / height or a single number treated as number / 1. When the element has a constrained width (such as width: 100% inside a block or flex container), the browser calculates the height from the ratio. When the height is constrained instead, the width is derived. If both are set explicitly, aspect-ratio is overridden.
For video embeds, width: 100% on the wrapper combined with aspect-ratio: 16 / 9 means the container always fills its parent horizontally while the height adjusts proportionally. The child iframe or video is then sized to width: 100%; height: 100% to fill the wrapper.
The property composes naturally with max-width. A wrapper with max-width: 640px; width: 100%; aspect-ratio: 16 / 9 caps at 640px wide while remaining perfectly proportional at smaller viewport sizes.
Combining with object-fit for video elements
When using a native <video> element rather than an iframe, object-fit controls how the video content fills its box. The default fill stretches the video to match the element dimensions exactly — fine when the video's intrinsic ratio matches the container's aspect-ratio, but distorting when they differ.
Use object-fit: cover to crop the video to fill the container while preserving its intrinsic ratio — suitable for background-style video. Use object-fit: contain to letterbox the video so the full frame is always visible. Combine either with aspect-ratio on the wrapper for full control over presentation regardless of source dimensions.
For iframes, object-fit has no effect because the iframe content is a separate browsing context. The iframe element itself should be sized to width: 100%; height: 100% and the video player inside the iframe manages its own presentation.
Browser support
The aspect-ratio property is widely supported. It landed in Chrome 88 (January 2021), Firefox 89 (June 2021), Safari 15 (September 2021), and Edge 88 (January 2021). More than three years of browser releases include native support, making it safe to use without a fallback for the vast majority of real-world traffic.
For sites with strict legacy support requirements, the @supports not (aspect-ratio: 16 / 9) block provides the padding-top fallback only to browsers that need it. Modern browsers skip the @supports not block entirely, so the fallback code has zero cost for current users.