Skip to main content

Output & evaluation cheat sheet

A quick reference for how Jess formats output and how it evaluates the trickier corners, each with a tiny input → output. The shared formatting and evaluation rules are the same engine as the Less site; the Jess-flavored specifics (interpolation spelling, Sass+ strictness) are at the end.

Output formatting​

Un-operated values are source-verbatim​

Un-operated dimensions, colors, keywords, and quoted strings emit exactly as written; only computed results (and compressed output) canonicalize.

.a { width: 1.0px; height: 2PX; color: #989; }
.a { width: 1.0px; height: 2PX; color: #989; }

See Verbatim values.

Operators and separators are spaced​

/, +, -, *, and list commas print with surrounding spaces, no matter how you wrote them — they are separators, not values.

.a { margin: 12px/16px; grid-area: 1/2/3/4; }
.a { margin: 12px / 16px; grid-area: 1 / 2 / 3 / 4; }

Exception: :nth-*() An+B stays unspaced​

The An+B microsyntax is selector syntax — never spaced, never evaluated.

.a:nth-child(2n+1) { color: red; }
.a:nth-child(2n+1) { color: red; }

Function shape passes through verbatim​

name(...) with no space before ( emits verbatim, even for names that are not real CSS functions.

.a { border: 1px solid(#a8000b); }
.a { border: 1px solid(#a8000b); }

Grouping parens dissolve after evaluation​

keyword (expr) — a space then parens — is math grouping. Parens are dropped when the calculation in them is resolved: a $( … ) that computes, a function that runs, or a variable or member that names one value ($w: 10vh; height: ($w) → height: 10vh). (A no-space keyword(expr) is the function shape above and stays verbatim.) Parens around something that computes nothing — one value, a CSS function such as var(), math kept as written, a variable that names a list — stay as you wrote them, as they do in plain CSS. The same holds inside a math function: math written in calc() is not computed, so calc(100% - ((1px + 2px))) keeps its parens, while calc(100% - (($(1px + 2px)))) is calc(100% - 3px) and calc(($(1px + 2px))) is calc(3px). Text is never a computed value, and it prints as written: parens around an escaped string, such as $e("1px + 2px"), stay wherever it is written, so calc(2 * ($e("1px + 2px"))) is calc(2 * (1px + 2px)) and ($e("foo")) is (foo). Only where the text is spliced into a selector, a property name or a string, or read by a function, the group gives its text.

$a: #a80000; $b: #00000b;
.a { border: 1px solid ($($a * .66 + $b * .33)); }
.a { border: 1px solid #6f0004; }
$w: 10vh;
.a { height: ($w); width: ($(1px + 2px)); top: var(--top, (10px)); left: (10px); }
.a { height: 10vh; width: 3px; top: var(--top, (10px)); left: (10px); }

Color functions pass through un-operated​

CSS-shaped rgb/rgba/hsl/hsla with three or more argument slots and no operation emit verbatim; the function runs when the value is operated on or given a Less overload/variable argument. Less one-/two-slot overloads such as rgba(#fff) dispatch normally.

.a { color: hsl(200, 50%, 40%); }               // verbatim
.b { color: lighten(hsl(200,50%,40%), 10%); } // computed

Nested output + :is() compaction​

Output is nested by default (collapseNesting: false); @media is not merged; extend cascades are :is()-compacted. See Output model and Extend.

Evaluation​

Escaped ~"..." is opaque​

An escaped string is never sniffed as a number. = compares by content (3 = ~"3" is true); </> against a number is not comparable, so a guard using them does not fire.

Mixin self-reference is a no-op​

A non-parametric ruleset that calls itself excludes its own frame — it renders once and never errors.

Mixin variable leaks are low priority​

A variable a mixin unlocks into the caller is low priority: a lexical binding always wins, and the leaked variable is used only where nothing lexical binds.

if() / boolean() are branch-lazy​

The branch not taken is never evaluated.

.a { width: if(false, 1/0, 7px); }
.a { width: 7px; }

@import (reference) is hidden until pulled in​

Reference imports emit nothing on their own; their rules appear only where you $extend them or call an imported mixin.

Resolve failures are errors​

Any failed variable resolve is a hard error unless the resolve is explicitly optional. There are no cyclic variables — $a: 1; $a: $a + 1; yields 2. See Advanced variable resolution.

Jess-flavored specifics​

  • Three $ forms, one per position: ${…} interpolates in identifier positions (selectors, property names, at-rule preludes) and in strings; $[…] (lookup) and $(...) (expression) are value-position forms, and $(...) is also allowed in strings. Inside ${…}, ${tone} is the variable and ${[tone]} the lookup — see Interpolation.
  • Variables: $name is a live reference; $^name is the scoped/final lookup. $name := value updates the live/current binding; $^name := value updates the scoped/final binding.
  • Sass+ rejects invalid CSS: where Sass tolerates invalid CSS (escaped at-rule keywords, bogus combinators), Jess's "Sass+" dialect rejects it — valid CSS is the target, not Sass parity.