Skip to main content

Quick start guide

This is the quickest way to see the way style is written in this framework, without explanation of why it is so and what are the advantages of such an approach.

We offer 4 ways to explain our methodology and framework:

  • Cheat Sheet - takes 3 minutes - Select what you want to do and find out how to do it in SPOT CSS framework.

  • Quick start guide (current document) - takes 15 minutes - The quickest way to see the way style is written in this framework, without explanation of why it is so and what are the advantages of such an approach.

  • Tutorial - takes 1 hour - A basic overview that is organized so that it can be read from start to end and so that the reader understands the fundamental principles and basic ways of using the framework.

  • Documentation - takes hours - Comprehensive documentation of everything, organized by mixins and framework entities, so you can quickly find exactly what you want to learn more about.

Choose the one that fits your current needs best.

Intro

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.

Fasten your seat belt, this is going to be a fast ride!

(more info)

Why SASS syntax (not SCSS)?

Main reason - because you don't need to write @include but only +. And in this framework, you will do it very often. So this way with SASS syntax it's more simple and more readable.

@include lorem-ipsum {
property: value;
}
+lorem-ipsum
property: value

(more info)

Installation

Install spotcss in your project:

$ npm i --save-dev spotcss

Import spotcss framework in your style:

@import "~spotcss"

Component

Component is a very base entity in this component-based methodology and framework. It can be any simple/single element, or any block of the website (structure of elements).

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

(more info)

Element

A component can be composed by one element but sometimes by several elements, and the following mixin +element help us define them.

+mode('draft') // will be explained later

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

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

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

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


button {
display: inline-block;
}
button .icon {
vertical-align: middle;
}
button .icon > img {
width: 100%;
}
button .text {
font-size: 1.2em;
}

(more info)

Pseudo-element

Even +pseudo-element has a separate mixin and works just like the +element.

+mode('draft') // will be explained later

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

+pseudo-element('before')
content: ''



button {
display: inline-block;
}
button::before {
content: '';
}

(more info)

Mutations

When component has more different appearances, we call it a mutation.

The difference can be on the component root element or components sub-elements.

If element has more appearances, it has a +default appearance and other mutations.

(more info)

Default

When component has more mutations, the "default" mutation must be declared and should go first.

+mode('draft') // will be explained later

+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;
}

If no mutations, no default is needed:

+mode('draft') // will be explained later

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


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

(more info)

Variant

Variant is the basic type of the mutation. It defines other than default appearance of the component.

+mode('draft') // will be explained later

+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 same principle applies to sub-elements:

+mode('draft') // will be explained later

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

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

+element('.text')
+default
font-weight: 1.2em

+variant('.primary')
font-weight: 1.6em



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

button .text {
font-weight: 1.2em;
}
button.primary .text {
font-weight: 1.6em;
}

Important: note that the class/variant .primary was applied to the root element selector of the component in both cases (button.primary .text and not as button .text.primary).

(more info)

State

Mixin +state works exactly same as mixin +variant. The only difference is in semantics. But it can be combined together too.

You can find out more about difference between state and variant here.

+mode('draft') // will be explained later

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

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

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

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



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

button.primary {
background-color: green;
}
button.primary:hover {
background-color: white;
}

(more info)

Context

This one is VERY IMPORTANT and most often completely misunderstood and unrealized the substance and impact of this approach.

It is not even possible to cover the whole idea in this super quick fly-through but be sure not to underestimate it so please study this later: Context in depth.

+mode('draft') // will be explained later

+component('button')
+default
font-size: 1.5em

+context('.product')
font-size: 1.25em



button {
font-size: 1.5em;
}
.product button {
font-size: 1.25em;
}

As you can see it adds the context before the component selector. But this is only a very shallow explanation.

(more info)

Responsive

Mixin +responsive works similar to mixin +context. The main difference is in semantics and that you can use media queries.

+mode('draft')

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

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

+responsive('@media (max-width: 360px)')
display: flex



button {
display: inline-block;
background-color: grey;
}
html.mobile-portrait button {
display: block;
}
@media (max-width: 360px) {
button {
display: flex;
}
}

(more info)

Specificity

In SPOT CSS framework the CSS selector specificity problem is not a problem anymore. You can increase element level, class level or id level specificity or you can say what you want to override directly.

+mode('draft') // will be explained later

+component('button')
+default
display: inline-block
+add-class-specificity(1)
background-color: grey

+variant('.primary')
+override('.btn[type="submit"].primary')
background-color: green
color: black


button {
display: inline-block;
}
button:not(._) {
background-color: grey;
}

button.primary:not(._):not(._) {
background-color: green;
color: black;
}

(more info)

Mode

In all examples above we were using +mode('draft'). This is a special mode for prototyping. If you want to write something really fast a try if it works then activate this mode.

In draft mode you don't need to do/write certain things. The code can be shorter. That's the reason why it's used in all examples until now. You don't need to write/use:

  • element separators
  • section register
  • can't use aliases, because of absence register section
  • there is no need to use the +default mixin
  • some strict checks for structure are not evaluated and therefore no warnings when parsing SASS

Mode has to be set before (each) component because it's applied only for the following component.

Default mode is strict and it doesn't need to be declared (because it's default).

+mode('draft') // this is explained right here and right now

...

// +mode('strict') // you don't need to declare strict mode because it is a default

The following examples would be without the mode draft which means the strict mode.

(more info)

Separator

Each element must be preceded by a separator. It's a mixin of underscores (as many as you want) and the parser will yell at you with warning if you forget it (in strict mode).

+______ // this works
+______________ // this is ok
+________________________ // this is fine too
+____________________________________ // the length is up to you

