HTML Academy
  • HTML Academy
  • Courses
  • Tutorials
  • Blog
  • Courses
  • Tutorials
  • Blog
  • Sign up
  • Log in
  • Home
  • Blog

Comparing CSS Variables in Pure CSS

Oct 25, 2025Alexander Pershin

We’re standing at the edge of a new, curious world — a world where you can define display logic right inside CSS. What used to require JavaScript yesterday now works natively, at the level of CSS itself.

Why it matters

Modern interfaces are becoming increasingly reactive. A weather card might change its background depending on temperature. A chart could highlight segments based on live data. A form component might visually warn you when a limit is exceeded.

And all of this is logic we usually push to JavaScript:

if (temp < 10) {
  element.classList.add('cold');
} else if (temp < 25) {
  element.classList.add('mild');
} else {
  element.classList.add('warm');
}

But if you think about it — this is just a condition that affects visual appearance. So why not let CSS itself handle it?

Imagine a component that receives variables like --temp, --limit, or --progress, and decides how to look — all on its own, without a single line of JS.

Can CSS variables be compared? Yes, they can!

Surprisingly — yes. And not just compared statically, but dynamically, in response to user interaction. Here’s a small example.

Important: right now it works only in Chrome.

Hover me in Chrome

In this snippet, the block reacts to two CSS variables, --x and --y. When you hover over it, the values change — and so does its appearance.

.comparison {
  --x: 100px;
  --y: 120px;
}
.comparison:hover {
  --x: 140px;
  --y: 120px;
}

On hover, the background updates instantly — with no JavaScript involved. This isn’t a trick. It’s real value comparison happening directly in CSS.

A full walkthrough of the technique is available in the step-by-step interactive demo — make sure to check it out after reading the article.

Why a special trick is needed

So, why don’t developers use CSS comparisons everywhere? It’s not even about browser support — it’s about the limitations of the core technology.

The key player here is container style queries. They let you write things like:

@container style(--theme: dark) {
  ...
}

But here’s the catch — these queries can only check for exact matches. They can tell if a variable equals a certain value, but that’s it. No >, <, or expressions like --temp > --max-temp — not yet.

So if you want true comparisons, you need a little creativity.

How the trick works: three possible outcomes

If you look closer, the limitation isn’t fatal. Style queries can only check equality, but a numerical comparison always has just three possible results:

  1. less than,
  2. equal,
  3. greater than.

Can we map all possible outcomes to just these three? Absolutely!

The key operation is ridiculously simple — subtraction. If you subtract one value from another, the result will always be:

  • negative — if the first value is smaller,
  • zero — if they’re equal,
  • positive — if the first value is larger.

We don’t really care about the exact number — only its sign. That sign tells us which side is bigger.

And this is exactly what the new sign() function does. It returns -1, 0, or 1.

So we end up with a neat, universal expression:

--sign: sign(var(--x) - var(--y));

Now the variable --sign holds everything CSS needs to know about the comparison:

  • -1 if --x is less than --y,
  • 0 if they’re equal,
  • 1 if --x is greater than --y.

Three outcomes — three states. That’s all we need to build conditional logic right in CSS.

From here on, we can use this value anywhere — inside an if() function or an @container query.

Step-by-step implementation

Step 1. Define the variables

.comparison:nth-child(1) { --x: 100px; --y: 120px; }
.comparison:nth-child(2) { --x: 100px; --y: 100px; }
.comparison:nth-child(3) { --x: 200px; --y: 100px; }

Step 2. Register the variable --sign

Registration ensures the browser treats --sign as a number and evaluates it right away.

@property --sign {
  inherits: true;
  initial-value: 0;
  syntax: "";
}

Step 3. Compute the sign

.comparison {
  --sign: sign(var(--x) - var(--y));
}

Step 4. React to the result

Using the new if() function:

.comparison {
  --sign: sign(var(--x) - var(--y));

  background-color: if(
    style(--sign: -1): coral;
    style(--sign: 1): lightgreen;
    else: lightgray;
  );
}

Or via container queries:

@container style(--sign: -1) {
  .comparison-result { background-color: coral; }
}

@container style(--sign: 0) {
  .comparison-result { background-color: lightgray; }
}

@container style(--sign: 1) {
  .comparison-result { background-color: lightgreen; }
}

With container queries, the comparison is computed on the parent, and the styles are applied to a nested element.

Either way, pure CSS decides what styles to apply based on variable values.

Wrapping up

The tiny expression sign(var(--x) - var(--y)) turns the impossible into possible.

We’ve got a universal way to encode a comparison result into a single variable — and then use it anywhere: inside @container or if().

CSS is no longer a passive styling language. It can now make decisions based on its own variables and conditional logic, dynamically adjusting the appearance of elements.

And while this currently works only in Chrome, the Pandora’s box is already open — CSS has started to think.

Cookies ∙ Privacy ∙ License Agreement ∙ About ∙ Contacts ∙ © HTML Academy OÜ, 2019−2025

VISAMastercard

Log in

or

Forgot your password?

Sign up

Sign up

or
Log in

Restore access

Have you forgotten your password or lost access to your profile? Enter your email connected to your profile and we will send you a link to restore access.

Forgot to connect your email to the profile? Email us and we’ll help.

We are using cookies to gather information which will help you use our website most effectively. You can read about this here or disable this feature if you want. By continuing to browse the site, you agree to our use of cookies.