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.
.chip::after { content: "×"; cursor: pointer; }
.chip::after:hover { background: #dc2626; color: #fff; }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.
.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.
.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.
.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.
.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.
$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.
.plan {
border: 2px solid var(--border);
&:has(input:checked) { border-color: var(--accent); }
&:has(input:focus-visible) { outline: 2px solid var(--accent); }
}:scroll-start and :scroll-end: carousel arrows
Scroll the strip or use the buttons. Each arrow fades out when there is nothing more to see in its direction.
.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.
.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.
.card h3 { font-size: fit(12px, 90px); }
.card p { height: same; }