CSS variables
Every CSS variable is prefixed steam-block- by default. Set the prefix attribute on an instance to change it, e.g. prefix="hero-" turns --steam-block-background into --hero-background. Set CSS variables globally (steam-block { ... }) for a site-wide look, or scope them to a class/id for one-off instances.
A CSS variable that maps onto a native CSS shorthand (padding, border, border-image) accepts exactly the same value syntax as that property, e.g. --steam-block-padding: 2rem 1rem or --steam-block-media-border: 2px dashed red.
Need a property or an effect that has no variable, like a hover state or a keyframe animation? Style the inside of the component directly with parts.
Theme
Two copy-pasteable starting points: a curated set of the CSS variables you’ll actually reach for first, and the complete set with every CSS variable’s real default value. Put either into your own stylesheet and tweak from there.
steam-block {
/* General */
--steam-block-min-width-breakpoint: 768px; /* stacked below this, side-by-side/overlay above it */
--steam-block-padding: 0px;
--steam-block-background: transparent;
--steam-block-border: 0px solid transparent;
--steam-block-border-radius: 0px;
--steam-block-box-shadow: none;
/* Media */
--steam-block-media-border-radius: 0px;
--steam-block-media-blend-mode: normal;
--steam-block-media-filter: none;
/* Split template (type="split", the default) */
--steam-block-gap: 1.5rem;
--steam-block-media-width: 1fr;
--steam-block-content-width: 1fr;
/* Hero template (type="hero") */
--steam-block-media-aspect-ratio: 16 / 9;
/* shared between templates: hero defaults to center, split to left */
--steam-block-content-text-align: left;
}
steam-block {
/* General: the component itself, both templates */
--steam-block-min-width-breakpoint: 768px;
--steam-block-padding: 0px;
--steam-block-max-width: none; /* ignored with media="fluid" */
--steam-block-background: transparent;
--steam-block-border: 0px solid transparent;
--steam-block-border-top: 0px solid transparent;
--steam-block-border-right: 0px solid transparent;
--steam-block-border-bottom: 0px solid transparent;
--steam-block-border-left: 0px solid transparent;
--steam-block-border-radius: 0px;
--steam-block-box-shadow: none;
/* Media, before layer (::before), both templates */
--steam-block-media-before-opacity: 1;
--steam-block-media-before-background: transparent;
--steam-block-media-before-clip-path: none;
--steam-block-media-before-mask: none;
/* Media slot, both templates */
--steam-block-media-opacity: 1;
--steam-block-media-object-position: center;
--steam-block-media-margin: 0px; /* desktop only (≥breakpoint) */
--steam-block-media-margin-stacked: 0px; /* stacked only (<breakpoint) */
--steam-block-media-border: 0px solid transparent;
--steam-block-media-border-top: 0px solid transparent;
--steam-block-media-border-right: 0px solid transparent;
--steam-block-media-border-bottom: 0px solid transparent;
--steam-block-media-border-left: 0px solid transparent;
--steam-block-media-border-radius: 0px;
--steam-block-media-box-shadow: none;
--steam-block-media-clip-path: none;
--steam-block-media-mask: none;
--steam-block-media-blend-mode: normal;
--steam-block-media-filter: none;
--steam-block-media-transform: none;
--steam-block-media-transition: none;
/* Media, after layer (::after), both templates */
--steam-block-media-after-opacity: 1;
--steam-block-media-after-background: transparent;
--steam-block-media-after-border-image: none;
--steam-block-media-after-clip-path: none;
--steam-block-media-after-mask: none;
--steam-block-media-after-blend-mode: normal;
/* Content, before layer (::before), both templates */
--steam-block-content-before-opacity: 1;
--steam-block-content-before-background: transparent;
--steam-block-content-before-clip-path: none;
--steam-block-content-before-mask: none;
--steam-block-content-before-blend-mode: normal;
/* Content slot, both templates */
--steam-block-content-opacity: 1;
--steam-block-content-display: block; /* set to grid/flex to lay out multiple un-wrapped slot="content" children */
--steam-block-content-grid-template-columns: none;
--steam-block-content-gap: normal;
--steam-block-content-margin: 0px; /* desktop only (≥breakpoint) */
--steam-block-content-margin-stacked: 0px; /* stacked only (<breakpoint) */
--steam-block-content-padding: 5vw; /* 0px instead, split only, at/above the breakpoint */
--steam-block-content-background: transparent;
--steam-block-content-border: 0px solid transparent;
--steam-block-content-border-top: 0px solid transparent;
--steam-block-content-border-right: 0px solid transparent;
--steam-block-content-border-bottom: 0px solid transparent;
--steam-block-content-border-left: 0px solid transparent;
--steam-block-content-border-radius: 0px;
--steam-block-content-box-shadow: none;
--steam-block-content-clip-path: none;
--steam-block-content-mask: none;
--steam-block-content-blend-mode: normal;
--steam-block-content-filter: none;
--steam-block-content-transform: none;
--steam-block-content-transition: none;
/* Content, after layer (::after), both templates */
--steam-block-content-after-opacity: 1;
--steam-block-content-after-background: transparent;
--steam-block-content-after-clip-path: none;
--steam-block-content-after-mask: none;
--steam-block-content-after-blend-mode: normal;
/* Split, type="split", the default: the grid itself, then its media
column, then its content column */
--steam-block-gap: 5vw; /* at/above the breakpoint only */
--steam-block-media-align-items: flex-start; /* only visible with data-size="auto"; hero's own default is center, same CSS variable */
--steam-block-media-justify-content: center; /* only visible with data-size="auto" */
--steam-block-content-justify-content: center;
--steam-block-media-width: 1fr;
--steam-block-media-min-width: 0;
--steam-block-content-width: 1fr;
--steam-block-content-min-width: 0;
--steam-block-content-text-align: left; /* hero's own default is center, same CSS variable */
/* Hero, type="hero": the overlay itself, then its media background,
then its content. -media-align-items/-media-justify-content and
-content-justify-content/-content-text-align are the same shared
CSS variables as Split above, hero just falls back to a different
default for each */
--steam-block-media-aspect-ratio: 16 / 9;
--steam-block-hero-align-items: center; /* hero-only, split's .content is unconditionally width:100% */
--steam-block-hero-media-max-width: none; /* media="fluid" only: caps the breakout width */
--steam-block-hero-content-width: auto; /* at/above the breakpoint only */
--steam-block-hero-content-max-width: 99%; /* at/above the breakpoint only */
/* Internal, read-only, don't set */
--steam-block-scrollbar-width: 0px;
}
Full reference
“Active at” means viewport width relative to --steam-block-min-width-breakpoint, unless it says otherwise.
General
The component itself, both templates.
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-min-width-breakpoint demo |
Viewport width the layout switches at. Default 768px. |
All widths |
--steam-block-padding demo |
padding of the section. |
All widths |
--steam-block-max-width demo |
max-width of the section, centered with margin-inline: auto. Ignored with media="fluid". |
All widths |
--steam-block-background demo |
Background of the section. | All widths |
--steam-block-border demo |
border shorthand of the section. |
All widths |
--steam-block-border-top demo |
border-top of the section, overrides --steam-block-border for that one side. |
All widths |
--steam-block-border-right demo |
border-right of the section. |
All widths |
--steam-block-border-bottom demo |
border-bottom of the section. |
All widths |
--steam-block-border-left demo |
border-left of the section. |
All widths |
--steam-block-border-radius demo |
border-radius of the section. hero clips its media to this radius (overflow: hidden) at every width. split doesn’t clip, so its media keeps square corners where it meets a rounded one: round it with --steam-block-media-border-radius too, or keep it off the corner with --steam-block-padding. |
All widths |
--steam-block-box-shadow demo |
box-shadow of the section. |
All widths |
Media
Control the element(s) placed in the media slot.
Media, before layer
Media, before layer (::before, painted behind the media). Clipped by --steam-block-media-clip-path/--steam-block-media-mask along with the media itself. Use --steam-block-background instead if you need color to show through a clip-path/mask cut. No border/box-shadow/margin/border-radius of its own, only the media box has those (below), and it always rounds to match the media’s own corner:
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-media-before-opacity demo |
opacity of the layer. Default 1. |
All widths |
--steam-block-media-before-background demo |
Background color/image of the layer. | All widths |
--steam-block-media-before-clip-path demo |
clip-path of the layer. |
All widths |
--steam-block-media-before-mask demo |
mask of the layer. |
All widths |
Media itself
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-media-opacity demo |
opacity of the media itself. |
All widths |
--steam-block-media-object-position demo |
object-position of the media. |
All widths |
--steam-block-media-margin demo |
margin on the media box, lets it bleed past its own column/box. hero clips this at its own overflow: hidden; split doesn’t clip it. |
Desktop only (≥breakpoint) |
--steam-block-media-margin-stacked |
The same margin on the media box, for the stacked layout below the breakpoint, where -media-margin is not read. A negative top margin lifts the media out of the block, see Floating in space. Clipped in hero like -media-margin. |
Stacked only (<breakpoint) |
--steam-block-media-border demo |
border around the media. |
All widths |
--steam-block-media-border-top demo |
border-top of the media. |
All widths |
--steam-block-media-border-right demo |
border-right of the media. |
All widths |
--steam-block-media-border-bottom demo |
border-bottom of the media. |
All widths |
--steam-block-media-border-left demo |
border-left of the media. |
All widths |
--steam-block-media-border-radius demo |
border-radius of the media. |
All widths |
--steam-block-media-box-shadow demo |
box-shadow of the media. |
All widths |
--steam-block-media-clip-path demo |
clip-path of the media. |
All widths |
--steam-block-media-mask demo |
mask of the media. |
All widths |
--steam-block-media-blend-mode demo |
mix-blend-mode of the media. |
All widths |
--steam-block-media-filter demo |
filter on the media. |
All widths |
--steam-block-media-transform demo |
transform on the media, e.g. scale(1.05). |
All widths |
--steam-block-media-transition |
transition shorthand on the media (and, in split, the column wrapping it). Default none. Pairs with steam-emerge or any class/attribute toggle that changes a -media-* variable’s value. |
All widths |
Media, after layer
Media, after layer (::after, painted on top of the media). Same property set as the before layer, plus border-image:
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-media-after-opacity demo |
opacity of the layer. Default 1. |
All widths |
--steam-block-media-after-background demo |
Background color/image of the layer. | All widths |
--steam-block-media-after-border-image demo |
border-image of the layer. Pair with --steam-block-media-border (same width, transparent) to reserve real space for it, otherwise it paints over the media’s own edge. |
All widths |
--steam-block-media-after-clip-path demo |
clip-path of the layer. |
All widths |
--steam-block-media-after-mask demo |
mask of the layer. |
All widths |
--steam-block-media-after-blend-mode demo |
mix-blend-mode of the layer. |
All widths |
The after layer is always pointer-events: none, so clicks still reach the media underneath (a video’s controls, an iframe’s own play button).
Content
Control the wrapping element placed in the content slot. Assumes the slot holds a single wrapper (<div slot="content">...</div>), except --steam-block-content-display, and --steam-block-content-grid-template-columns meant for the case where you skip the wrapper.
Content, before layer
Content, before layer (::before, painted on the content box itself, same box --steam-block-content-background paints on). No border/box-shadow/margin/border-radius of its own, only the content box has those (below), and it always rounds to match the content box’s own corner:
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-content-before-opacity demo |
opacity of the layer. Default 1. |
All widths |
--steam-block-content-before-background demo |
Background color/image of the layer. | All widths |
--steam-block-content-before-clip-path demo |
clip-path of the layer. |
All widths |
--steam-block-content-before-mask demo |
mask of the layer. |
All widths |
--steam-block-content-before-blend-mode demo |
mix-blend-mode of the layer. |
All widths |
Content itself
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-content-opacity demo |
opacity of the slotted content. |
All widths |
--steam-block-content-display demo |
display of the content block. Default block. Set to grid or flex to arrange multiple slotted children with no wrapper <div> (see below). |
All widths |
--steam-block-content-grid-template-columns demo |
grid-template-columns. Only has an effect once -content-display: grid is set. |
All widths |
--steam-block-content-gap demo |
gap between children. Distinct from --steam-block-gap, which is split’s gap between the content and media columns. |
All widths |
--steam-block-content-margin demo |
margin on the content block, all four sides. |
Desktop only (≥breakpoint) |
--steam-block-content-margin-stacked |
The same margin on the content block, for the stacked layout below the breakpoint. A negative top margin pulls the content up over the media, see Magazine overlap. A separate variable, so a desktop offset like -50% never reaches a phone screen. |
Stacked only (<breakpoint) |
--steam-block-content-padding demo |
padding inside the content block. |
All widths (default differs: 5vw below the breakpoint, 0px at/above it in split) |
--steam-block-content-background demo |
Background of the content block. | All widths |
--steam-block-content-border demo |
border around the content block. |
All widths |
--steam-block-content-border-top demo |
border-top of the content block. |
All widths |
--steam-block-content-border-right demo |
border-right of the content block. |
All widths |
--steam-block-content-border-bottom demo |
border-bottom of the content block. |
All widths |
--steam-block-content-border-left demo |
border-left of the content block. |
All widths |
--steam-block-content-border-radius demo |
border-radius of the content block. |
All widths |
--steam-block-content-box-shadow demo |
box-shadow of the content block. |
All widths |
--steam-block-content-clip-path demo |
clip-path of the content block. |
All widths |
--steam-block-content-mask demo |
mask of the content block. |
All widths |
--steam-block-content-blend-mode demo |
mix-blend-mode of the slotted content. |
All widths |
--steam-block-content-filter demo |
filter on the slotted content. |
All widths |
--steam-block-content-transform demo |
transform on the content block. |
All widths |
--steam-block-content-transition |
transition shorthand on the content block (and, in split, the column wrapping it). Default none. Pairs with steam-emerge or any class/attribute toggle that changes a -content-* CSS variable’s value. |
All widths |
Content, after layer
Content, after layer (::after, painted on top of the content box). Same property set as the before layer:
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-content-after-opacity demo |
opacity of the layer. Default 1. |
All widths |
--steam-block-content-after-background demo |
Background color/image of the layer. | All widths |
--steam-block-content-after-clip-path demo |
clip-path of the layer. |
All widths |
--steam-block-content-after-mask demo |
mask of the layer. |
All widths |
--steam-block-content-after-blend-mode demo |
mix-blend-mode of the layer. |
All widths |
The after layer is always pointer-events: none, so clicks and text selection still reach real content underneath (buttons, links).
No media, text only
split still renders an empty media column even with nothing slotted into it. Zero --steam-block-media-width and --steam-block-gap (a Grid gap is reserved regardless of column width) so the content column takes the full row:
.text-only-block {
--steam-block-content-display: grid;
--steam-block-content-grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
--steam-block-content-gap: 2rem;
--steam-block-gap: 0;
--steam-block-media-width: 0;
}
Multiple columns in hero
.content shrinks to fit by default, so a grid of un-wrapped slot="content" children collapses to one narrow column unless you force the overlay to fill its width first:
.hero-columns {
--steam-block-media-after-background: linear-gradient(to top, rgba(0,0,0,.85) 30%, transparent 75%);
--steam-block-content-display: grid;
--steam-block-content-grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
--steam-block-content-gap: 1.5rem;
--steam-block-hero-align-items: stretch;
--steam-block-hero-content-max-width: 100%;
}
<steam-block class="hero-columns" type="hero" overlay="true">
<img slot="media" src="photo.jpg" alt="">
<div slot="content"><strong>Column one</strong></div>
<div slot="content"><strong>Column two</strong></div>
<div slot="content"><strong>Column three</strong></div>
<div slot="content"><strong>Column four</strong></div>
</steam-block>
See Text columns on the examples page for both of these live.
Split-specific
For type="split", the default. The grid itself, then its media column, then its content column.
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-media-aspect-ratio demo | aspect-ratio for the media. Shared with hero (see Hero-specific below), no fallback here. Holds only as long as the media column stays the taller of the two. | All widths |
--steam-block-gap demo | gap between the content and media columns. | Desktop only (≥breakpoint) |
--steam-block-media-align-items demo | align-items of the media within its column, only visible with data-size="auto". Shared with hero, defaults to flex-start here, center there. | All widths |
--steam-block-media-justify-content demo | justify-content of the media within its column, only visible with data-size="auto". Shared with hero, both default to center. | All widths |
--steam-block-content-justify-content demo | justify-content of the content column. Shared with hero, both default to center. | All widths |
--steam-block-media-width demo | Width of the media column. | Desktop only (≥breakpoint); below it the column stacks full-width |
--steam-block-media-min-width demo | Minimum width of the media column. Default 0, no built-in floor. | Desktop only (≥breakpoint) |
--steam-block-content-width demo | Width of the content column. | Desktop only (≥breakpoint); below it the column stacks full-width |
--steam-block-content-min-width demo | Minimum width of the content column. Default 0, no built-in floor. | Desktop only (≥breakpoint) |
--steam-block-content-text-align demo | text-align of the content column. Shared with hero, split defaults to left, hero to center. | All widths |
--steam-block-content-transition/--steam-block-media-transition (documented under Content/Media above) also apply to .left/.right, the columns wrapping them, not just the inner box.
Hero-specific
For type="hero". The overlay itself, then its media background, then its content.
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-media-aspect-ratio demo | aspect-ratio of the media background. Defaults to 16 / 9. Wherever the content overlays the media it is a minimum: the hero keeps the ratio while the content fits and grows taller when it doesn’t, so no text is ever clipped. Shared with split (see Split-specific above). | All widths |
--steam-block-hero-align-items demo | align-items of the content overlay. Hero-only, no split equivalent. | Desktop only (≥breakpoint), or every width once overlay="true" forces the overlay early |
--steam-block-media-align-items demo | align-items of the media within its area, only visible with data-size="auto". Shared with split, defaults to center here, flex-start there. | All widths |
--steam-block-media-justify-content demo | justify-content of the media within its area, only visible with data-size="auto". Shared with split, both default to center. | All widths |
--steam-block-content-justify-content demo | justify-content of the content overlay. Shared with split, both default to center. | All widths |
--steam-block-hero-media-max-width demo | Caps the width of the background media. | All widths (media="fluid" only) |
--steam-block-hero-content-width demo | width of the content overlay. Default auto, the overlay sizes to its own content.Set a value such as 45% or 32rem for a fixed box that keeps its --steam-block-hero-align-items position. | Desktop only (≥breakpoint) |
--steam-block-hero-content-max-width demo | max-width of the content overlay. Default 99%. | Desktop only (≥breakpoint) |
--steam-block-content-text-align demo | text-align of the content overlay. Shared with split, hero defaults to center, split to left. | All widths |
Internal
| CSS variable | Description | Active at |
|---|---|---|
--steam-block-scrollbar-width | Set automatically on :host from the browser’s scrollbar width, used internally by the media="fluid" breakout math. Read-only. | All widths |
See every variable rendered live in the Visual reference, and combined into complete examples in Usage.