# Variables, mixins and JavaScript expressions

> CSS Post Processor variables: plain values, mixins with parameters, JavaScript expressions, auto-updating responsive variables and runtime css.set().

Source: https://csspp.dev/docs/variables/


css-pp variables do more than hold a value. A variable can be a plain value, a mixin with parameters, or a JavaScript expression evaluated in the page. Add a `!` and it recalculates whenever the window is resized.

## Defining and using a variable

Define a variable on its own line, outside any rule, with a `$`, a name and the value in braces. Use it with `$name`. Definitions can go anywhere in the stylesheet, before or after the rules that use them.

```css
$brand{#0ea5e9}
$gap{24px}

.button { background: $brand; margin-bottom: $gap; }
```

Wrap the name in brackets when it touches other characters, so css-pp can tell where the name ends:

```css
$size{1280}

.hero { background-image: url(/img/hero-$[size].jpg); }
.box  { width: $[size]px; }
```

Native CSS custom properties can't do this. A `url()` can't be assembled from `var()` pieces, but a css-pp variable is substituted as text before the browser sees it.

## JavaScript expressions

If a value is valid JavaScript, css-pp evaluates it; otherwise it is used as written. That makes calculations and logic one line long:

```css
$half{css.vars.w() / 2}          /* half the viewport width, as a number */
$cols{Math.max(1, Math.floor(css.vars.w() / 320))}

.panel { width: $[half]px; }
.grid  { grid-template-columns: repeat($cols, 1fr); }
```

A value can hold several statements. The value of the last expression is the result:

```css
$img!{
  if (css.vars.w() > 1600) "1920";
  else if (css.vars.w() > 1024) "1600";
  else "1024";
}
.hero { background-image: url(/img/hero-$[img!].jpg); }
```

These helpers are available inside expressions:

| Helper | Returns |
|---|---|
| `css.vars.w()` | Viewport width in pixels |
| `css.vars.h()` | Viewport height in pixels |
| `css.vars.w('.selector', n)` | Width of the *n*-th element matching the selector (default 0) |
| `css.vars.h('.selector', n)` | Height of the *n*-th matching element |

Any global JavaScript works too, such as `Math`, `Date`, `document` or your own functions.

> **Security note.** Expressions run with `eval()`, just like code in a `<script>` tag. Only process stylesheets you control. If your Content Security Policy blocks `'unsafe-eval'`, plain values, nesting and the state and content selectors still work, but expressions and built-ins such as `$[index]` do not.

## Mixins with parameters

A variable can hold a block of declarations. List default parameter values in parentheses and refer to them as `&a`, `&b`, `&c` and so on, in order:

```css
$shadow(0, 8px){box-shadow: &a &b 24px rgb(0 0 0 / .18)}
$truncate(1){display: -webkit-box; -webkit-line-clamp: &a; -webkit-box-orient: vertical; overflow: hidden}

.card    { $shadow(0, 12px); }
.excerpt { $truncate(3); }
.title   { $truncate; }          /* uses the default: 1 line */
```

Arguments are positional and comma-separated. When you pass arguments, pass all of them; the defaults apply only when you call the mixin without parentheses.

## The current selector: `&self`

Pass `&self` as an argument and it becomes the selector of the rule that uses the variable, as a quoted string. That lets a variable measure or count the elements it is styling:

```css
$count!(&self){document.querySelectorAll(&a).length}

/* split the row evenly, however many columns there are */
.cols > div { width: calc(100% / $[count!]); }
```

The `!` makes the count update after the page has loaded and when the window is resized (see below). This particular one is also built in as [`$[count]`](/docs/index-variable/#values).

## Auto-updating variables

End a variable's name with `!` and css-pp recalculates it after the page finishes loading, whenever the window is resized and when the orientation changes. Every rule that uses it updates in place. Include the `!` when you use it:

```css
$vw!{css.vars.w()}
$vh!{css.vars.h()}

.full   { height: $[vh!]px; }
.label::after { content: "$[vw!]px wide"; }
```

Recalculation is throttled by [`css.defaults.resizing`](/docs/#options) (100 ms by default).

## Variables that reference variables

A value can use other variables. css-pp resolves them before evaluating:

```css
$base{16}
$large{$base * 1.5}

h1 { font-size: $[large]px; }
```

## Arrays: one value per element

If a variable evaluates to an array, each matched element gets the next item. The values map to element positions, like `:nth-child()`:

```css
$palette{['#ef4444', '#f59e0b', '#10b981', '#3b82f6']}

.tags > li { background: $palette; }
```

For values computed from an element's position, [`$[index]`](/docs/index-variable/) is usually simpler.

## Changing variables at runtime

Call `css.set(sheet, name, value)` to change a variable after the page has loaded. Every rule that uses it updates immediately, without reloading the stylesheet. `sheet` is the stylesheet name: the file name without its extension, or the `id` you passed to `css.open('#id')`.

```js
css.set('site', 'brand', '#e11d48');   // recolor every rule that uses $brand
css.get('site', 'brand');              // "#e11d48"
```

Pass values as strings. `css.set()` ignores empty values such as `0` or `''`, so write `'0'` instead. More in the [JavaScript API](/docs/javascript-api/).

## Comments

Both comment styles are supported:

```css
/* block comment */
.a { color: red; } // line comment, to the end of the line
```

A `//` counts as a comment only at the start of a line or after a space, `;`, `{` or `}`. URLs such as `url(https://cdn.example.com/a.png)` and `url(//cdn.example.com/a.png)` are left alone.
