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

      CodeSOD: A Unique Way to Primary Key

      July 22, 2025

      BrowserStack launches Figma plugin for detecting accessibility issues in design phase

      July 22, 2025

      Parasoft brings agentic AI to service virtualization in latest release

      July 22, 2025

      Node.js vs. Python for Backend: 7 Reasons C-Level Leaders Choose Node.js Talent

      July 21, 2025

      The best CRM software with email marketing in 2025: Expert tested and reviewed

      July 22, 2025

      This multi-port car charger can power 4 gadgets at once – and it’s surprisingly cheap

      July 22, 2025

      I’m a wearables editor and here are the 7 Pixel Watch 4 rumors I’m most curious about

      July 22, 2025

      8 ways I quickly leveled up my Linux skills – and you can too

      July 22, 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 Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025
      Recent

      The Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025

      Zero Trust & Cybersecurity Mesh: Your Org’s Survival Guide

      July 22, 2025

      Execute Ping Commands and Get Back Structured Data in PHP

      July 22, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025
      Recent

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025

      “I don’t think I changed his mind” — NVIDIA CEO comments on H20 AI GPU sales resuming in China following a meeting with President Trump

      July 22, 2025

      Galaxy Z Fold 7 review: Six years later — Samsung finally cracks the foldable code

      July 22, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»Poking at the CSS if() Function a Little More: Conditional Color Theming

    Poking at the CSS if() Function a Little More: Conditional Color Theming

    June 25, 2025

    Chrome 137 shipped the if() CSS function, so it’s totally possible we’ll see other browsers implement it, though it’s tough to know exactly when. Whatever the case, if() enables us to use values conditionally, which we can already do with queries and other functions (e.g., media queries and the light-dark() function), so I’m sure you’re wondering: What exactly does if() do?

    Sunkanmi gave us a nice overview of the function yesterday, poking at the syntax at a high level. I’d like to poke at it a little harder in this article, getting into some possible real-world usage.

    To recap, if() conditionally assigns a value to a property based on the value of a CSS variable. For example, we could assign different values to the color and background properties based on the value of --theme:

    • --theme: "Shamrock"
      • color: ‌hsl(146 50% 3%)
      • background: hsl(146 50% 40%)
    • --theme: Anything else
      • color: hsl(43 74% 3%)
      • background: hsl(43 74% 64%)
    :root {
      /* Change to fall back to the ‘else’ values */
      --theme: "Shamrock";
    
      body {
        color: if(style(--theme: "Shamrock"): hsl(146 50% 3%); else: hsl(43 74% 3%));
        background: if(style(--theme: "Shamrock"): hsl(146 50% 40%); else: hsl(43 74% 64%));
      }
    }
    CodePen Embed Fallback

    I don’t love the syntax (too many colons, brackets, and so on), but we can format it like this (which I think is a bit clearer):

    color: if(
      style(--theme: "Shamrock"): hsl(146 50% 3%);
      else: hsl(43 74% 3%)
    );

    We should be able to do a crazy number of things with if(), and I hope that becomes the case eventually, but I did some testing and learned that the syntax above is the only one that works. We can’t base the condition on the value of an ordinary CSS property (instead of a custom property), HTML attribute (using attr()), or any other value. For now, at least, the condition must be based on the value of a custom property (CSS variable).

    Exploring what we can do with if()

    Judging from that first example, it’s clear that we can use if() for theming (and design systems overall). While we could utilize the light-dark() function for this, what if the themes aren’t strictly light and dark, or what if we want to have more than two themes or light and dark modes for each theme? Well, that’s what if() can be used for.

    First, let’s create more themes/more conditions:

    :root {
      /* Shamrock | Saffron | Amethyst */
      --theme: "Saffron"; /* ...I choose you! */
    
      body {
        color: if(
          style(--theme: "Shamrock"): hsl(146 50% 3%);
          style(--theme: "Saffron"): hsl(43 74% 3%);
          style(--theme: "Amethyst"): hsl(282 47% 3%)
        );
        background: if(
          style(--theme: "Shamrock"): hsl(146 50% 40%);
          style(--theme: "Saffron"): hsl(43 74% 64%);
          style(--theme: "Amethyst"): hsl(282 47% 56%)
        );
        transition: 300ms;
      }
    }

    Pretty simple really, but there are a few easy-to-miss things. Firstly, there’s no “else condition” this time, which means that if the theme isn’t Shamrock, Saffron, or Amethyst, the default browser styles are used. Otherwise, the if() function resolves to the value of the first true statement, which is the Saffron theme in this case. Secondly, transitions work right out of the box; in the demo below, I’ve added a user interface for toggling the --theme, and for the transition, literally just transition: 300ms alongside the if() functions:

    CodePen Embed Fallback

    Note: if theme-swapping is user-controlled, such as selecting an option, you don’t actually need if() at all. You can just use the logic that I’ve used at the beginning of the demo (:root:has(#shamrock:checked) { /* Styles */ }). Amit Sheen has an excellent demonstration over at Smashing Magazine.

    To make the code more maintainable though, we can slide the colors into CSS variables as well, then use them in the if() functions, then slide the if() functions themselves into CSS variables:

    /* Setup */
    :root {
      /* Shamrock | Saffron | Amethyst */
      --theme: "Shamrock"; /* ...I choose you! */
    
      /* Base colors */
      --shamrock: hsl(146 50% 40%);
      --saffron: hsl(43 74% 64%);
      --amethyst: hsl(282 47% 56%);
    
      /* Base colors, but at 3% lightness */
      --shamrock-complementary: hsl(from var(--shamrock) h s 3%);
      --saffron-complementary: hsl(from var(--saffron) h s 3%);
      --amethyst-complementary: hsl(from var(--amethyst) h s 3%);
    
      --background: if(
        style(--theme: "Shamrock"): var(--shamrock);
        style(--theme: "Saffron"): var(--saffron);
        style(--theme: "Amethyst"): var(--amethyst)
      );
    
      --color: if(
        style(--theme: "Shamrock"): var(--shamrock-complementary);
        style(--theme: "Saffron"): var(--saffron-complementary);
        style(--theme: "Amethyst"): var(--amethyst-complementary)
      );
    
      /* Usage */
      body {
        /* One variable, all ifs! */
        background: var(--background);
        color: var(--color);
        accent-color: var(--color);
    
        /* Can’t forget this! */
        transition: 300ms;
      }
    }
    CodePen Embed Fallback

    As well as using CSS variables within the if() function, we can also nest other functions. In the example below, I’ve thrown light-dark() in there, which basically inverts the colors for dark mode:

    --background: if(
      style(--theme: "Shamrock"): light-dark(var(--shamrock), var(--shamrock-complementary));
      style(--theme: "Saffron"): light-dark(var(--saffron), var(--saffron-complementary));
      style(--theme: "Amethyst"): light-dark(var(--amethyst), var(--amethyst-complementary))
    );
    CodePen Embed Fallback

    if() vs. Container style queries

    If you haven’t used container style queries before, they basically check if a container has a certain CSS variable (much like the if() function). Here’s the exact same example/demo but with container style queries instead of the if() function:

    :root {
      /* Shamrock | Saffron | Amethyst */
      --theme: "Shamrock"; /* ...I choose you! */
    
      --shamrock: hsl(146 50% 40%);
      --saffron: hsl(43 74% 64%);
      --amethyst: hsl(282 47% 56%);
    
      --shamrock-complementary: hsl(from var(--shamrock) h s 3%);
      --saffron-complementary: hsl(from var(--saffron) h s 3%);
      --amethyst-complementary: hsl(from var(--amethyst) h s 3%);
    
      body {
        /* Container has chosen Shamrock! */
        @container style(--theme: "Shamrock") {
          --background: light-dark(var(--shamrock), var(--shamrock-complementary));
          --color: light-dark(var(--shamrock-complementary), var(--shamrock));
        }
    
        @container style(--theme: "Saffron") {
          --background: light-dark(var(--saffron), var(--saffron-complementary));
          --color: light-dark(var(--saffron-complementary), var(--saffron));
        }
    
        @container style(--theme: "Amethyst") {
          --background: light-dark(var(--amethyst), var(--amethyst-complementary));
          --color: light-dark(var(--amethyst-complementary), var(--amethyst));
        }
    
        background: var(--background);
        color: var(--color);
        accent-color: var(--color);
        transition: 300ms;
      }
    }
    CodePen Embed Fallback

    As you can see, where if() facilitates conditional values, container style queries facilitate conditional properties and values. Other than that, it really is just a different syntax.

    Additional things you can do with if() (but might not realize)

    Check if a CSS variable exists:

    /* Hide icons if variable isn’t set */
    .icon {
      display: if(
        style(--icon-family): inline-block;
        else: none
      );
    }

    Create more-complex conditional statements:

    h1 {
      font-size: if(
        style(--largerHeadings: true): xxx-large;
        style(--theme: "themeWithLargerHeadings"): xxx-large
      );
    }

    Check if two CSS variables match:

    /* If #s2 has the same background as #s1, add a border */
    #s2 {
      border-top: if(
        style(--s2-background: var(--s1-background)): thin solid red
      );
    }

    if() and calc(): When the math isn’t mathing

    This won’t work (maybe someone can help me pinpoint why):

    div {
      /* 3/3 = 1 */
      --calc: calc(3/3);
      /* Blue, because if() won’t calculate --calc */
      background: if(style(--calc: 1): red; else: blue);
    }

    To make if() calculate --calc, we’ll need to register the CSS variable using @property first, like this:

    @property --calc {
      syntax: "<number>";
      initial-value: 0;
      inherits: false;
    }

    Closing thoughts

    Although I’m not keen on the syntax and how unreadable it can sometimes look (especially if it’s formatted on one line), I’m mega excited to see how if() evolves. I’d love to be able to use it with ordinary properties (e.g., color: if(style(background: white): black; style(background: black): white);) to avoid having to set CSS variables where possible.

    It’d also be awesome if calc() calculations could be calculated on the fly without having to register the variable.

    That being said, I’m still super happy with what if() does currently, and can’t wait to build even simpler design systems.


    Poking at the CSS if() Function a Little More: Conditional Color Theming 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 ArticleIntehill 16″ 3K Touchscreen U16ZT Portable Monitor Review
    Next Article CVE-2025-48954 – Discourse is an open-source discussion platform. V

    Related Posts

    News & Updates

    The best CRM software with email marketing in 2025: Expert tested and reviewed

    July 22, 2025
    News & Updates

    This multi-port car charger can power 4 gadgets at once – and it’s surprisingly cheap

    July 22, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Real-world applications of Amazon Nova Canvas for interior design and product photography

    Machine Learning

    CVE-2025-46802 – PuTTY Screen Session Privilege Escalation Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-42962 – SAP Business Warehouse Cross-Site Scripting (XSS)

    Common Vulnerabilities and Exposures (CVEs)

    Thunderbird-lek laat aanvaller stilletjes Windows-inloggegevens stelen

    Security

    Highlights

    Development

    No Ceasefire in the Cyberspace Between India and Pakistan

    May 14, 2025

    India and Pakistan may have reached a status quo of ceasefire on ground, air and…

    CVE-2025-5268 – Mozilla Firefox Memory Corruption Vulnerability

    May 27, 2025

    Microsoft Edge lets you turn off the Copilot-inspired New Tab Page and built-in Copilot Search for good

    May 13, 2025

    CVE-2025-6032 – Podman TLS Certificate Verification Bypass Vulnerability

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

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