It must be used before every +element and +pseudo-element.

It is used for visual perception where the start and the end of the css code of every element is and it proved to be a very useful (mandatory) mixin.

+component('button')

...

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

+____________________________
+pseudo-element('after')
width: 100%

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

Why it's useful and why it's worth it you can read in section Single place of element below.

But as you can see below it helps to fast scan the code and to orient in component sub-elements:

+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block
+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block
+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

The above example shows one very important thing - if you take any highlighted element block there is no other CSS code addressing that element outside of this single contiguous block.

(more info)

Register

In strict mode you have to register every +element and +pseudo-element and also every mutation of the component in special section "register" right after the component declaration.

+component('button')
+register
+variant('.primary')
+element('.icon')
+element('img')

+default
// code

+variant('.primary')
// code

+____________________
+element('.icon')
// code

+____________________
+element('img')
+default
// code

+variant('.primary')
// code







button {
/* code */
}
button.primary {
/* code */
}

button .icon {
/* code */
}

button img {
/* code */
}

button.primary img {
/* code */
}

The register section allows you (among other things) to declare a mutation for sub-element of the component (and not only for the root element) as you can see in the following example:

+component('button')
+register
+variant('.primary')
+element('.icon')
+element('img')
+state('.loading')

+default
// code

+variant('.primary')
// code

+____________________
+element('.icon')
// code

+____________________
+element('img')
+default
// code

+state('.loading')
// code








button {
/* code */
}
button.primary {
/* code */
}

button .icon {
/* code */
}

button img {
/* code */
}

button img.loading {
/* code */
}

(more info)

Aliases

Another benefit of using register mixin is the ability to declare aliases.

Alias must be enclosed in curly brackets: {alias name} and it have to be unique in component.

+component('{button}', 'button.btn')
+register
+state('{focused}', ':focus', '.focused')
+variant('{highlighted}', '.go01-flushed')
+pseudo-element('{caret}', 'after')

+default
// code

+state('{focused}')
// code

+__________________________
+pseudo-element('{caret}')
+default
// code

+variant('{highlighted}')
// code

...

(more info)

Only-for

There is no need to register tree-structural pseudo-classes. Just use the mixin +only-for.

+______________________________
+element('p')
+default
margin: 10px 0

+only-for(':first-child')
margin: 0


p {
margin: 10px 0;
}

p:first-child {
margin: 0
}

Or you can use the mixin +only-for for reusing the generic code.

Example of grouped mutations:

+register
+variant('.lorem')
+variant('.ipsum')

...

+variant('.lorem', '.ipsum')
+default
overflow: hidden
margin: 1em

+only-for('.lorem')
display: block

+only-for('.ipsum')
display: flex







.lorem, .ipsum {
overflow: hidden;
margin: 1em;
}

.lorem {
display: block;
}
.ipsum {
display: flex;
}


Example of exclusive mutations:

+register
+state('{collapsible}', '.expanded', '.collapsed')

...

+state('{collapsible}')
+default
overflow: hidden
margin: 1em

+only-for('.expanded')
display: block

+only-for('.collapsed')
display: flex






.expanded, .collapsed {
overflow: hidden;
margin: 1em;
}

.expanded {
display: block;
}
.collapsed {
display: flex;
}


Example of elements:

+____________________________________
+element('th', 'td')
+default
overflow: hidden
margin: 1em

+only-for('th')
color: white

+only-for('td')
color: grey


th, td {
overflow: hidden;
margin: 1em;
}

th {
color: white;
}
td {
color: grey;
}


Example of pseudo-elements:

+____________________________________
+pseudo-element('before', 'after')
+default
overflow: hidden
margin: 1em

+only-for('::before')
color: white

+only-for('::after')
color: grey


my-button::before, my-button::after {
overflow: hidden;
margin: 1em;
}

my-button::before {
color: white;
}
my-button::after {
color: grey;
}

(more info)

Single place of element

The name SPOT CSS as the abbreviation of "Single Place of Truth". That's the core idea behind this methodology: "Everything in a single spot".

It applies to all entities - component, element and mutation too:

+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block
+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block
+mode('draft')

+component('button.btn')
display: inline-block
color: #3432A1
line-height: 1.5em

+_________________________
+element('.icon')
+default
display: inline-block
color: #3432A1

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
+default
font-size: 1.2em
display: inline-block

+state(':hover')
vertical-align: middle
margin: 0.2em

+_________________________
+element('img')
+default
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

+_________________________
+element('.text')
+default
display: inline-block
color: #3432A1
line-height: 1.5em

+state(':hover')
vertical-align: middle
margin: 0.2em

+state('.pressed')
width: 100%
height: auto

+variant('.primary')
font-size: 1.2em
display: inline-block

There are few axioms that every SPOT CSS code must comply:

  • any specific element on the page is addressed by one component only (or none if not styled)

  • style of every component is written in one contiguous block (and there is no other place of additional style for this component) - as you can see in the first column of the example above.

  • style of every sub-element of component is written in one contiguous block (and there is no other place of additional style for this sub-element) - as you can see in the second column of the example above.

  • style of every mutation in any sub-element or component is written in one contiguous block (and there is an exception for this case but no other place of additional style out of this sub-element) - as you can see in the third column of the example above.

This topic "Single place of element" is very much intertwined with the context(s) topic. But that is beyond the scope of this quick start guide.

(more info)

Scratching the surface...

This was just scratching the surface to make you a picture about the SPOT CSS framework. But there is also a deeper theory behind this methodology.

If you want to know more, it's time to take a deeper dive into the tutorial or the full documentation.