aboutsummaryrefslogtreecommitdiff

csma

csma is a tiny superset of CSS, with the goal of making rules more organizeable and modular than ever.

How to use

Currently the only preprocessor is "preproc.awk":

awk -f preproc.awk styles.csma styles.csma

Remember to pass the csma file twice

Language reference

The syntactical additions to CSS are two:

  • macro name
  • macro definition

The concept is inspired from C-like macros. There is no CSS modification, you can only really move around rules (and text).

(Standalone) Macro name

A macro name is a string in the form:

<LETTERS>

where LETTERS can be any combination and length of letters, excluding >, & and newlines.

A macro name can be placed almost anywhere in a CSS file and it will be replaced by some value.

Macro definition

That value is specified via macro definitions, a macro name followed by curly braces:

<NAME> {
    VALUE
}

Now, every time you have a standalone <NAME>, it will be replaced with VALUE. The curly brace can be anywhere after the macro name, even after multiple new lines, but there must only be blank characters between them.

Let's look at an example:

<Number>
<Number> { 5 }

The resulting file will be:

5

As you can see, the definitions are parsed before (standalone) macro names, so it doesn't matter if the standalone name is before or after the definition.

Multiple definitions with the same macro name are concatenated, so with:

<Number>
<Number> { 5 }
<Number> { 6 }

you'll get:

56

Newlines inner empty lines are preserved, so this:

<Number>
<Number> {

  5

}
<Number> {
  6

}

results into:

5

6

Inner macro definitions

You are also allowed to put definitions inside other definitions:

<Color> {
  <Text> { black }
  <Body> { white }
}

Nested macro's name

Inner definitions come with a trick: their name is accessed by prepending their parent and "/". So, this won't result in anyting:

<Color> {
  <Text> { black }
  <Body> { white }
}
<Text>

however this will result in the word "black":

<Color> {
  <Text> { black }
  <Body> { white }
}
<Colors/Text>

It's important to note that this changes the entire name of the macro and every macro is globally accessible. There is no actual tree-like structure behind it, so the syntax:

<A> {
  <B1> { ... }
  <B2> { ... }
  ...
  <BN> { ... }
}

is (almost) equivalent to:

<A> {
}
<A/B1> { ... }
<A/B2> { ... }
...
<A/BN> { ... }

You can nest as much as you like, and for every paren't you get another "name/" prepended, in this:

<A> {
  <B> {
    <C> {
      89
    }
  }
}

you have three macros: <A>, <A/B> and <A/B/C>.

Nested macro replacement

Nested macro definitions are also automatically replaced in their parent. So here:

<A> {
  rule1
  <B> {
    rule2
  }
}

<A>

<A/B>

you'll get:

rule1
rule2

rule2

So nested definitions:

<A> {
  <B1> { ... }
  <B2> { ... }
  ...
  <BN> { ... }
}

are "spiritually" equivalent to:

<A> {
  <B1>
  <B1> { ... }
  <B2>
  <B2> { ... }
  ...
  <BN>
  <BN> { ... }
}

But only when actually nested! So if we rewrite the example from above like:

<A> {
  rule1
}
<A/B> {
  rule2
}

<A>

<A/B>

the result will be:

rule1

rule2

Nested macro concatenation

Since multiple definitions are concatenated, there is no problem in doing:

<A/B>
<A> {
  <B> {}
}
<A/B> { 1 }
<A> {
  <B> { 5 }
}

the result will be:

15

Inner standalone macro names

Replacement of standalone macro names also happens inside definitions. This:

<A>
<A> {
  <B>
}
<B> {
  rule
}

results into:

rule

This also allows us to kinda do the nested macro replacement without actually nesting the entire macro definition:

<A> {
  rule1
  <A/B>
}
<A/B> {
  rule2
}

<A>

<A/B>

the result is:

rule1
rule2

rule2

How to use effectively in CSS

Image the following scenario, you have a website with:

  • header with website logo, links to pages and a hidden menu bar, for mobile devices
  • page with text and picture contents
  • image reel
  • footer with social links, a map with your business address and disclaimers

The CSS rules can stack up very quickly, and it can be difficult to maintain. One way in which you can use CSMA is by representing your site structure with different macros and dividing everything into them:

<Page>

<Page> {
  body { ... }

  <Page/Header>
  <Page/Contents>
  <Page/Footer>
}

<Page/Header> {
  header { ... }

  <Link> {
    .header-link {
      ...
    }
    .header-link:hover() {
      ...
    }
  }

  <Logo> {
    .header-logo {
      ...
    }
  }
}

<Page/Contents> {
  article {
    ...
  }
  <Image reel>
  a {
    ...
  }
  b {
    ...
  }
}

<Page/Footer> {
  ...
}

But this is just an example.

You may want to have even more macros that mostly contain other macros (like with <Page>). This way you can very easily turn on or off a feature, and rules are easily discoverable (for example, try finding the rule for the header logo).