Get Started

Cards · Borders · Dividers · Shadows

The card is 100% token-driven

Every property on .card reads a --card-* variable with an ACSS fallback — background, padding, border width, border colour, radius, gap, overflow, shadow, text colour, heading colour, icon colour, media aspect-ratio and object-fit. You never write a card declaration. You re-point a token. Every chip on this page is therefore nothing but custom-property assignments, and every one has zero literal values.

Verdict on tiles: retire them

.tile existed because the ACSS 3 Card Framework forced uniform padding, so an edge-to-edge image needed its own component — seven chips: .tile, .tile__media, .tile__body, .tile__title, .tile__text, .tile--horizontal, .tile__number.

ACSS 4 ships the media convention natively. Any descendant of .card whose class contains __media gets aspect-ratio, object-fit: cover, overflow: clip and inline-size: 100% for free, driven by --card-media-aspect-ratio, --card-media-object-fit and --card-media-radius. The only thing left is pulling the media out to the card edge, and that is one modifier whose value is the card padding itself.

7 chips → 1 modifier. .tile can go.

Cards

The native card, untouched

No modifier, no chip. This is .card plus a figure whose class contains __media. The 16:9 crop, the cover fit, the clipped corners, the heading colour, the gap and the button treatment are all framework defaults.

Native card

Nothing but .card and .card__media. The media is inset by --card-padding.

Read more

Native card, no media

A card is not required to have media. The gap between children is --card-gap.

Read more

Native card

The framework also takes over any button inside the card.

Read more

Tiles

Inset media vs edge-to-edge

Left is the native card. The others add .card__media--flush, whose whole body is margin: calc(var(--card-padding) * -1) with the block-end reset. That single modifier is the entire tile system.

Inset media

The framework default — media sits inside --card-padding.

View

Edge-to-edge media

.card__media--flush — the old .tile in one modifier. No shadow and no border: the image supplies its own edge, and the card’s overflow: clip rounds the top corners. This is how an image-led tile is normally treated.

View

Flush + outlined

The same modifier with an outline instead of elevation.

View

.card--bare

No surface at all — this is what replaced .tile. The media reaches the edge because there is no padding to escape, not because a modifier pulls it out.

Combinations

The four worth keeping

Not every permutation — the ones that get used. Border and shadow are alternatives, not partners: an outline says structural, a shadow says elevated, and doing both at once is the most common way a card starts to look cheap.

1 · Flat

The only card here carrying a modifier. .card–flat sets the border colour to transparent — because the Cards panel already sets that variable at :root, so on this template the default card is OUTLINED, and flat is the thing you have to ask for.

2 · Outlined — the default

--card-border-color: var(--border-color-dark). Structural. Reads as a frame, works on any background, survives being printed.

3 · Raised

--card-shadow: var(--box-shadow-1), plus a WHITE surface and no border. Elevation means closer to the light, so the surface must be lighter than what it sits on. The Cards default is –neutral-ultra-light at luminance 0.888 against a 1.0 page — that reads as recessed, and a grey shadow around a grey box is just a fuzzy mass. White surface; the shadow defines the edge.

4 · Tile

Flush media with a hairline outline. An ambient shadow under a full-bleed image reads as a halo, because this template’s shadow scale has no offset — see the Shadows section. An outline is the honest treatment for a tile.

Borders & dividers

Two token systems, not one

A border frames a component. A divider separates peer items. ACSS ships both as complete shorthands — --border and --divider — each composed from its own size, style and colour settings in Borders & Dividers. Re-point the composed token, never its ingredients.

Border

The frame here is --card-border-color reading --border-color-dark. Width and style come from --border-width and --border-style.

--border = --border-size --border-style --border-color-dark

Divider, full width

Above the rule.


Below it. Spacing is --divider-gap; the line itself is --divider.

hr.wp-block-separator

Divider, narrow

Above the rule.


Narrowed with the ACSS width utility, not a custom class. This is the correction to the divider--20 that never existed on any site.

hr.wp-block-separator.width--20

Shadows

Three steps, and a warning

ACSS 4 ships --box-shadow-1, -2 and -3 — not the v3 -m/-l/-xl names, which resolve to nothing and silently produce box-shadow: none. On a card you never write box-shadow: you set --card-shadow, because .card already reads it.

--box-shadow-1

The default lift. Subtle enough for a grid of many cards. All three raised steps also set the surface to white — that is what makes a shadow read as an edge instead of a haze.

--box-shadow-2

One step up. For a single featured card, not a whole grid.

--card-shadow: var(--box-shadow-2)

--box-shadow-3

Rarely right on a card. Here so you can see where the scale ends.

--card-shadow: var(--box-shadow-3)

.bg--dark

Cards on a dark band

Light card, raised

The default card is a LIGHT island, and on a dark band that is usually correct. The shadow is what separates it.

card--dark

Points --card-background, --card-text-color, --card-heading-color and --card-icon-color at the Ultra Dark colour assignment — not at raw palette shades. Re-theme that relationship in the dashboard and these cards follow.

card--dark + flush

Its border is --border-color-light, the contextual half of the border pair. --border itself is not contextual, so the light half has to be chosen deliberately.

.card--bare

Same class, no colour named in the markup — but the modifier re-points –card-text-color and –card-heading-color inside .bg–dark. Without that, .card paints its own dark text and this measures 1.00:1.

The buttons above are repainted by the BAND, not by the card.

.bg--ultra-dark

Cards on an ultra-dark band

Light card, raised

The default card is a LIGHT island, and on a dark band that is usually correct. The shadow is what separates it.

card--dark

Points --card-background, --card-text-color, --card-heading-color and --card-icon-color at the Ultra Dark colour assignment — not at raw palette shades. Re-theme that relationship in the dashboard and these cards follow.

card--dark + flush

Its border is --border-color-light, the contextual half of the border pair. --border itself is not contextual, so the light half has to be chosen deliberately.

.card--bare

The same modifier on ultra-dark, unchanged. One contextual re-point covers both bands, so nothing here is band-specific.

The buttons above are repainted by the BAND, not by the card.

Audit

Six chips, zero rogue numbers

Everything on this page that ACSS 4 does not ship is listed below. Each chip body contains only custom-property assignments or keywords — no px, no rem, no percentage, no hex, no chosen number of any kind.

  • .demo-grid — grid-template-columns: var(--grid-auto-3); gap: var(--grid-gap). --grid-auto-3 is a repeat(auto-fit, minmax(…)) token, so the grid reflows with no media query and no breakpoint number anywhere.
  • .card--raised--card-shadow: var(--box-shadow-1); --card-border-color: transparent.
  • .card--outlined--card-border-color: var(--border-color-dark); --card-shadow: none.
  • .card--dark — five token re-points, all aimed at the Ultra Dark colour assignment.
  • .card__media--flush — margin: calc(var(--card-padding) * -1); margin-block-end: 0. The one place a value is computed rather than referenced, and it is computed FROM a token.
  • .card__media — deliberately empty. ACSS matches it via .card :where([class*="__media"]); the chip exists only so the class is backed by an id.

Two corrections this page forced

ACSS 4 has no grid CLASSES, but it ships 30 grid VARIABLES including --grid-auto-2 through --grid-auto-12. The reference records the absence of the classes as though it meant no grid support. It does not.

.card is not light-only. ACSS ships .card:where([class*="--dark"]) as an explicit extension point, and every colour on the card is a token. A dark card is five re-points, not a rebuild.