postcss-preset-env

PostCSS Mixins And PostCSS Custom Functions

We are happy to announce the release of @csstools/postcss-mixins and @csstools/postcss-custom-functions.

If you are using postcss-preset-env you will already have this plugin when using the latest version. Otherwise now is a great time to upgrade 🎉

@function

Custom functions work at the value level and allow you to abstract complex bits of logic into a shared function.

For example, in a columns system you sometimes still need to compute the size of a number of columns:

@function --columns-size(--span <integer>: 1, --columns <integer>: 1, --container-size <length>: 100px, --gutter-size <length>: 0px) {
	result: calc(((var(--container-size) - (var(--gutter-size) * (var(--columns) - 1))) / var(--columns) * var(--span)) + (var(--gutter-size) * (var(--span) - 1)));
}

.foo {
	width: --columns-size(5, 12, calc(100vw - 40px), 8px);
}

Typed arguments and a typed return can't be fully transpiled by a build tool. But we think there is still enough here to make a PostCSS plugin.

Try it out in the playground.

Another example is a gamut-mapped version of oklch() with the ray tracing algorithm:

@function --oklch-in-srgb-gamut(--l <number>: 0, --c <number>: 0, --h <number>: 0) {
	--angle: calc(var(--h) * 1deg);
	--ca: cos(var(--angle));
	--sa: sin(var(--angle));
	--oka: calc(var(--c) * var(--ca));
	--okb: calc(var(--c) * var(--sa));
	--lr0: calc(var(--l) + 0.3963377773761749 * var(--oka) + 0.2158037573099136 * var(--okb));
	--mr0: calc(var(--l) - 0.1055613458156586 * var(--oka) - 0.0638541728258133 * var(--okb));
	--sr0: calc(var(--l) - 0.0894841775298119 * var(--oka) - 1.2914855480194092 * var(--okb));
	--or: calc(4.076741636 * pow(var(--lr0),3) + -3.307711539 * pow(var(--mr0),3) + 0.2309699032 * pow(var(--sr0),3));
	--og: calc(-1.268437973 * pow(var(--lr0),3) + 2.609757349 * pow(var(--mr0),3) + -0.341319376 * pow(var(--sr0),3));
	--ob: calc(-0.004196076139 * pow(var(--lr0),3) + -0.7034186179 * pow(var(--mr0),3) + 1.707614694 * pow(var(--sr0),3));
	--inr: clamp(0, sign(var(--or)) + sign(1 - var(--or)) - 1, 1);
	--ing: clamp(0, sign(var(--og)) + sign(1 - var(--og)) - 1, 1);
	--inb: clamp(0, sign(var(--ob)) + sign(1 - var(--ob)) - 1, 1);
	--mask: calc(var(--inr) * var(--ing) * var(--inb));
	--low: clamp(0, sign(0.000001 - var(--l)), 1);
	--high: clamp(0, sign(var(--l) - 0.999999), 1);
	--anchor: pow(var(--l),3);
	--origin: oklch(var(--l) var(--c) var(--h));
	--p0: color(from var(--origin) srgb-linear calc(var(--anchor) + (r - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (g - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (b - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))));
	--k1: oklch(from var(--p0) var(--l) c var(--h));
	--p1: color(from var(--k1) srgb-linear calc(var(--anchor) + (r - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (g - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (b - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))));
	--k2: oklch(from var(--p1) var(--l) c var(--h));
	--p2: color(from var(--k2) srgb-linear calc(var(--anchor) + (r - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (g - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (b - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))));
	--k3: oklch(from var(--p2) var(--l) c var(--h));
	--p3: color(from var(--k3) srgb-linear calc(var(--anchor) + (r - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (g - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))) calc(var(--anchor) + (b - var(--anchor)) * min((max(0, sign(r - var(--anchor))) - var(--anchor)) / (r - var(--anchor) + 0.000000000001),(max(0, sign(g - var(--anchor))) - var(--anchor)) / (g - var(--anchor) + 0.000000000001),(max(0, sign(b - var(--anchor))) - var(--anchor)) / (b - var(--anchor) + 0.000000000001))));
	result: oklch(from var(--p3) clamp(0, var(--l), 1) calc((c * (1 - var(--mask)) + var(--c) * var(--mask)) * (1 - var(--high)) * (1 - var(--low))) var(--h));
}

.example {
	outline: 2px solid red;
	width: 100px;
	height: 100px;
	background-color: oklch(0.99 0.99 0);
}

.example-mapped {
	outline: 2px solid red;
	width: 100px;
	height: 100px;
	background-color: --oklch-in-srgb-gamut(0.99, 0.99, 0);
}

See it in action here, and with the transpiled code in the playground.

@mixin

Mixins make larger chunks of CSS reusable.
We like to use mixins for typography:

card.html

<div class="card">
	<div class="card__title">
		Hello!
	</div>
</div>

typography.css

@mixin --type-a {
	font-family: monospace;
	font-size: 2rem;
	font-weight: 500;
}

card.css

.card {
	padding: 20px;
	background-color: #ffd7f8;
}

.card__title {
	color: #410633;

	@apply --type-a;
}

Try it out in the playground.