Learn how scopes work and how you can create them

Scopes are an incredible useful feature of Assembler CSS that allow you to set properties to a child element or to a pseudo-element. Using a scope is done by prefixing the property name with the ! symbol and the scope’s name.

For example, scopes allow you set a property to the first letter in a text.

First letter scope
<div x-style="color:royalblue; first-letter!color:tomato; ...">
    First letter scope

Another useful thing you could do is combine a scope with a state to obtain the desired effect.

<input x-style="placeholder!color:slateblue; placeholder!color.focus:coral; ..." 
       placeholder="Email address">

Creating scopes

The best thing about scopes is that you can create your own! So, for example, if a certain pseudo-element selector is not supported by default, you don’t have to wait until we implement it.

Writing your own scope is simply a matter of defining a custom CSS variable suffixed with --scope. The content of the CSS variable must be a selector that targets either a child element or a pseudo-element.

In order for you to be able to build a custom selector, Assembler CSS provides you with a series of placeholders.

  • $var - The name of the variable holding the value set to the property
  • $property - The name of the targeted CSS property
  • $value - The value of the property in the form var(--asm-var)
  • $variants - A collection of alternative, cross-browser, CSS property-value pairs, or an empty string
  • $body - A combination between $property, $value, and $variants placeholders, representing the body of the current CSS rule.
  • $class - The CSS selector class that identifies the current scope
  • $state - The CSS scope associated with the property, or an empty string
  • $selector - A combination between $class and $state placeholders, representing the current CSS selection rule

Let’s exemplify how one can create a custom scope by building a scope named bullet that targets the ::marker pseudo-element.

The only thing we need to do is to define the scope itself.

:root {
    --bullet--scope: "$selector::marker { $body }";

Now we can start using our newly created scope.

  • JavaScript
  • HTML
  • CSS
  <li x-style="bullet!color:red">JavaScript</li>
  <li x-style="bullet!color:green">HTML</li>
  <li x-style="bullet!color:blue">CSS</li>

The above scope works great when setting individual values, but what if we want to set the property for all ::marker pseudo-elements under ul? We can simply define a new scope bullet-l1 that will do exactly that.

:root {
  --bullet-l1--scope: "$selector > *::marker { $body }";
  --bullet--scope: "$selector::marker { $body }";

The order in which you declare scopes matters when multiple scopes targets the same pseudo-element or element, so we must make sure we declare bullet after bullet-l1. This way we can use bullet to overwrite values for individual elements.

  • CSS
  • HTML
  • JavaScript
<ul x-style="bullet-l1!color:green; bullet-l1!content:'&check;'; ...">
  <li x-style="bullet!color:red; bullet!content:'&cross;'">JavaScript</li>

Built-in scopes

Below is the full list of scopes that Assembler CSS is providing, together with their definitions.

Scope Definition
before $selector::before { $body }
after $selector::after { $body }
selection $selector::selection { $body }
placeholder $selector::placeholder { $body }
first-letter $selector::first-letter { $body }
first-line $selector::first-line { $body }
marker $selector::marker { $body }
marker-l1 $selector > *::marker {$body}
even $selector:nth-child(even) {$body}
odd $selector:nth-child(odd) {$body}
first selector:first-child {$body}
last selector:last-child {$body}
l1 $selector > * {$body}
l2 $selector > * > * {$body}
sibling $selector > * + * {$body}
child $selector > $class {$body}
dark @media(prefers-color-scheme: dark) {$selector {$body}}
light @media(prefers-color-scheme: light) {$selector {$body}}
landscape @media(orientation: landscape) {$selector {$body}}
portrait @media(orientation: portrait) {$selector {$body}}
motion-reduce @media(prefers-reduced-motion: reduce) {$selector {$body}}
motion-safe @media(prefers-reduced-motion: no-preference) {$selector {$body}}
text-clip $selector {-webkit-background-clip: text !important; -moz-background-clip:text !important; background-clip:text !important;}

Text clip

The text-clip scope is used only to overcome a bug in Chromium-based browsers when using a CSS variable, having the value text, for the background-clip property.

Text clip
<div x-style="text-clip!bg-clip:text; color:transparent; gradient:red, blue; ...">
  Text clip