Tuesday, June 9, 2026

@operate | CSS-Methods


The @operate at-rule defines CSS customized features. These customized features are reusable blocks of CSS that may settle for arguments, comprise advanced logic, and return values based mostly on that logic. The characteristic is analogous in nature to a extra dynamic model of customized properties (CSS variables).

Word: There may be additionally a @operate at-rule in Sass which is analogous in goal however totally different in operate to the native CSS @operate. Pay attention to this if Sass is a part of your stack or when looking for sources as it’s simple to conflate one with the opposite.

Syntax

The @operate at-rule defines a customized operate, utilizing the next syntax:

@operate --function-name(#?) [returns ]? {
  
}

 =  ? [ :  ]?

In different phrases, we outline the operate’s identify as a dashed ident (--my-function), provide some situation we need to match (), and say what kind of factor we need to return, say, a CSS[] worth. And, if that situation matches, we apply types ().

Let’s dig deeper into what these issues really imply.

Arguments and Descriptors

There are a selection of components to the syntax for @operate to deal with totally different components of the characteristic. It could all look very advanced — and it’s — but it surely’ll change into clearer later after we take a look at some examples.

--function-token

A user-defined identifier that should begin with two dashes (--), just like the dashed-ident of customized properties. Similar to customized properties, the identify is case-sensitive. For instance, --conversion and --Conversion would consult with totally different customized operate definitions.

@operate --progression()

(non-obligatory)

An non-obligatory comma-separated checklist of inputs that may embody:

  • --param-name: The identify of the argument (should begin with --).
  • (non-obligatory): A key phrase or kind (e.g., , ) that tells the operate what kind of enter or end result it’s returning when it hits a matched situation.
  • (non-obligatory): A fallback worth that’s returned if the result’s invalid, such because the argument is omitted through the operate name. Should you present a default worth, it should be legitimate to the aforementioned (e.g. a should default to a sound CSS size). It’s separated from the remainder of the parameter definition with a colon (:).
  • returns (non-obligatory): Defines the anticipated output kind of the operate. This helps the browser validate logic earlier than rendering. If a kind isn’t specified then, something will probably be legitimate (like writing returns kind(*)).
  • : CSS declarations and at-rules that assemble the operate’s physique and logic. It may well embody customized properties and the end result descriptor — both on the root or nested inside an at-rule.
@operate --progression(--current , --total ) returns  {
  end result:
}

The end result descriptor that defines what the customized operate will return. If a customized operate forgoes the end result descriptor, it is going to at all times return guaranteed-invalid worth, identical to a damaged customized property.

@operate --progression(--current , --total ) returns  {}

Primary Utilization

For an instance of essentially the most fundamental operate you possibly can make, we’ve got a operate that calculates a offered worth (e.g. 20px) in half (e.g. 10px), and returns returns it as a size unit (e.g. px):

@operate --half(--size ) {
  end result: calc(var(--size) / 2);
}

Right here, we’re ‘naming’ our operate by setting the function-token to --half. We’re then making a function-parameter known as --size, and setting the css-type to , so that it’ll solely settle for size values. The end result descriptor is ready to calc(--size / 2), which makes use of the CSS Calculating Perform to halve the worth sourced from the dimension function-parameter.

We then use the operate like so:

.container {
  margin-inline: --half(20px); /* This can resolve to 10px */
}

Sort Checking

Similar to when writing JavaScript or different languages, generally we need to guarantee a operate solely accepts sure arguments. For instance, what if we need to make sure that solely numbers may be enter and that solely a proportion may be output?

@operate --progression(--current , --total ) returns  {
  end result: calc(var(--current) / var(--total) * 100%);
}

.progress-bar {
  width: --progression(3, 5); /* Evaluates to 60% */
}

The is enclosed in angle brackets in a fashion an identical to the way you type-check a customized property through @property. If an argument doesn’t match the declared kind (e.g. ), the operate name turns into invalid, which could be very beneficial for catching bugs early in giant codebases.

You need to use a to permit a number of varieties by wrapping the kinds in kind() and utilizing | as a separator. For instance, --alpha right here permits each and :

@operate --transparent(--color , --alpha kind( | ));

Comma-Separated Lists

