Core concepts

Learn the core concepts behind Assembler CSS

We designed Assembler CSS to resemble existing technologies and to help users become pro-efficient in using the framework as quickly as humanly possible.

As a starting point, let’s build a simple HTML component using the style attribute.

<div style="background: #7b4fe9; width: 150px; 
            height: 150px; border-radius: 4px; 
            margin-left: auto; margin-right: auto"></div>

Now let’s use Assembler CSS to build the same HTML component again, but this time using the x-style attribute.

<div x-style="background: #7b4fe9; width: 150px; 
              height: 150px; border-radius: 4px; 
              margin-left: auto; margin-right: auto"></div>

Can you spot any difference in terms of code between the two components, besides the attribute name? If you carefully analyze the content of the style and x-style attributes, you will find that they are, in fact, identical. The implications of this simple fact are mind-blowing: if you have ever used the style attribute, you already know how to use Assembler CSS.

The properties used inside a style attribute are called CSS properties, and the ones used inside an x-style attribute are called Assembler properties, or just properties. Each assembler property corresponds to an identically named CSS property.

Virtual properties

Using properties in their full name when designing components is cumbersome and hard to read. To mitigate this, we have introduced the concept of virtual properties. Let’s rewrite the above HTML component, but this time by using virtual properties.

<div x-style="bg:#7b4fe9; w:150px; h:150px; radius; mx:auto"></div>

Much better this way! The code is considerably more compact and way easier to read.

When naming virtual properties, we took inspiration from popular CSS frameworks like Bootstrap and TailwindCSS. The chances are that you have already used one of these frameworks, so classes as mx-auto are already familiar to you. With a little imagination, you may observe that mx-auto strongly resembles the above mx:auto.

For brevity, referring to a virtual property as being property is perfectly acceptable, as long as it doesn’t create confusion.

You might have already observed that radius doesn’t have an explicit value set. That’s because radius and a series of other properties have associated default values.

Some virtual properties map onto multiple properties simultaneously, while others map onto different properties depending on their value. For example, mx maps to margin-left and margin-right while flex could map onto either display or flex.

<div x-style="flex; flex:auto"></div>
<!-- equivalent of -->
<div x-style="display:flex; flex:auto"></div>

CSS variables

Custom CSS properties, or CSS variables, are one of the most powerful features in modern CSS. Assembler CSS allows you to refer to a CSS variable using the @ symbol, followed by the variable name.

Hello, World!
<style>
    :root {
        --primary: #7b4fe9;
    }
</style>
<div x-style="color:@primary">Hello, World!</div>

Of course, you can also use the standard syntax, if you prefer, but we find it to be a little too convoluted for our taste.

Hello, World!
<style>
    :root {
        --primary: #7b4fe9;
    }
</style>
<div x-style="color:var(--primary)">Hello, World!</div>

The majority of CSS frameworks provide, by default, some color system, usually a collection of color palettes. Developers can refer to those colors by using CSS classes like text-primary, bg-red, border-blue-300, and so on.

But what if you need to add a new color or a custom color palette? How can you do it? You will most certainly need to clone a Git repository, then install some tools used for building CSS, and only then, after much effort, you will be able to add your custom colors. Needless to say that if you are not a programmer, everything will be much harder for you.

In our book, this is unacceptable. That’s why, if you want to use a color palette with Assembler CSS, you only need to define custom CSS variables.

:root {
    /* Material Design Indigo Palette */
    --indigo-50: #e8eaf6;
    --indigo-100: #c5cae9;
    --indigo-200: #9fa8da;
    --indigo-300: #7986cb;
    --indigo-400: #5c6bc0;
    --indigo-500: #3f51b5;
    --indigo-600: #3949ab;
    --indigo-700: #303f9f;
    --indigo-800: #283593;
    --indigo-900: #1a237e;
    --indigo: var(--indigo-500);
    
    /* Custom color */
    --amber: #FFC107;
}

Then you can use your color palettes however you want; for borders, text, etc.

Hello, World!
<div x-style="gradient:@indigo-300, @indigo-900; color:@amber; p:8; radius">
    Hello, World!
</div>

Preset values

Sometimes maintaining the same proportions across your entire design can be pretty challenging. That’s why we have introduced the concept of preset values, which, in most cases, are nothing more than an alias for a CSS variable.

Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
<div x-style="font-size:xs">Hello, World!</div>
<div x-style="font-size:sm">Hello, World!</div>
<div x-style="font-size:base">Hello, World!</div>
<div x-style="font-size:lg">Hello, World!</div>
<div x-style="font-size:xl">Hello, World!</div>

