The ?! marker puts a selector in initial observed mode. It looks at the DOM snapshot at page open; it does not watch elements added later.
Behavior
Section titled “Behavior”- if in the DOM on first compilation → generated
- if not in the DOM on first compilation → not generated
- if later added to the DOM → not generated
- if later removed from the DOM → generated CSS stays active
Writing Rule
Section titled “Writing Rule”The ?! marker is written at the very end of the selector part, without a space. If a pseudo is present, it comes after the pseudo.
.col-4?! { grid-column: span 4; }.span-2?! { grid-column: span 2; }.btn:focus?! { outline: 2px solid #2060ff; }
/* wrong */.btn?!:focus { outline: 2px solid #2060ff; }.col-4 ?! { grid-column: span 4; }The same rule applies after composition via &var(...):
--hovercard: :hover { transform: translateY(-2px); };--active: .is-active { box-shadow: 0 10px 26px rgba(22, 61, 120, 0.18); };
.card &var(--hovercard)?! { opacity: 0.85; }.card &var(--active)?! { opacity: 0.85; }These examples are evaluated as .card:hover?! and .card.is-active?! respectively.
Typical Usage
Section titled “Typical Usage”@for(i, [1-12]) { .col-${i}?! { grid-column: span ${i}; }}When the page opens, only the .col-* selectors that are present in the DOM are generated. CSS is not generated for new .col-* elements that come later.
When Should It Be Used?
Section titled “When Should It Be Used?”| Situation | Usage | Why | Example |
|---|---|---|---|
| Grid classes that are fixed on page open | Use ?! | Initial snapshot is sufficient, no need to watch later | .col-4?! { grid-column: span 4; } |
| Producing only the used part of large utility sets | Use ?! | Generates as much CSS as the actual usage at open | .mt-4?! { margin-top: 16px; } |
| Fixed card variants from SSR or server render | Use ?! | DOM is ready on first load, no later additions expected | .card-compact?! { padding: 8px; } |
| Visible part of theme / palette utility classes at open | Use ?! | Emitted as much as the first observed usage | .text-primary?! { color: var(--colors.primary); } |
| Toast, modal, drawer that open later | Prefer ? | They will be added to DOM outside the initial snapshot, so ?! is insufficient | .toast? { background: #333; } |
| Basic layout rules that must always be generated | Don't use Observed | Use a normal selector if you don't want snapshot filtering | .container { max-width: 1200px; } |
Short note:
- If the opening DOM snapshot is sufficient →
?! - If there are selectors to be added to the DOM later →
? - For static CSS needed in all cases, don't use observed
Usage Scenarios
Section titled “Usage Scenarios”Grid System
Section titled “Grid System”@for(i, [1-12]) { .col-${i}?! { grid-column: span ${i}; }}
@for(i, [1-6]) { .row-${i}?! { grid-row: span ${i}; }}Palette and Utility Sets
Section titled “Palette and Utility Sets”--palette: [primary, secondary, success, warning, danger];
@for(color, var(--palette)) { .text-${color}?! { color: var(--colors.${color}); } .bg-${color}?! { background: var(--colors.${color}); } .border-${color}?! { border-color: var(--colors.${color}); }}Spacing Utility With @for
Section titled “Spacing Utility With @for”@for(i, [0-12]) { .mt-${i}?! { margin-top: ${i * 4}px; } .mb-${i}?! { margin-bottom: ${i * 4}px; } .p-${i}?! { padding: ${i * 4}px; }}Conditional Initial Observed With @if
Section titled “Conditional Initial Observed With @if”--layout: compact;
@if(var(--layout) === 'compact') { .card-compact?! { padding: 8px; }}else { .card-compact?! { padding: 16px; }}Only the true branch is generated; the generated selector also only enters CSS if it has a match in the opening snapshot.
Usage With lazy
Section titled “Usage With lazy”When lazy is on, the behavior of initial observed rules at the initial load time gains extra importance. For the detailed behavior table, see the Performance page.