Video Hero - Content over video
Using CSS grid to position a video element “over” a picture element to serve as responsive placeholder images, no JS required.
Demo
My Brilliant Product
Something you really need to buy now!
HTML
<!-- Wrapper for content and media -->
<div class="container--media-content">
<!-- Wrapper for `picture` and `video` elements -->
<div class="container--media">
<!-- Each `width`, `height` and `media` value should match, respectively (first `pciture` > `source` with first `video` > `source`, etc.) -->
<picture>
<!-- `fetchpriority="high"` assumes this component is above-the-fold; if not, replace it with `loading="lazy"`-->
<source
fetchpriority="high"
width="720"
height="1280"
srcset="https://aarontgrogg.com/wp-content/uploads/2025/12/video-hero-components-image-portrait.webp"
media="(max-width: 480px)" />
<source
fetchpriority="high"
width="1280"
height="720"
srcset="https://aarontgrogg.com/wp-content/uploads/2025/12/video-hero-components-image-landscape.webp"
media="(min-width: 481px)" />
<img src="" alt="Wonderfully descriptive text" />
</picture>
<video playsinline autoplay loop muted controls>
<!-- `fetchpriority="high"` assumes this component is above-the-fold; if not, replace it with `preload="none"`-->
<source
fetchpriority="high"
width="720"
height="1280"
src="https://aarontgrogg.com/wp-content/uploads/2025/12/video-hero-components-video-portrait.mp4"
media="(max-width: 480px)" />
<source
fetchpriority="high"
width="1280"
height="720"
src="https://aarontgrogg.com/wp-content/uploads/2025/12/video-hero-components-video-landscape.mp4"
media="(min-width: 481px)" />
</video>
</div>
<!-- Wrapper for any content you wish to display over the media; can also be removed without causing harm -->
<div class="container--content">
<h1>My Brilliant Product</h1>
<p>Something you really need to buy now!</p>
<button>Add to Cart</button>
</div>
</div>CSS
/* This grid aligns the `.container--content` "over" the `.container--media` */
.container--media-content {
display: grid;
grid-template: "media-content";
place-items: center;
place-content: start;
& > * {
grid-area: media-content;
}
}
/* This grid aligns the `video` "over" the `picture/img` */
.container--media {
width: 100%;
height: 100%;
display: grid;
grid-template: "media";
place-items: stretch;
place-content: stretch;
& > * {
grid-area: media;
}
/* Make sure video and image assets are the same size, so this aligns them perfectly */
& img, video {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
}
.container--content {
/* Needed to retain accessibility to content, for CTA, etc. */
position: relative;
/* For cosmetics */
padding: 4em;
background-color: rgb(from var(--green-light) r g b / .8);
color: var(--green-dark);
button {
border-radius: 4px;
border: 1px solid var(--green-med);
background-color: var(--green-dark);
padding-block: .5rem;
padding-inline: 2rem;
color: var(--green-light);
font-size: 16px;
cursor: pointer;
}
}JS
No JS required.Baseline
CodePen
See the Pen on CodePen.