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

      The Power Of The Intl API: A Definitive Guide To Browser-Native Internationalization

      August 8, 2025

      This week in AI dev tools: GPT-5, Claude Opus 4.1, and more (August 8, 2025)

      August 8, 2025

      Elastic simplifies log analytics for SREs and developers with launch of Log Essentials

      August 7, 2025

      OpenAI launches GPT-5

      August 7, 2025

      I compared the best headphones from Apple, Sony, Bose, and Sonos: Here’s how the AirPods Max wins

      August 10, 2025

      I changed these 6 settings on my iPad to significantly improve its battery life

      August 10, 2025

      DistroWatch Weekly, Issue 1134

      August 10, 2025

      3 portable power stations I travel everywhere with (and how they differ)

      August 9, 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

      Next.js PWA offline capability with Service Worker, no extra package

      August 10, 2025
      Recent

      Next.js PWA offline capability with Service Worker, no extra package

      August 10, 2025

      spatie/laravel-flare

      August 9, 2025

      Establishing Consistent Data Foundations with Laravel’s Database Population System

      August 8, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Windows 11 Copilot gets free access to GPT-5 Thinking, reduced rate limits than ChatGPT Free

      August 10, 2025
      Recent

      Windows 11 Copilot gets free access to GPT-5 Thinking, reduced rate limits than ChatGPT Free

      August 10, 2025

      Best Architecture AI Rendering Platform: 6 Tools Tested

      August 10, 2025

      Microsoft won’t kill off Chromium Edge and PWAs on Windows 10 until October 2028

      August 10, 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

    I compared the best headphones from Apple, Sony, Bose, and Sonos: Here’s how the AirPods Max wins

    August 10, 2025
    News & Updates

    I changed these 6 settings on my iPad to significantly improve its battery life

    August 10, 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

    Are Amazon Basics tools any good? I bought a bunch to find out, and you’d be surprised

    News & Updates

    CVE-2025-49162 – Arris VIP1113 TFTP File Overwrite Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    KelpUI

    News & Updates

    CVE-2025-6332 – PHPGurukul Directory Management System SQL Injection

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    Distribution Release: Proxmox 8.4 “Virtual Environment”

    April 9, 2025

    The DistroWatch news feed is brought to you by TUXEDO COMPUTERS. Proxmox is a commercial company offering specialised products based on Debian, notably Proxmox Virtual Environment and Proxmox Mail Gateway. The company has announced its release of Proxmox 8.4 “Virtual Environment” which introduces new hardware support, an API for third-party backups, and Virtiofs passthrough. “We are excited to announce….

    I replaced my premium headphones with this classic Bose pair – and didn’t regret it

    June 13, 2025

    Windows 11 now lets you extract texts (OCR) from your screen without screenshots

    April 15, 2025

    CVE-2025-8330 – Code-projects Vehicle Management SQL Injection

    July 30, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

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