Live examples

Everything on this page is styled by CSS Post Processor, running in your browser. Each demo shows the exact CSS that drives it. Open your developer tools to watch the data-css-* attributes change.

Clickable ::after: chips with a close icon

The × is a pseudo-element, not a button. It turns red only while the pointer is on it, and clicking it removes the chip. Clicking the label does nothing.

CSSJavaScriptPerlHTML

CSS
.chip::after { content: "×"; cursor: pointer; }
.chip::after:hover { background: #dc2626; color: #fff; }
JavaScript
css.on('click', '.chip::after', function () {
  this.remove();
});

$[index]: a color ramp and a staggered entrance

Each square gets its own hue and its own animation delay from a single rule. Add squares and they continue the sequence.

CSS
.ramp > span {
  background: hsl(calc($[index] * 30) 85% 60%);
  animation: pop .5s both;
  animation-delay: calc($[index] * 70ms);
}

:seen and :stuck: reveal on scroll, pinned header

Scroll inside the box. Tiles slide in once 60% of each is visible, and the header changes color only while it is stuck.

Sticky header
Tile 1
Tile 2
Tile 3
Tile 4
Tile 5
Tile 6
Tile 7
Tile 8
CSS
.tile { transition: opacity .6s, translate .6s; }
.tile:not(:seen(60%)) { opacity: 0; translate: -2rem 0; }

.bar { position: sticky; top: 0; }
.bar:stuck { background: var(--accent); color: var(--accent-ink); }

:overflowing: only when text is really cut off

Drag the box's bottom-right corner to resize it. The warning appears only while the title is truncated.

CSS Post Processor adds the selectors native CSS still lacks
Title is truncated
CSS
.title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.flag { display: none; }
.box:has(.title:overflowing) .flag { display: block; }

:contains() and [data-stock<5]: styling from content

Change the stock. Below 5 a warning appears, and at 0 the badge says "Sold out" and the row dims. No styling code in the JavaScript: it only updates the number and the text.

Ballet shoes Low stockIn stock: 6
Leotard Low stockIn stock: 2
CSS
.item:has(.badge:contains("sold out" i)) { opacity: .45; }
.low { display: none; }
.item:has([data-stock<5]):not(:has([data-stock<1])) .low { display: inline; }

Auto-updating variables

A variable whose name ends in ! is recalculated when the window resizes. Resize this window to see it change.

CSS
$vw!{css.vars.w()}
.vw::after { content: "This window is $[vw!]px wide"; }

Nesting with native :has()

Nested rules with & work with native selectors too. Pick a plan.

CSS
.plan {
  border: 2px solid var(--border);
  &:has(input:checked) { border-color: var(--accent); }
  &:has(input:focus-visible) { outline: 2px solid var(--accent); }
}

Scroll the strip or use the buttons. Each arrow fades out when there is nothing more to see in its direction.

CSS
.carousel:has(.track:scroll-start) .prev,
.carousel:has(.track:scroll-end) .next {
  opacity: .3;
  pointer-events: none;
}

:filled: floating labels without tricks

Type in the field. The label moves up while the field has a value or focus. No placeholder hack, no script.

CSS
.float span { position: absolute; top: 1rem; transition: translate .2s; }
.float:has(input:filled, input:focus) span {
  translate: 0 -.65rem;
  font-size: .75rem;
}

font-size: fit() and height: same

Each headline fills its card, and both paragraphs take the height of the taller one. Resize the window to see them recalculate.

Wide card

Short text.

Narrow

This one is longer, so it sets the height for both.

CSS
.card h3 { font-size: fit(12px, 90px); }
.card p  { height: same; }

Read the docs Recipes Download