Skip to content

Unified media-background + overlay macro with automatic z-index #489

Description

@jackgranatowski

Problem

There's no recipe for the classic "hero with a real <video> (or <img>) as the background" pattern — where the media is an actual DOM element (not a CSS background-image), an overlay/gradient sits on top of it for legibility, and the section's real content sits above both without the author manually wiring z-index.

Today an author has to hand-assemble three things themselves:

<section style="position: relative">
  ``&lt;video class="sf-overlay" autoplay muted loop src="/hero.mp4"&gt;``</video>
  <div class="sf-overlay" style="background: var(--sf-scrim-gradient)"></div>
  <div style="position: relative; z-index: 1">  <!-- ← this z-index is the manual step -->
    <h1>Hero content</h1>
  </div>
</section>

.sf-overlay (core/layout.css, position: absolute; inset: 0) already solves positioning the video and the gradient div. Nothing solves the third line — stacking real content above them — automatically.

Not the same as .sf-surface-bg (#523 / #559)

.sf-surface-bg (landing via #559) solves a different, CSS-only case: a base color + background-image (photo/gradient/pattern) + an overlay, all composed as two layers of one background-image property on a single element — see the worked example in the discussion above. Because it's pure background-*, there is no separate element and therefore no stacking problem to solve: content in normal flow already paints above a background-image for free.

That composition cannot hold a real <video> element (autoplaying/looping video isn't expressible as a CSS background), and it does nothing for the "auto z-index my content" problem this issue is about. The two issues are complementary, not duplicates:

.sf-surface-bg (#523/#559) This issue (#489)
Media type CSS background-image only Real <img>/<video> element
Overlay 2nd background-image layer Separate overlay element (like .sf-overlay)
Content stacking Automatic (nothing to do — it's just a background) Manual today — this issue closes that gap

.sf-scrim is the closest existing precedent for "automatic content stacking": it already does position: relative; z-index: 1 on > :not(img, picture, video, svg, canvas) / .sf-scrim__content — but .sf-scrim doesn't position a background media element for you; it assumes you already have one in flow (e.g. an <img> as a normal child, not absolutely positioned as a full-bleed background).

Scope

  • A macro/recipe (e.g. .sf-media-bg — naming TBD) that, applied to a container holding a background <img>/<video> element (positioned via .sf-overlay or equivalent) plus a content element:
    • Automatically stacks the content above the media + overlay via z-index (reusing --sf-z-overlay or a dedicated token — no new token group), matching .sf-scrim's existing auto-stack pattern.
    • Supports an optional overlay layer (reuse --sf-scrim-gradient/--sf-scrim-color — don't reinvent overlay tokens).
  • Document in docs/macros.md with a full HTML usage example (like the one above, minus the manual z-index).
  • Note in the docs how this differs from .sf-surface-bg (CSS-background-only) so users pick the right one.

Acceptance criteria

  • Applying the macro to a <video>/<img>-background section auto-stacks real content above it — no manual z-index needed
  • Optional overlay/gradient supported, built from existing scrim tokens
  • Documented with a worked example, cross-referenced against .sf-surface-bg

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions