Background Video

Ambient video used as a section background.

Field notes, in motion

normal motion

html

<section class="bg-video bg-video--normal">
  <video class="bg-video__el" autoplay muted loop playsinline poster="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='225'%3E%3Crect width='400' height='225' fill='%23241430'/%3E%3Ccircle cx='320' cy='40' r='90' fill='%23A8E6C1' opacity='0.5'/%3E%3Ccircle cx='60' cy='180' r='110' fill='%23BFD9F2' opacity='0.35'/%3E%3C/svg%3E" aria-hidden="true">
    <!-- Provide a real <source src="your-video.mp4" type="video/mp4"> for playback -->
  </video>
  <div class="bg-video__scrim" style="background:#241430;opacity:45%;"></div>
  <div class="bg-video__content">
    <h2 class="bg-video__heading">Field notes, in motion</h2>
    <span class="bg-video__badge">normal motion</span>
  </div>
</section>
<style>
.bg-video { position: relative; max-width: 360px; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 12px; background: #241430; }
.bg-video__el { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.bg-video__scrim { position: absolute; inset: 0; }
.bg-video__content { position: relative; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; gap: 8px; padding: 16px; color: #FAF7F2; }
.bg-video__heading { margin: 0; font: 700 20px/1.2 system-ui, sans-serif; }
.bg-video__badge { align-self: flex-start; padding: 3px 8px; border-radius: 999px; background: #FAF7F2; color: #241430; font: 600 11px/1.4 system-ui, sans-serif; text-transform: uppercase; letter-spacing: .04em; }
@media (prefers-reduced-motion: no-preference) {
.bg-video--slow .bg-video__badge { animation: bgv-pulse 3s ease-in-out infinite; }
.bg-video--normal .bg-video__badge { animation: bgv-pulse 1.6s ease-in-out infinite; }
.bg-video--fast .bg-video__badge { animation: bgv-pulse .8s ease-in-out infinite; }
}
@keyframes bgv-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
</style>

tailwind

<section class="bg-video-tw bg-video-tw--normal relative max-w-[360px] overflow-hidden rounded-xl bg-[#241430]" style="aspect-ratio:16/9;">
  <video class="absolute inset-0 w-full h-full object-cover" autoplay muted loop playsinline poster="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='225'%3E%3Crect width='400' height='225' fill='%23241430'/%3E%3Ccircle cx='320' cy='40' r='90' fill='%23A8E6C1' opacity='0.5'/%3E%3Ccircle cx='60' cy='180' r='110' fill='%23BFD9F2' opacity='0.35'/%3E%3C/svg%3E" aria-hidden="true">
    <!-- Provide a real <source src="your-video.mp4" type="video/mp4"> for playback -->
  </video>
  <div class="absolute inset-0" style="background:#241430;opacity:45%;"></div>
  <div class="relative h-full flex flex-col justify-end gap-2 p-4 text-[#FAF7F2]">
    <h2 class="m-0 text-xl font-bold">Field notes, in motion</h2>
    <span class="self-start px-2 py-0.5 rounded-full bg-[#FAF7F2] text-[#241430] text-[11px] font-semibold uppercase tracking-wide">normal motion</span>
  </div>
</section>
<style>
@media (prefers-reduced-motion: no-preference) {
.bg-video-tw--slow span { animation: bgv-tw-pulse 3s ease-in-out infinite; }
.bg-video-tw--normal span { animation: bgv-tw-pulse 1.6s ease-in-out infinite; }
.bg-video-tw--fast span { animation: bgv-tw-pulse .8s ease-in-out infinite; }
}
@keyframes bgv-tw-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
</style>

react

export function BackgroundVideo({
  heading = "Field notes, in motion",
  overlayOpacity = 45,
  overlayColor = "#241430",
  speed = "normal",
}) {
  const duration = { slow: "3s", normal: "1.6s", fast: ".8s" }[speed] ?? "1.6s";
  return (
    <section style={{ position: "relative", maxWidth: 360, aspectRatio: "16 / 9", overflow: "hidden",
      borderRadius: 12, background: "#241430" }}>
      <video
        style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }}
        autoPlay muted loop playsInline
        poster="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='225'%3E%3Crect width='400' height='225' fill='%23241430'/%3E%3Ccircle cx='320' cy='40' r='90' fill='%23A8E6C1' opacity='0.5'/%3E%3Ccircle cx='60' cy='180' r='110' fill='%23BFD9F2' opacity='0.35'/%3E%3C/svg%3E"
        aria-hidden="true"
      >
        {/* Provide a real <source src="your-video.mp4" type="video/mp4" /> for playback */}
      </video>
      <div style={{ position: "absolute", inset: 0, background: overlayColor, opacity: overlayOpacity / 100 }} />
      <div style={{ position: "relative", height: "100%", display: "flex", flexDirection: "column",
        justifyContent: "flex-end", gap: 8, padding: 16, color: "#FAF7F2" }}>
        <h2 style={{ margin: 0, font: "700 20px/1.2 system-ui, sans-serif" }}>{heading}</h2>
        <span className="bgv-badge" style={{ alignSelf: "flex-start", padding: "3px 8px", borderRadius: 999, background: "#FAF7F2",
          color: "#241430", font: "600 11px/1.4 system-ui, sans-serif", textTransform: "uppercase",
          letterSpacing: ".04em" }}>
          {speed} motion
        </span>
      </div>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .bgv-badge { animation: bgv-pulse ${duration} ease-in-out infinite; }
          @keyframes bgv-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
        }
      `}</style>
    </section>
  );
}