
Fluid Type, OddContrast, and Custom CSS Functions
Here’s what we’re up to:
- Revisiting Fluid Type on Winging It with Richard Rutter | March 20, 2025
- New features for OddContrast
- CSS Layout Workshop coming in April 2025
- Custom CSS Functions in the Browser article by Miriam Suzanne
Upcoming Winging It LIVE
Copy permalink to “Upcoming Winging It LIVE”Revisiting Fluid Type with Stacy Kvernmo, Miriam Suzanne, and guest Richard Rutter on March 20, 2025.
New Features for OddContrast
Copy permalink to “New Features for OddContrast”If you haven’t checked it out, OddContrast is OddBird’s color format converter, with newer color formats like Oklch, Oklab, and the Display P3 color space. It’s also a color contrast checker to help designers meet WCAG 2 accessibility standards.
- Swap background and foreground colors. Either drag-and-drop or use the button located between the two colors.
- A new Show Gamut dropdown menu allows displaying color gamut ranges on the color sliders. And we’ve made it more obvious when a color is outside the specified gamut.
- Contrast ratios now incorporate foreground color alpha values. Ratios displayed are an estimation of contrast when the foreground color is not opaque.
Miriam will be teaching a workshop about building more resilient and maintainable web layouts using modern CSS.
Watch for special editions of OddNews this month with free lessons and early bird tickets.
Custom CSS Functions in the Browser
Copy permalink to “Custom CSS Functions in the Browser”There’s been a lot of progress in the CSS Working Group lately, but I want to draw your attention to a prototype that landed in Chromium ‘Canary’ (v136+) browsers with the experimental platform features flag enabled. Author-defined Functions are coming to CSS, and you can start to experiment with them now!
Back in 2009 I was using Natalie Downe’s responsive layout technique. This was
before media queries, or Responsive Web Design™, or calc()
, or modern
layout methods like flexbox and grid. The process involved a lot of math. It
wasn’t complicated math – a single division problem – but it was repeated for
every element in the layout. At its simplest (not accounting for gutters), if we
want to span 3 out of 10 columns using percentages, we need to divide those
numbers and multiply by 100%. Tired of doing that over and over, then
copy-pasting the results into my CSS, I installed Sass.
Soon, we’ll be able to solve these problems directly in CSS, without any third-party tools or preprocessing. Writing our own functions will allow us to take some repetitive bit of logic, give it a meaningful name, and reuse it anywhere we need. The simplest possible CSS function is something like this:
/* define the function */
@function --always-blue() { result: blue; }
button {
/* call the function */
background: --always-blue();
}
That’s not the most useful function (unless you need a longer way to write
blue
) but it demonstrates the syntax. Like custom properties, a function name
has to start with two dashes. But there are also a few differences:
- The function isn’t defined on elements (like
:root
) but exists globally - The function is called directly, without wrapping it in
var()
To make it more useful, let’s add some logic. I think one of the most exciting things we can do is return conditional results that would otherwise require nested at-rules:
@function --media-scheme() {
result: light;
@media (prefers-color-scheme: dark) { result: dark; }
}
:root {
--color-scheme: --media-scheme();
}
Notice that we have two result
descriptors, but we will still get a single
result from the function. In many languages, like JavaScript, we might expect to
get the first valid result every time – but this is CSS, where the last valid
result takes precedence. If the user has a dark-mode preference set, this
function will return dark
– otherwise it will return the default light
scheme value.
We can also add call-time parameters that act like local custom properties, only available inside the function:
@function --transparent(--color, --alpha) {
result: oklch(from var(--color) l c h / var(--alpha);
}
We can define --color
and --alpha
each time the function is called, and
those values will get slotted into a ‘relative color syntax’ to change the alpha
opacity of our color:
button {
background: --transparent(blue, 0.5); /* blue at half opacity */
}
We can also provide a default value for a parameter, if we want to make it
optional. Let’s choose a default --alpha
that is still mostly-opaque, but a
little bit see-through:
@function --transparent(--color, --alpha: 0.8) {
result: oklch(from var(--color) l c h / var(--alpha);
}
dialog {
background: --transparent(black); /* black at default 0.8 opacity */
}
Ideally we’re able to solve two problems when we create these functions: one is making our code less repetitive, but the other is making it more meaningful. In this case we can avoid writing the full relative color syntax when we only want to change the opacity of a color. The result is a syntax that’s more targeted to our goals, and highlights the most important information.
There’s a lot more we can do with CSS functions, and Bramus has a couple articles that go into more detail. I’ve also been playing in CodePen with more color-manipulation and fluid-type functions.
What functions would be most useful to you? Let us know what you come up with on Mastodon or BlueSky, we’d love to see your demos.
For years, OddBird has been contributing to open web tools & standards, with a focus on CSS and related platform features at the W3C. But that work takes resources, making it hard for independent contributors like us to stay involved.
If you appreciate what we’re doing, you (or your company) can sponsor our work directly or hire us to develop something you need.
- Sponsor us. We display sponsor logos and avatars on our website.
- Hire us to develop the Anchor Positioning polyfill or a language/tool you rely on.