Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 16, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 16, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 16, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 16, 2025

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025

      Minecraft licensing robbed us of this controversial NFL schedule release video

      May 16, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The power of generators

      May 16, 2025
      Recent

      The power of generators

      May 16, 2025

      Simplify Factory Associations with Laravel’s UseFactory Attribute

      May 16, 2025

      This Week in Laravel: React Native, PhpStorm Junie, and more

      May 16, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025
      Recent

      Microsoft has closed its “Experience Center” store in Sydney, Australia — as it ramps up a continued digital growth campaign

      May 16, 2025

      Bing Search APIs to be “decommissioned completely” as Microsoft urges developers to use its Azure agentic AI alternative

      May 16, 2025

      Microsoft might kill the Surface Laptop Studio as production is quietly halted

      May 16, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»CSS Functions and Mixins Module Notes

    CSS Functions and Mixins Module Notes

    July 31, 2024

    Most days, I’m writing vanilla CSS. Thanks to CSS variables and nesting, I have fewer reasons to reach for Sass or any other preprocessor. The times I reach for Sass tend to be when I need a @mixin to loop through a list of items or help keep common styles DRY.

    That could change for me in the not-so-distant future since a new CSS Functions and Mixins Module draft was published in late June after the CSSWG resolved to adopt the proposal back in February.

    Notice the module’s name: Functions and Mixins. There’s a distinction between the two.

    This is all new and incredibly unbaked at the moment with plenty of TODO notes in the draft and points to consider in future drafts. The draft spec doesn’t even have a definition for mixins yet. It’ll likely be some time before we get something real to work and experiment with, but I like trying to wrap my mind around these sorts of things while they’re still in early days, knowing things are bound to change.

    In addition to the early draft spec, Miriam Suzanne published a thorough explainer that helps plug some of the information gaps. Miriam’s an editor on the spec, so I find anything she writes about this to be useful context.

    There’s a lot to read! Here are my key takeaways…

    Custom functions are advanced custom properties

    We’re not talking about the single-purpose, built-in functions we’ve come to love in recent years — e.g., calc(), min(), max(), etc. Instead, we’re talking about custom functions defined with an @function at-rule that contains logic for returning an expected value.

    That makes custom functions a lot like a custom property. A custom property is merely a placeholder for some expected value that we usually define up front:

    :root {
    –primary-color: hsl(25 100% 50%);
    }

    Custom functions look pretty similar, only they’re defined with @function and take parameters. This is the syntax currently in the draft spec:

    @function <function-name> [( <parameter-list> )]? {
    <function-rules>

    result: <result>;
    }

    The result is what the ultimate value of the custom function evaluates to. It’s a little confusing to me at the moment, but how I’m processing this is that a custom function returns a custom property. Here’s an example straight from the spec draft (slightly modified) that calculates the area of a circle:

    @function –circle-area(–r) {
    –r2: var(–r) * var(–r);

    result: calc(pi * var(–r2));
    }

    Calling the function is sort of like declaring a custom property, only without var() and with arguments for the defined parameters:

    .elenent {
    inline-size: –circle-area(–r, 1.5rem); /* = ~7.065rem */
    }

    Seems like we could achieve the same thing as a custom property with current CSS features:

    :root {
    –r: 1rem;
    –r2: var(–r) * var(–r);
    –circle-area: calc(pi * var(–r2));
    }

    .element {
    inline-size: var(–circle-area, 1.5rem);
    }

    That said, the reasons we’d reach for a custom function over a custom property are that (1) they can return one of multiple values in a single stroke, and (2) they support conditional rules, such as @supports and @media to determine which value to return. Check out Miriam’s example of a custom function that returns one of multiple values based on the inline size of the viewport.

    /* Function name */
    @function –sizes(
    /* Array of possible values */
    –s type(length),
    –m type(length),
    –l type(length),
    /* The returned value with a default */
    ) returns type(length) {
    –min: 16px;

    /* Conditional rules */
    @media (inline-size < 20em) {
    result: max(var(–min), var(–s, 1em));
    }
    @media (20em < inline-size < 50em) {
    result: max(var(–min), var(–m, 1em + 0.5vw));
    }
    @media (50em < inline-size) {
    result: max(var(–min), var(–l, 1.2em + 1vw));
    }
    }

    Miriam goes on to explain how a comma-separated list of parameters like this requires additional CSSWG work because it could be mistaken as a compound selector.

    Mixins help maintain DRY, reusable style blocks

    Mixins feel more familiar to me than custom functions. Years of writing Sass mixins will do that to you, and indeed, is perhaps the primary reason I still reach for Sass every now and then.

    Mixins sorta look like the new custom functions. Instead of @function we’re working with @mixin which is exactly how it works in Sass.

    /* Custom function */
    @function <function-name> [( <parameter-list> )]? {
    <function-rules>
    result: <result>;
    }

    /* CSS/Sass mixin */
    @mixin <mixin-name> [( <parameter-list> )]? {
    <mixin-rules>
    }

    So, custom functions and mixins are fairly similar but they’re certainly different:

    Functions are defined with @function; mixins are defined with @mixin but are both named with a dashed ident (e.g. –name).

    Functions result in a value; mixins result in style rules.

    This makes mixins ideal for abstracting styles that you might use as utility classes, say a class for hidden text that is read by screenreaders:

    .sr-text {
    position: absolute;
    left: -10000px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    }

    In true utility fashion, we can sprinkle this class on elements in the HTML to hide the text.

    <a class=”sr-text”>Skip to main content</a>

    Super handy! But as any Tailwind-hater will tell you, this can lead to ugly markup that’s difficult to interpret if we rely on many utility classes. Screereader text isn’t in too much danger of that, but a quick example from the Tailwind docs should illustrate that point:

    <div class=”origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg”>

    It’s a matter of preference, really. But back to mixins! The deal is that we can use utility classes almost as little CSS snippets to build out other style rules and maintain a clearer separation between markup and styles. If we take the same .sr-text styles from before and mixin-erize them (yep, I’m coining this):

    @mixin –sr-text {
    position: absolute;
    left: -10000px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    }

    Instead of jumping into HTML to apply the styles, we can embed them in other CSS style rules with a new @apply at-rule:

    header a:first-child {
    @apply –sr-text;

    /* Results in: */
    position: absolute;
    left: -10000px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    }

    Perhaps a better example is something every project seems to need: centering something!

    @mixin –center-me {
    display: grid;
    place-items: center;
    }

    This can now be part of a bigger ruleset:

    header {
    @apply –center-me;
    /*
    display: grid;
    place-items: center;
    */

    background-color: –c-blue-50;
    color: –c-white;
    /* etc. */
    }

    That’s different from Sass which uses @include to call the mixin instead of @apply. We can even return larger blocks of styles, such as styles for an element’s ::before and ::after pseudos:

    @mixin –center-me {
    display: grid;
    place-items: center;
    position: relative;

    &::after {
    background-color: hsl(25 100% 50% / .25);
    content: “”;
    height: 100%;
    position: absolute;
    width: 100%;
    }
    }

    And, of course, we saw that mixins accept argument parameters just like custom functions. You might use arguments if you want to loosen up the styles for variations, such as defining consistent gradients with different colors:

    @mixin –gradient-linear(–color-1, –color-2, –angle) {
    /* etc. */
    }

    We’re able to specify the syntax for each parameter as a form of type checking:

    @mixin –gradient-linear(
    –color-1 type(color),
    –color-2 type(color),
    –angle type(angle),
    ) {
    /* etc. */
    }

    We can abstract those variables further and set default values on them:

    @mixin –gradient-linear(
    –color-1 type(color),
    –color-2 type(color),
    –angle type(angle),
    ) {
    –from: var(–color-1, orangered);
    –to: var(–from-color, goldenrod);
    –angle: var(–at-angle, to bottom right);

    /* etc. */
    }

    …then we write the mixin’s style rules with the parameters as variable placeholders.

    @mixin –gradient-linear(
    –color-1 type(color),
    –color-2 type(color),
    –angle type(angle),
    ) {
    –from: var(–color-1, orangered);
    –to: var(–from-color, goldenrod);
    –angle: var(–at-angle, to bottom right);

    background: linear-gradient(var(–angle), var(–from), var(–to));
    }

    Sprinkle conditional logic in there if you’d like:

    @mixin –gradient-linear(
    –color-1 type(color),
    –color-2 type(color),
    –angle type(angle),
    ) {
    –from: var(–color-1, orangered);
    –to: var(–from-color, goldenrod);
    –angle: var(–at-angle, to bottom right);

    background: linear-gradient(var(–angle), var(–from), var(–to));

    @media (prefers-contrast: more) {
    background: color-mix(var(–from), black);
    color: white;
    }
    }

    This is all set to @apply the mixin in any rulesets we want:

    header {
    @apply –gradient-linear;
    /* etc. */
    }

    .some-class {
    @apply –gradient-linear;
    /* etc. */
    }

    …and combine them with other mixins:

    header {
    @apply –gradient-linear;
    @apply –center-me;
    /* etc. */
    }

    This is all very high level. Miriam gets into the nuances of things like:

    Applying mixins at the root level (i.e., not in a selector)

    Working with Container Queries with the limitation of having to set global custom properties on another element than the one that is queried.

    The possibility of conditionally setting mixin parameters with something like @when/@else in the mixin. (Which makes me wonder about the newly-proposed if() function and whether it would be used in place of @when.)

    Why we might draw a line at supporting loops the same way Sass does. (CSS is a declarative language and loops are imperative flows.)

    Scoping mixins (@layer? scope? Something else?)

    Miriam has an excellent outline of the open questions and discussions happening around mixins.

    That’s, um, it… at least for now.

    Gah, this is a lot for my blonde brain! Anytime I’m neck-deep in CSS specification drafts, I have to remind myself that the dust is still settling. The spec authors and editors are wrestling with a lot of the same questions we have — and more! — so it’s not like a cursory read of the drafts is going to make experts out of anyone. And that’s before we get to the fact that things can, and likely will, change by the time it all becomes a recommended feature for browsers to implement.

    This will be an interesting space to watch, which is something you can do with the following resources:

    Proposal: Custom CSS Functions & Mixins (GitHub Issue #9350)

    CSS Mixins & Functions Explainer (Miriam Suzanne)

    Layered Toggles: Optional CSS Mixins (Roman Komarov)

    All GitHub issues tagged css-mixins

    CSS Functions and Mixins Module Notes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleThe 6 Best Microsoft Excel Courses Worth Taking in 2024
    Next Article This AI Paper from Apple Introduces the Foundation Language Models that Power Apple Intelligence Features: AFM-on-Device and AFM-Server

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 17, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-40906 – MongoDB BSON Serialization BSON::XS Multiple Vulnerabilities

    May 17, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    Archman Linux – Arch-based distribution

    Development

    PHP 8.4.0 Beta 3 now available for testing

    Development

    Composite Components in AEM SPA (React)

    Development

    AI Porn red

    Web Development

    Highlights

    You can get Microsoft 365’s Office desktop apps for free on Windows 11 by changing region

    February 25, 2025

    A simple “hack” gives you free access to Microsoft 365’s Office desktop apps on Windows…

    Like human brains, large language models reason about diverse data in a general way

    February 19, 2025

    How to fetch username and password from excel one by one to test login functionality in robot framework-selenium-python

    July 12, 2024

    Lemosnight

    June 24, 2024
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.