In the example above, font-size:xs maps to font-size:@font-size-xs, font-size:sm maps to font-size:@font-size-sm, and so on. This means that you can easily modify and customize how preset values behave by using CSS variables.

Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
<style>
    /* Invert font size */
    :root {
        --font-size-xs: 1.25rem !important;
        --font-size-sm: 1.125rem !important;
        --font-size-base: 1rem !important;
        --font-size-lg: 0.825rem !important;
        --font-size-xl: 0.75rem !important;
    }
</style>
<div x-style="font-size:xs">Hello, World!</div>
<div x-style="font-size:sm">Hello, World!</div>
<div x-style="font-size:base">Hello, World!</div>
<div x-style="font-size:lg">Hello, World!</div>
<div x-style="font-size:xl">Hello, World!</div>

Migrating back and forth between Assembler CSS and existing CSS frameworks should be done as smoothly as possible. Therefore, the names used for preset values were inspired at large by existing CSS frameworks.

States

Until now, everything that we have presented here could be reproduced, in a way or another, by using the style attribute. But there are things that you can’t do by simply using a style attribute, like changing the border color of an input element when it receives focus or changing the color of a text when you hover the mouse over it.

Assembler CSS allows you to change the value of a property, depending on the element’s state. You can do this by appending to the property name the . symbol, followed by the name of the state you want to target.

Hover your mouse here
<div x-style="color:#3f51b5; color.hover:#ffc107; font-size:40px">
    Hover your mouse here
</div>

Scopes

There are circumstances when you don’t want a property to target the current element but a child of the current element or the first letter in a text. Or, in the case of an input element, you might want to target the placeholder.

Using a scope is done by prefixing the property name with the ! symbol and the scope’s name.

Hello, World!
<div x-style="color:#3f51b5; first-letter!color:#ffc107; font-size:40px">
    Hello, World!
</div>

You can also combine scopes and states to obtain the desired visual effect.

<input placeholder="First name"
       x-style="appearance:none; h:8; min-w:16; px:2; py:1; outline:none;
                placeholder!color:silver; placeholder!color.focus:@indigo;
                placeholder!transition:all 0.25s; transition:all 0.25s;
                border; border-color:@indigo; border-color.focus:@indigo-700; 
                font-size:base; radius; ring.focus:3px @indigo-100">

Media breakpoints

Creating responsive designs with Assembler CSS is extremely easy. We provide two modes in which you can handle responsive design: mobile-first mode and desktop-first mode. The default mode is mobile-first.

Each mode has different breakpoints. For mobile-first we have: sm, md, lg, and xl, while for desktop-first we have xs, sm, md, and lg. As you can see, the sm, md, and lg, are common to both modes.

Targeting a specific media breakpoint is done by prefixing the property name with the symbol | and the breakpoint name.

<!-- Resize your browser or flip your phone to see the effect -->
<div x-style="bg:red; sm|bg:green; md|bg:blue; lg|bg:orange; xl|bg:indigo;
              w:150px; h:150px; mx:auto"></div>

Mixins

Mixins are one of the most useful features of Assembler CSS. They allow you to write reusable style rules and apply them to various elements. Applying a mixin to an element is done by prefixing the mixin’s name with ^ symbol.

<div x-style="^foo"></div>

Mixins can receive arguments, and you can apply multiple mixins at the same time.

<!-- Mixin with arguments -->
<div x-style="^foo:arg1, arg2"></div>

<!-- Multiple mixins -->
<div x-style="^foo:arg1, arg2; ^bar; ^baz:arg1"></div>

You can define a new mixin with the help of a CSS variable. When declared, the variable name must be suffixed with --mixin.

<style>
    :root {
        --input--mixin: "appearance:none; h:8; min-w:16; px:2; py:1; outline:none;
                         placeholder!color:silver; placeholder!color.focus:@indigo;
                         placeholder!transition:all 0.25s; transition:all 0.25s;
                         border; border-color:@indigo; border-color.focus:@indigo-700;
                         font-size:base; radius; ring.focus:3px @indigo-100";
    }
</style>
<div x-style="mb:4">
    <label>First name:</label>
    <input placeholder="First name" x-style="^input">
</div>
<div>
    <label>Last name:</label>
    <input placeholder="Last name" x-style="^input">
</div>