CSS @mixin At-Rule
The @mixin at-rule defines a reusable group of CSS declarations and nested rules that can be applied to multiple selectors. Mixins can accept parameters, use conditional rules, and reduce repeated CSS. The native CSS feature is experimental and is not yet supported in browsers.
@mixin Syntax
@mixin --mixin-name {
property: value;
}
The @mixin at-rule begins with a custom name starting with two hyphens, followed by a block containing CSS declarations or nested rules.
Mixins can also declare parameters inside parentheses.
@mixin --mixin-name(--parameter: default-value) {
property: var(--parameter);
}
A mixin is applied inside a CSS style rule using the proposed @apply at-rule.
@mixin --rounded-box {
padding: 20px;
border-radius: 8px;
}
.card {
@apply --rounded-box;
}
The --rounded-box mixin supplies the padding and border-radius declarations to the .card rule.
Unlike a CSS custom property, a mixin can contain multiple declarations and nested style rules rather than a single reusable value.
How @mixin Works
A mixin separates a reusable set of styles from the selectors that use those styles.
@mixin --panel {
padding: 20px;
border: 1px solid #ddd;
border-radius: 6px;
}
.card {
@apply --panel;
}
.notice {
@apply --panel;
}
Both .card and .notice receive the declarations defined in --panel.
Under the proposed behavior, applying a mixin substitutes its declarations and nested rules at the location of the @apply statement.
This allows a common group of styles to be maintained in one place instead of being repeated across multiple selectors.
Experimental Feature: Browsers do not currently implement native CSS mixins. These examples illustrate the proposed syntax and will not produce the intended styling in an ordinary browser.
Mixin Parameters
Parameters allow a mixin to accept different values each time it is applied.
@mixin --button-style(--background, --text) {
background-color: var(--background);
color: var(--text);
padding: 12px 20px;
border: 0;
}
.primary-button {
@apply --button-style(#0056b3, #fff);
}
.success-button {
@apply --button-style(#198754, #fff);
}
The same mixin defines the shared button styles, while each application supplies different background and text colors.
Inside the mixin, var() references the parameter values.
Typed Parameters
The draft also allows parameters to specify expected CSS value types.
@mixin --spacing(--gap <length>) {
padding: var(--gap);
}
.box {
@apply --spacing(20px);
}
The <length> type indicates that the parameter expects a CSS length value.
Typed parameters can help prevent incompatible values from being used when applying a mixin.
Default Parameter Values
A parameter can include a default value, which is used when an application does not supply an argument.
@mixin --card-style(--padding: 20px, --radius: 6px) {
padding: var(--padding);
border-radius: var(--radius);
border: 1px solid #ddd;
}
.card {
@apply --card-style;
}
.compact-card {
@apply --card-style(10px, 4px);
}
The .card selector uses the default padding and border radius. The .compact-card selector supplies different values.
Default values make mixins easier to reuse when most elements share the same styling but some require adjustments.
Conditional Rules
Mixins can contain conditional group rules, such as @media and @supports, allowing reusable styles to respond to different conditions.
Using @media
@mixin --responsive-padding {
padding: 10px;
@media (min-width: 768px) {
padding: 20px;
}
}
.container {
@apply --responsive-padding;
}
Under the proposed behavior, the container uses smaller padding on narrow viewports and larger padding when the viewport is at least 768 pixels wide.
Using @supports
@mixin --grid-layout {
display: block;
@supports (display: grid) {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
}
.layout {
@apply --grid-layout;
}
This mixin defines a basic display style and adds grid layout declarations when CSS Grid is supported.
Conditional rules inside mixins allow shared responsive or feature-dependent behavior to be defined in one location.
Nested Rules
A mixin can contain nested CSS selectors as well as property declarations.
@mixin --interactive-button {
padding: 12px 20px;
background-color: #0056b3;
color: #fff;
&:hover {
background-color: #003d80;
}
}
.button {
@apply --interactive-button;
}
The & nesting selector refers to the selector where the mixin is applied.
In this example, the mixin defines both the button's normal appearance and its hover styling.
The draft permits nested style rules inside a mixin. However, it does not currently allow @layer rules within a mixin body.
Content Blocks
The proposed @contents at-rule allows a mixin to receive a block of CSS declarations from the location where it is applied.
@mixin --wide-screen {
@media (min-width: 768px) {
@contents;
}
}
.card {
padding: 10px;
@apply --wide-screen {
padding: 20px;
font-size: 18px;
}
}
The mixin defines the media query, while the @apply block supplies the declarations to use when that condition matches.
In the proposed behavior, the card uses 10px padding by default and receives the larger padding and font size at wider viewport widths.
Fallback Content
The @contents rule can also contain fallback declarations for applications that do not provide a content block.
@mixin --highlight {
@contents {
background-color: #fff3cd;
}
}
.notice {
@apply --highlight;
}
.alert {
@apply --highlight {
background-color: #f8d7da;
}
}
The .notice selector uses the fallback background, while .alert supplies its own background color.
The @contents feature is part of the experimental native CSS mixin proposal and is not supported in current browsers.
CSS Mixins vs. Sass Mixins
The @mixin name is also used by Sass, a CSS preprocessor. Although the two features share a similar purpose, their syntax and processing are different.
| Feature | Native CSS Mixins | Sass Mixins |
|---|---|---|
| Definition | @mixin --name |
@mixin name |
| Application | @apply --name; |
@include name; |
| Parameters | CSS-style names beginning with -- |
Sass variables beginning with $ |
| Processing | Intended for native browser processing. | Compiled into CSS before delivery to the browser. |
| Browser Support | Not currently supported. | Compiled CSS works in browsers. |
Sass Example
@mixin button-style($background) {
background-color: $background;
color: #fff;
padding: 12px 20px;
}
.button {
@include button-style(#0056b3);
}
This is Sass syntax, not native CSS. A Sass compiler processes the mixin and generates ordinary CSS declarations.
For production websites, Sass mixins remain an available option for reusable declaration groups until native CSS mixins have sufficient browser support.
@mixin Example
The following example demonstrates how the proposed native CSS mixin syntax could create two buttons with shared styling and different background colors.
HTML
<button class="primary-button">Primary Button</button>
<button class="success-button">Success Button</button>
CSS
@mixin --button-style(--background: #0056b3) {
padding: 12px 20px;
border: 0;
border-radius: 4px;
background-color: var(--background);
color: #fff;
font-size: 16px;
}
.primary-button {
@apply --button-style;
}
.success-button {
@apply --button-style(#198754);
}
In a future browser implementation that follows this draft, the Primary Button would have a blue background and the Success Button would have a green background. Both would share the same padding, border radius, and text styling.
These styles will not render as intended in current browsers because the native @mixin and @apply features are unsupported.
Browser Support
The native CSS @mixin at-rule is experimental and not Baseline. It is not currently supported by major browsers. See the CSS Custom Functions and Mixins specification for developments and Can I Use? for future compatibility information.
Specifications
The @mixin at-rule is defined in the draft CSS Custom Functions and Mixins Module Level 1. The specification describes reusable mixin definitions, parameters, nested rules, conditional styles, and the related @apply and @contents at-rules.
The feature remains under active development, and its syntax and behavior may change before browser implementations become available.
