Status: Canonical
Last updated: 2025-12-21
Taxonomy placement: D4. Layering (treats depth + elevation as one consumer concept)
CEM uses layering as the umbrella term for:
Companion specs:
cem-colors) — tonal “dig down” vs “lift up”cem-dimension) — breathing room couplingcem-shape) — bend roles for overlays/modalscem-stroke) — contour reinforcement, especially in forced-colorscem-timing) — lift/drop transitions and reduced-motion behaviorLayering communicates relationship and intent before interaction:
In consumer language, layering typically reads as:
Layering exists to support three outcomes:
The tier number communicates priority and meaning (user psychology), not guaranteed draw order. Physical stacking may differ because of clipping, portals, and platform APIs. That physical mismatch does not change the semantic contract.
Normative rules
--cem-elevation-* as a z-index value.Discriminator rules: Overlay vs Floating
Use these rules when physical appearance could be misread (notably when overlays appear over dialogs).
Choose Overlay when the UI is a separate transient layer artifact with its own dismissal semantics (appears/disappears without becoming part of layout).
Typical: menus, popovers, autocomplete lists, date pickers, tooltips.
Choose Floating when the UI is the same object as in the work context, temporarily lifted for affordance while remaining part of the current task.
Typical: hover lift, “picked-up” cards, dragged items.
Examples (required interpretation)
CEM defines exactly 7 canonical tiers. The ladder is signed: two recess rungs, one base rung, and four lift rungs.
The ladder is designed to be perceptually distinct and implementable across light/dark/contrast themes.
| Signed tier | Token | Canonical name | Intended meaning | Typical examples |
|---|---|---|---|---|
| −2 | --cem-recess-2 |
Deep recessed | infrastructure far behind attention | deep shell wells, backstage panels |
| −1 | --cem-recess-1 |
Recessed | back context behind work | side navigation rail, filter plane |
| 0 | --cem-elevation-0 |
Base | ground / canvas | app background, page canvas |
| +1 | --cem-elevation-1 |
Raised | work region separation | cards, primary panels, editors |
| +2 | --cem-elevation-2 |
Floating | interactive lift / grouped focus | hover-lift regions, dragged items |
| +3 | --cem-elevation-3 |
Overlay | contextual transient layer | menus, tooltips, popovers, select lists |
| +4 | --cem-elevation-4 |
Command | must respond / modal decision | dialogs, blocking confirmations |
Layering is experienced as the user moves through a interaction flow.
[ Back layer ] | [ Work layer ]
(nav/context) | (primary content)
Layering is a composition of:
CEM defines five named planes (semantic layer roles). They are typically implemented with portals.
Normative rules
A tooltip can render above a dialog while remaining an Overlay-tier element.
This is not a contradiction; it reflects two truths:
CEM D4 defines three layers of contract.
Basis tokens are the minimal numeric “rungs.” They encode signed tier meaning.
--cem-recess-2--cem-recess-1--cem-elevation-0--cem-elevation-1--cem-elevation-2--cem-elevation-3--cem-elevation-4Semantic endpoints are what components use. They map to basis rungs.
--cem-layer-back--cem-layer-base--cem-layer-work--cem-layer-overlay--cem-layer-commandAdapters describe how the rung is rendered:
Adapters can vary per theme/density without changing semantics.
D4 emits the semantic-aliases shape, not per-channel adapter hooks:
box-shadow recipe (positive recipes for lift, inset
recipes for recess, none for the canvas baseline). This is the most universally meaningful single channel
that is not z-index (using rungs as z-index is explicitly forbidden — see §2.2).var() (--cem-layer-work: var(--cem-elevation-1), etc.).--cem-layer-{rung}-tone, -contour, -material, -space, -motion) are
theme-stylesheet concerns: tone is owned by D0’s .cem-theme-{light,dark,contrast-light,contrast-dark,native}
blocks; contour is owned by D5; spacing by D1; motion by D7. D4 does not redeclare them.This keeps D4 focused on rung shape; theme adapters compose the remaining channels.
§7.2 requires each rung to differ from its neighbors in at least one perceivable channel (≥2 in dense UIs). D4
emits shadow as the canonical channel; tone is the second channel and is supplied per-theme by
cem-colors.html (light/dark/contrast/native blocks). Together those two channels satisfy the rule in normal
themes. In forced-colors: active themes, shadows are stripped — D4’s forced-colors override collapses all rungs
to none, and the tier signal is then carried by D5 contour (--cem-stroke-boundary-strong) and by spatial
isolation. Browser-level verification of “≥1 perceivable channel change per rung” is performed in Phase 13.
The 7-tier ladder rungs are required and must remain stable. Each rung emits as a box-shadow recipe (the
canonical single channel — see §6.4). Recess rungs use inset recipes; lift rungs use outset recipes; the canvas
base is none. Values are perceptually graded so each step differs visibly from its neighbors.
| Token | Value | Description | tier |
|---|---|---|---|
--cem-recess-2 |
inset 0 2px 4px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(0, 0, 0, 0.04) |
Deep recessed (−2) | required |
--cem-recess-1 |
inset 0 1px 2px rgba(0, 0, 0, 0.04) |
Recessed (−1) | required |
--cem-elevation-0 |
none |
Base / canvas (0) | required |
--cem-elevation-1 |
0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 1px rgba(0, 0, 0, 0.04) |
Raised (+1) — work regions | required |
--cem-elevation-2 |
0 2px 4px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.06) |
Floating (+2) — lift within work | required |
--cem-elevation-3 |
0 4px 8px rgba(0, 0, 0, 0.10), 0 2px 4px rgba(0, 0, 0, 0.08) |
Overlay (+3) — menus, tooltips, popovers | required |
--cem-elevation-4 |
0 8px 16px rgba(0, 0, 0, 0.12), 0 4px 8px rgba(0, 0, 0, 0.10) |
Command (+4) — dialogs, modal decisions | required |
When moving by one rung, at least one of the following must change in a perceivable way (and ideally two in high-density UI):
Recess should primarily use tone and contour (shadows are often imperceptible “into” the page).
Lift should primarily use tone + shadow, with contour as a fallback.
Semantic endpoints allow components to express layering without knowing numeric rungs.
| Endpoint | Maps to rung | Meaning |
|---|---|---|
--cem-layer-back |
--cem-recess-1 |
back layer: context behind work |
--cem-layer-base |
--cem-elevation-0 |
canvas/base |
--cem-layer-work |
--cem-elevation-1 |
primary work regions |
--cem-layer-overlay |
--cem-elevation-3 |
contextual transient UI |
--cem-layer-command |
--cem-elevation-4 |
must respond: modal decision |
Note:
--cem-elevation-2(Floating) is most often an internal component choice within the Work layer (e.g., a temporary lifted region), not a global plane.
| Token | Value | Description | tier |
|---|---|---|---|
--cem-layer-back |
var(--cem-recess-1) |
Back: context behind work | required |
--cem-layer-base |
var(--cem-elevation-0) |
Canvas / base | required |
--cem-layer-work |
var(--cem-elevation-1) |
Primary work regions | required |
--cem-layer-overlay |
var(--cem-elevation-3) |
Contextual transient UI (menus, tooltips) | required |
--cem-layer-command |
var(--cem-elevation-4) |
Modal / must-respond surfaces (dialogs) | required |
Optional endpoints are allowed only if they remain stable and scoped, and if they map cleanly to an existing rung without creating new “micro tiers”.
Examples:
--cem-layer-back-deep → --cem-layer-back + --cem-recess-2--cem-layer-work-floating → --cem-layer-work + --cem-elevation-2| Token | Value | Description | tier |
|---|---|---|---|
--cem-layer-back-deep |
var(--cem-recess-2) |
Back layer at deepest recess | optional |
--cem-layer-work-floating |
var(--cem-elevation-2) |
Lifted affordance within work plane | optional |
Layering cues are multi-channel. No single channel is reliable across all themes.
The CEM color ladder is the primary driver of “dig down” vs “lift up.”
Rules
Where supported, material/blur can reinforce overlay separation, but MUST NOT replace tone/contrast requirements.
Layers with higher semantic priority SHOULD “earn” breathing room (inset and/or gap) in comfort density modes.
Lift/drop transitions MAY reinforce the ladder, but the meaning must remain clear in reduced-motion settings.
Scrim communicates modality and commitment.
| Layer role | Typical components | Scrim | Notes |
|---|---|---|---|
| Back / Base / Work | nav, content | none | scrim would reduce usability |
| Overlay | menus, popovers, tooltips | optional (rare) | only if overlay must strongly detach from busy content |
| Command | dialogs, blocking confirmations | required | command owns modality, focus trap, and dismissal precedence |
Layering (signed depth) and action states (visual priority order) must not contradict each other.
State changes (hover, focus, pressed, selected, disabled, readonly) MUST NOT change the layer endpoint. They may adjust rung rendering (tone/contour/shadow) within a bounded range.
Action states must align with layering cues and color ladder direction.
A button becoming hovered does not become an Overlay. State changes should be expressed as micro-shifts within the component’s assigned layer role.
This guidance assumes the component’s base endpoint is correct.
Pressed feedback may reduce shadow (a “press in”), but MUST preserve the state’s prominence via tone/contour so the user does not read it as “disabled or background.”
Layering relies on other dimensions for robustness:
Layering MUST NOT rename or duplicate these dimensions; it only defines coupling invariants.
Layer meaning must remain readable without shadows and with limited color (e.g., high-contrast themes). Therefore:
In forced-colors:
In forced-colors: active themes, shadows are stripped by the user agent. D4’s generator collapses every rung’s
shadow recipe to none, and components rely on D5 contour (--cem-stroke-boundary-strong) plus spatial
isolation to carry the tier signal.
| Token | Forced-colors value |
|---|---|
--cem-recess-2 |
none |
--cem-recess-1 |
none |
--cem-elevation-0 |
none |
--cem-elevation-1 |
none |
--cem-elevation-2 |
none |
--cem-elevation-3 |
none |
--cem-elevation-4 |
none |
cem-layering-rungs-forced is generator-only — no new tokens. The same rung names are redeclared inside
@media (forced-colors: active) :root { … }.
This matrix maps common component families to layer endpoints and their default rung.
| Component family | Layer endpoint | Default rung | Notes |
|---|---|---|---|
| App shell (chrome) | --cem-layer-back |
--cem-recess-1 |
recessed context; low brand energy |
| Backstage wells (rare) | --cem-layer-back |
--cem-recess-2 |
use sparingly; avoid turning the UI into “tunnels” |
| Page canvas | --cem-layer-base |
--cem-elevation-0 |
ground / canvas |
| Main content panels | --cem-layer-work |
--cem-elevation-1 |
default work separation |
| Floating affordances (within work) | --cem-layer-work |
--cem-elevation-2 |
same object lifted (hover/drag) |
| Tooltip | --cem-layer-overlay |
--cem-elevation-3 |
may portal above dialogs; remains Overlay |
| Menu / popover / select list | --cem-layer-overlay |
--cem-elevation-3 |
portal/top-layer; dismiss precedence above dialog |
| Sheet (non-blocking) | --cem-layer-overlay |
--cem-elevation-3 |
optional scrim only if required |
| Dialog / confirmation | --cem-layer-command |
--cem-elevation-4 |
owns modality, scrim, focus trap |
| Toast / global banner | --cem-layer-overlay |
--cem-elevation-3 |
if it blocks progress, treat as Command |
The following demonstrates the mapping shape; it is not a required implementation.
/* Semantic endpoints select a rung; adapters render the rung. */
.cem-layer--work { --cem-rung: var(--cem-elevation-1); }
.cem-layer--overlay { --cem-rung: var(--cem-elevation-3); }
.cem-layer--command { --cem-rung: var(--cem-elevation-4); }
/* Adapter hooks (tone/shadow/contour) are theme-specific. */
.cem-layer {
background: var(--cem-layer-tone, Canvas);
box-shadow: var(--cem-layer-shadow, none);
outline: var(--cem-layer-contour, none);
}
--cem-recess-2--cem-recess-1--cem-elevation-0--cem-elevation-1--cem-elevation-2--cem-elevation-3--cem-elevation-4--cem-layer-back--cem-layer-base--cem-layer-work--cem-layer-overlay--cem-layer-command--cem-layer-back-deep → --cem-layer-back + --cem-recess-2--cem-layer-work-floating → --cem-layer-work + --cem-elevation-2Treat as breaking if you:
Treat as minor/patch if you:
This spec is the canonical D4 contract for layering (signed depth).
--cem-elevation-*, --cem-recess-*, and --cem-layer-* as the public CEM contract going forward.| Source table | Section | Description |
|---|---|---|
cem-layering-rungs |
§7.1 | 7 basis rungs as box-shadow recipes (--cem-recess-{2,1}, --cem-elevation-{0..4}) |
cem-layering-semantic |
§8.1 | 5 required semantic endpoints (--cem-layer-{back,base,work,overlay,command}) |
cem-layering-semantic-optional |
§8.2 | 2 optional endpoints (--cem-layer-{back-deep,work-floating}) |
cem-layering-rungs-forced |
§13.2 | Forced-colors rung override values (generator-only; no new tokens) |
Generator derivation rules:
cem-layering-rungs, cem-layering-semantic, cem-layering-semantic-optional → token list (tier in last
column).cem-layering-rungs-forced → override values emitted inside @media (forced-colors: active) :root { … };
no new tokens.--cem-elevation-* and --cem-recess-* MUST NOT be used as z-index values (§2.2).custom-element-dist discussion #14): https://github.com/EPA-WG/custom-element-dist/discussions/14