Skip to main content

REST

Intro

The problem

Why is CSS a pain?

  • Because it's global
    Each declaration can affect anything in the document.

  • Changes come in from anywhere
    Each declaration can affect anything from any line and any file.

  • Rules can affect unwanted targets
    Each declaration can affect more than the intended target.

  • It can be done in infinite ways
    The points above make any task doable in a millions ways.

Solution

The goals of this methodology:

  • develop with simplicity, clarity and definiteness
    Avoid unpredictable dependencies and scattered information in many files.

  • maintain with confidence without side-effects
    Watch out for unwanted outcomes, avoid uncertain results.

  • scaling project and team
    Do not slow down as the project grows. Keep developers substitutable.

  • prevent resignation from CSS entropy
    Do not let your project fall into chaos where the only solution is to start over.

Main concept

SPOT CSS methodology and framework is all about architecture!

The main objective was to design rules that will unify the resulting code into a single possible form, no matter who writes it.

The solution is to have all rules for specific element in one and only SINGLE PLACE.

Hence the name SPOT CSS as the abbreviation of "Single Place of Truth".

3 Rules

There are only 3 simple rules to follow. And SASS compiler will let you know if you break them.

#1 One entity in one place

The most important rule is ONE ENTITY IN ONE PLACE, hence the name "Single Place Of Truth".

This applies to any entity, such as a component, element, or mutation.

You will find any entity always in one contiguous block.

#2 Fixed semantic order

The second rule is FIXED SEMANTIC ORDER of all entities:

A component contains:

  1. register - the very first...
  2. default -
  3. state
  4. variant
  5. responsive
  6. context
  7. pseudo-element - repeat entities with order 2. - 6.
  8. element - repeat entities with order 2. - 6.

When this prescripted order is not followed, SASS parser will let you know that you break the 2nd rule.

This rule brings the ability to find (or not to find) everything with absolute certainty. Because even if you can't find something (on its prescripted place), it means it doesn't exist.

#3 Follow HTML structure

The third and last rule is FOLLOW HTML STRUCTURE to find everything very quickly.

<button>
<span class="icon">
<img src="{{ buttonImage }}" />
</span>
<span class="text">
button name
</span>
</button>
+mode('draft')

+component('button')
display: inline-block

+____________________________
+element('.icon')
vertical-align: middle

+____________________________
+element('img')
width: 100%

+____________________________
+element('.text')
font-size: 1.2em

If your component has sub elements, a SASS/SCSS code have to reflect exact same element structure.

Why SASS syntax (not SCSS)?

Because you don't need to write @include but only +. And in this framework, you will do it very often. It's more simple and more readable.

Of course there are other differences: tabs instead curly brackets { } and no semicolons ;. But the main reason is omiting the @include keyword.

@include lorem() {
property: value;

@include ipsum('dolor') {
property: value;

@include sit('amet') {
@include consectetur {
property: value;
}
}
}
}
+lorem()
property: value

+ipsum('dolor')
property: value

+sit('amet')
+consectetur
property: value

But when you don't like SASS syntax (or just not used to), you can easily write SCSS. Therefore, all examples are also given in this syntax. It's a matter of preference (but also habit).

Installation

Install spotcss in your project:

$ npm i --save-dev spotcss

Import spotcss framework in your style:

@import "~spotcss"

Component

+component('button')
display: inline-block
button {
display: inline-block;
}

Mutations

When one entity has more appearances, we call it a MUTATION.

If element has only one appearance, we call it element without mutations. If element has more appearances, it has default appearance and other mutations.

Default

+mode('draft')

+component('button')
+default
display: inline-block
background-color: grey

+variant('.primary')
background-color: green



button {
display: inline-block;
background-color: grey;
}
button.primary {
background-color: green;
}

The mixins and functions used in the code above: mode, component, default, variant.

Variant

+mode('draft')

+component('button')
+default
display: inline-block
background-color: grey

+variant('.primary')
background-color: green



button {
display: inline-block;
background-color: grey;
}
button.primary {
background-color: green;
}

The mixins and functions used in the code above: mode, component, default, variant.

State

+mode('draft')

+component('button')
+default
display: inline-block
background-color: grey

+state(':hover')
background-color: yellow



button {
display: inline-block;
background-color: grey;
}
button:hover {
background-color: yellow;
}

The mixins and functions used in the code above: mode, component, default, state.

Context

+mode('draft')

+component('button')
+default
display: inline-block
background-color: grey

+context('ui-modal')
display: block



button {
display: inline-block;
background-color: grey;
}
ui-modal button {
display: block;
}

The mixins and functions used in the code above: mode, component, default, context.

Responsive

+mode('draft')

+component('button')
+default
display: inline-block
background-color: grey

+responsive('html.mobile-portrait')
display: block



button {
display: inline-block;
background-color: grey;
}
html.mobile-portrait button {
display: block;
}

The mixins and functions used in the code above: mode, component, default, responsive.

Sub-element

TODO

Separator

TODO

Element

TODO

Pseudo-element

TODO

Register

TODO

Mutations

TODO

Element structure

TODO

Exclusive values

TODO

Aliases

TODO

Sub components

TODO

Mode

TODO

Specificity

TODO

Element specificity

TODO

Class specificity

TODO

Id specificity

TODO

Override

TODO

<a class="link">Link</a>
<button class="btn">
<span class="icon">
<img src="{{ buttonImage }}" />
</span>
<span class="text">
Button name
</span>
</button>
<div class="card">
<div class="header">
<h3 class="title">Header</h3>
</div>
<div class="content">
<button class="btn">
<span class="icon">
<img src="{{ buttonImage }}" />
</span>
<span class="text">
Button name
</span>
</button>
</div>
</div>
.btn {
display: inline-block;

&.primary {
background: #dda132;

.icon {
position: relative;
top: -2px;
}

.text {
text-shadow: 0 2px black;
}
}
}
.card {
display: inline-block;
border-radius: 1em;
padding: 16px;

.btn {
padding: 5px 10px;
margin: 10px;
}

&.selected {
outline: 2px solid gray;
box-shadow: 0 0 2em black;
}
}
<div class="card">
<div class="header">
<h3 class="title">
<div class="content">
<button class="btn">
<span class="icon">
<img>
<span class="text">
+component('.carousel')
...

+_________________________
+pseudo-element('before')
...

+state(':hover')
property: value
+component('.btn')
...

+_____________________
+element('.text')
...

+state('.primary')
property: value
.btn.primary .text {
property: value
}