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.