CSS makes use of commas to separate the inputs of a customized operate, which begs the query: what in the event you want to present an inventory of values? To supply an inventory of values as one enter slightly than a number of separate inputs, you should first mark a operate to anticipate an inventory.

To do that, you suffix the # character to the . When calling the operate, you then wrap the checklist of values in curly braces, which tells the browser to deal with all the things contained in the braces as a single argument.

For example:

/* Calculates the space between the very best and lowest values in an inventory, plus one other enter */
@operate --get-range(--list #, --n ) {
  end result: calc(max(var(--list)) - min(var(--list)) + var(--n));
}

div {
  /* Finds the distinction between 10px and 100px, then provides 200px */
  padding-block: --get-range({10px, 100px, 50px, 25px}, 200px); /* 290px */
}

Constructs and the CSS Cascade

The end result descriptor follows the principles of the CSS Cascade. Which means you’ll be able to declare a number of end result values, and the final legitimate matching worth will win, identical to some other properties. As such, conditional group guidelines (@media, @container, @helps) and different features, corresponding to if(), present a number of further potentialities.

On this case, we return a --suitable-font-size that defaults to 16px when the display is lower than 1000px pixels. If the display is bigger than 1000px then the “successful” fashion is what’s within the @media block.

@operate --suitable-font-size() returns  {
  end result: 16px;

  @media (width > 1000px) {
    end result: 20px;
  }
}

physique {
  font-size: --suitable-font-size();
}

Understand that the final outlined worth at all times wins, so in the event you have been to jot down the instance under, the end result would at all times be 16px, whatever the media question being triggered.

@operate --suitable-font-size() returns  {
  @media (width > 1000px) {
    end result: 20px;
  }

  end result: 16px;
}

The adherence to the established cascade additionally lets you use customized properties inside a operate. These customized properties are domestically scoped, so they’re solely accessible in your customized operate and any customized operate that references it and thus received’t unexpectedly leak out globally and work together with the remainder of your CSS.

@operate --spacing-scale(--multiplier) {
  --base-unit: 8px;
  end result: calc(var(--base-unit) * var(--multiplier));
}

You too can use different customized features inside a customized operate, primarily nesting one operate inside one other. This enables for very clear code, the place every part solely does one job and features may be broadly reused.

@operate --square(--n) {
  end result: calc(var(--n) * var(--n));
}

@operate --circle-area(--radius) {
  --pi: 3.14159;
  end result: calc(var(--pi) * --square(var(--radius)));
}

.blob {
  width: calc(--circle-area(10) * 1px); /* 314.159px */
}

Defaults

Capabilities can deal with a number of arguments and supply default values. The default worth is outlined by together with it on the finish of the operate parameter, separated by a colon (:).

/* Outline the operate */
@operate --brand-glass(--opacity : 0.5) returns  {
  end result: rgb(10 120 255 / var(--opacity));
}

/* Use the operate */
.header {
  background: --brand-glass(); /* Defaults to 0.5 */
}

.header:hover {
  background: --brand-glass(0.8); /* Overrides to 0.8 */
}

No Aspect Results

A CSS @operate can solely return a worth; it can not do the rest. For instance, you can’t change a property within a operate or use a operate to generate a number of declarations. For such talents, one should look to the proposed @mixin at-rule, which would offer performance on this method, permitting a number of traces of CSS properties and different advanced logic.

Round Dependencies

CSS could be very strict about round logic. If Perform A calls Perform B, and Perform B calls Perform A, the browser will catch this cyclic dependency and instantly mark each as invalid.

This additionally applies to CSS Customized Properties and referring to the customized operate itself. If a operate depends on a customized property or operate that’s itself calculated by that very same operate, the browser will finish the calculation to forestall an infinite recursion.

Specification

The @operate at-rule is outlined within the CSS Customized Capabilities and Mixins Module Degree 1 specification.

Browser Assist

Unsupported browsers ignore @operate, so fallback declarations and progressive enhancement methods may be advantageous. You need to use @helps to test if @operate is supported within the consumer’s browser, like so:

@helps (at-rule(@operate)) {
  /* ... */
}

Paradoxically, nevertheless, at time of writing, the @helps at-rule analysis performance doesn’t have full help throughout browsers (Chrome 148+ solely), so you will want to test whether it is supported in your case. You may see the dialogue on this in CSS Drafts Problem #2463.

Extra Data

Related Articles

Latest Articles