NoLoJS logo

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

Wonderfully descriptive text

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

[`picture`](https://webstatus.dev/features/picture) [`video`](https://webstatus.dev/features/video) [`grid`](https://webstatus.dev/features/grid)

CodePen

See the Pen on CodePen.