Functions
This section refers to functions defined in stylesheets. For importing functions from other languages, see the @-use and @-from at-rules.
In Jess, a function is not a new kind of statement — it is a value. You write an anonymous mixin that returns a single value, and you bind it to a variable like any other value. We indicate we want a single value with >, and the return value is then assigned with result. (This matches the CSS @function spec, where the return descriptor is result:.)
$my-function: @() > {
result: $(1 + 2);
}
.box {
value: $my-function();
}
→
.box {
value: 3;
}
Because the definition is a block-valued assignment, it auto-terminates at its closing brace — the ; above is optional. See block-valued assignments.
Expression bodies
Like arrow functions in JavaScript, an anonymous function can return a single expression instead of a block.
$my-function: @() > $(1 + 2);
.box {
value: $my-function();
}
→
.box {
value: 3;
}
This is exactly sugar for a body whose only statement is result: <expression>; nothing downstream can tell the two spellings apart.
An expression body is not a block, so it does not get the block exception: it still needs a ; to separate it from a following declaration. See block-valued assignments.
Parameters, defaults, and named arguments
@(…) takes the same parameter list a named mixin declares, and a call binds through the same argument binder a named mixin call uses. So you get positional arguments, named arguments, and parameter defaults with no extra rules to learn.
$add: @($a, $b: 10px) > {
result: $($a + $b);
}
.box {
width: $add(1px);
height: $add(1px, 2px);
margin: $add($b: 2px, $a: 1px);
}
→
.box {
width: 11px;
height: 3px;
margin: 3px;
}
$add(1px) lets $b fall back to its default, $add(1px, 2px) binds positionally,
and $add($b: 2px, $a: 1px) binds by name — so named arguments may appear in any
order.
Arity is checked
Passing the wrong number of arguments is an error (eval/bad-call-arity), not a silent fallback to the literal call text:
$double: @($n) > $($n * 2);
.box {
value: $double(1, 2); // error: function expects 1 args, got 2
}
A body that never assigns result: is also an error (eval/invalid-function) — the call has no value to yield:
$broken: @($n) > {
width: $n; // never assigns `result:`
}
.box {
value: $broken(1px); // error
}
No early returns
Functions do not have "early" returns — the last resolved result: assignment wins. A result: inside an $if branch does not short-circuit; evaluation continues, and a later result: overrides it.
$pick: @() > {
$if(true) {
result: one;
}
result: two;
}
.box {
value: $pick();
}
→
.box {
value: two;
}
Think of functions like "mixins that look up the final assignment to a property named result".
Functions are first-class values
A function literal is a value and $my-function is an ordinary variable that happens to hold one. Referencing it without a call parenthesis reads the function itself, so you can alias it:
$double: @($n) > $($n * 2);
$alias: $double;
.box {
value: $alias(4);
}
→
.box {
value: 8;
}
…and you can pass it to another function and call it there. A function received as a parameter is bound by reference, so it stays callable:
$double: @($n) > $($n * 2);
$twice: @($fn, $v) > {
result: $fn($fn($v));
}
.box {
value: $twice($double, 3);
}
→
.box {
value: 12;
}