Summary Files Commits Branches @commit @diff @stats
AgeCommit messageAuthorLinesSHA
2023-11-23[tests] Added test for appending inner definition and closing braces next to ... HEAD main
 Syndamia Verified
-0/+32a00471f
2023-11-23[csmap] No more removal of leading tabulation
 Syndamia Verified
-11/+05c659c2
2023-11-23[csmap] Removed comments
 Syndamia Verified
-5/+0287831e
[...]
 
 
Clone
https://git.syndamia.com/archive/csma
git@syndamia.com:archive/csma
 
BranchAge
main3 years
NameSize
.vim68 Blog stats plain
LICENSE34.3 KiBlog stats plain blame
README.md5.0 KiBlog stats plain blame
csmap.awk4.0 KiBlog stats plain blame
example.csma446 Blog stats plain blame
tests.csma2.3 KiBlog stats plain blame

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).