@for iterates over an array or object and produces CSS for each item. It runs at compile time; the output is standard CSS.
Syntax
Section titled “Syntax”@for(item, target) { /* CSS for each iteration */}The iteration value is accessed with ${item} and object item fields with ${item.key}. Arithmetic, string concatenation, and compile-time var() access are supported inside ${...}.
Basic Usage
Section titled “Basic Usage”Literal Array
Section titled “Literal Array”@for(i, [1, 2, 3]) { .w-${i} { width: ${i * 10}px; }}Generated CSS:
.w-1 { width: 10px; }.w-2 { width: 20px; }.w-3 { width: 30px; }Can also be written with range syntax:
@for(i, [1-4]) { .p-${i} { padding: ${i * 4}px; }}Target Types
Section titled “Target Types”Array Variable
Section titled “Array Variable”--scale: [1-3];--space: 4px;
@for(i, var(--scale)) { .m-${i} { margin: ${i} * var(--space); }}Generated CSS:
.m-1 { margin: 4px; }.m-2 { margin: 8px; }.m-3 { margin: 12px; }Array of Objects
Section titled “Array of Objects”When array items are objects, fields are accessed with ${item.key}.
--breakpoints: [ { name: sm; size: 640px }, { name: md; size: 768px }, { name: lg; size: 1024px }];
@for(bp, var(--breakpoints)) { @media (min-width: ${bp.size}) { .container-${bp.name} { max-width: ${bp.size}; } }}Generated CSS:
@media (min-width: 640px) { .container-sm { max-width: 640px; }}
@media (min-width: 768px) { .container-md { max-width: 768px; }}
@media (min-width: 1024px) { .container-lg { max-width: 1024px; }}This pattern is the most typical example of generating at-rules inside @for. A separate @media block is opened on each iteration.
With Nesting
Section titled “With Nesting”@for can also be used when generating nested selector blocks:
--variants: [sm, md];
@for(size, var(--variants)) { .card-${size} { .title { font-size: 14px; } }}Generated CSS:
.card-sm .title { font-size: 14px;}
.card-md .title { font-size: 14px;}Object Key Loop
Section titled “Object Key Loop”When @for(key, var(--obj)) is used, the iteration value becomes the object's keys. The value of that key is accessed with var(--obj[${key}]).
--alignContent: { normal: normal; start: flex-start; end: flex-end; };
@for(key, var(--alignContent)) { .content-${key} { align-content: var(--alignContent[${key}]); }}Generated CSS:
.content-normal { align-content: normal; }.content-start { align-content: flex-start; }.content-end { align-content: flex-end; }Part of the variable name inside var(...) can also be generated via a placeholder:
--themes: { light: light; dark: dark; };--colors-light: { bg: #f8f9fa; };--colors-dark: { bg: #0f1117; };
@for(t, var(--themes)) { .theme-${t} { --c-bg: var(--colors-${t}.bg); }}In this example var(--colors-${t}.bg) resolves on each iteration as var(--colors-light.bg) and var(--colors-dark.bg). The same placeholder variable name generation can also be used inside @fun.
@for can also be used inside an object variable body to generate keys:
--factor: 2;--range: [1-4];
--spacing: { @for(i, var(--range)) { ${i}: ${i * var(--factor)}px; }};This support is only for the @for(...) { key:value; } form inside object body; @if and @fun are not supported inside object body.
Index Variable
Section titled “Index Variable”The loop index can be accessed with the (item, ind) form. Index starts from 0.
--colors: [red, blue, green];
@for((color, ind), var(--colors)) { .color-${ind} { background: ${color}; }}Generated CSS:
.color-0 { background: red; }.color-1 { background: blue; }.color-2 { background: green; }Using index with nth-child:
--items: [card, panel, box];
@for((name, ind), var(--items)) { .list:nth-child(${ind + 1}) { content: '${name}'; }}Generated CSS:
.list:nth-child(1) { content: 'card'; }.list:nth-child(2) { content: 'panel'; }.list:nth-child(3) { content: 'box'; }Nested Loop
Section titled “Nested Loop”@for blocks can be nested.
--x: [1-2];--y: [1-3];
@for(i, var(--x)) { @for(j, var(--y)) { .m-${i}-${j} { padding: ${i * j}px; } }}Generated CSS:
.m-1-1 { padding: 1px; }.m-1-2 { padding: 2px; }.m-1-3 { padding: 3px; }.m-2-1 { padding: 2px; }.m-2-2 { padding: 4px; }.m-2-3 { padding: 6px; }String concatenation alternatives in selector:
.m-${i}-${j} /* .m-1-1 */.m-${i+'-'+j} /* .m-1-1 — same result */For details on arithmetic and string expressions, go to the Expression Engine page.
Top-Level Variable Generation
Section titled “Top-Level Variable Generation”Top-level variable definitions can be generated inside a @for block. Generated variables behave like normal --name: value;.
@for(i, [100, 200, 300]) { --duration-${i}: ${i}ms;}Generated variables:
--duration-100: 100ms;--duration-200: 200ms;--duration-300: 300ms;These variables can then be used normally:
@for(i, [100, 200, 300]) { --duration-${i}: ${i}ms;}
.fade-100 { transition: opacity var(--duration-100) ease; }.fade-200 { transition: opacity var(--duration-200) ease; }Generated CSS:
:root { --duration-100: 100ms; --duration-200: 200ms; --duration-300: 300ms;}
.fade-100 { transition: opacity var(--duration-100) ease; }.fade-200 { transition: opacity var(--duration-200) ease; }Multiplier With Unit-Carrying Array
Section titled “Multiplier With Unit-Carrying Array”If array items carry units, they can be multiplied by a unitless multiplier.
--scale: [1px-3px];--factor: 4;
@for(i, var(--scale)) { .space-${i} { margin-top: ${i} * var(--factor); }}Generated CSS:
.space-1px { margin-top: 4px; }.space-2px { margin-top: 8px; }.space-3px { margin-top: 12px; }Usage With @if
Section titled “Usage With @if”@if can be used inside a @for block. The condition is evaluated separately on each iteration.
--sizes: [sm, md, lg];
@for(size, var(--sizes)) { @if(${size} === 'sm') { .btn-${size} { padding: 4px 8px; } } elseif(${size} === 'md') { .btn-${size} { padding: 8px 16px; } } else { .btn-${size} { padding: 12px 24px; } }}Generated CSS:
.btn-sm { padding: 4px 8px; }.btn-md { padding: 8px 16px; }.btn-lg { padding: 12px 24px; }