Skip to content

Cascading Style Sheets Script Specification

boltgolt edited this page Mar 21, 2017 · 10 revisions

Second draft, 03-03-17

This page defines all aspects of the Cascading Style Sheets Script language, abbreviated to CSSS. CSSS builds upon the CSS syntax with new parts to allow server-side generating of HTML, complete with styling.

Table of contents


1 Control flow statements

Normally a script is executed from the top to the bottom, however, control flow statements can alter the flow of execution of the script. In CSSS, all control flow statements start with an @ symbol.

The if, elif and else blocks can also be used within elements, see below.

1.1 if statement

if statements only execute the code contained in their block if the expression within their parentheses evaluates to true. Their syntax is as follows:

@if (expression) {
    /* Some code */
}

The expression used has to return a boolean, but can otherwise be anything. For example:

@if (8 < 7) {
    /* Code entered here never gets run */
}

In this case, the code within the if block is not executed, as 8 < 7 results into false.

1.2 elif statement

elif statement has to be declared directly after an if (or other elif) statement's code block has closed. Very similar to an if statement, it only executes the other code in its block when the expression within its parentheses evaluates to true, but with an added requirement: All previous if or elif statement's expression must have evaluated to false.

@if (false) {
    /* Code that is never run */
}
@elif (true) {
    /* Code that is run */
}

1.3 else statement

The else statement's block of code is run when all the previous if (or elif) statements did not execute. Therefore it has to be directly below a code block of either one. else should be the last statement in an if-elif-else chain and can not be followed by an elif.

@if (false) {
    /* Code that is never run */
}
@else {
    /* Code that will run */
}

1.4 while statement

A while statement is the only way in CSSS to loop code. While the expression within its parentheses evaluates to true, the code in the code block will be run over and over again. while statements look quite similar to an if statement:

@while (true) {
    /* Code that will run forever, as the expression will always be true */
}

2 Variables

Variables allow the script to store and retrieve information while running. All variable names should start with -- (2 dashes) followed by alphanumeric characters or dashes, matching [a-zA-Z0-9-]. A valid name could be: --var-name

2.1 Writing/declaring a variable

Variables do not need to be declared in any way before being written to, they are always ready to go. Keep in mind that this isn't true for reading them. All writing statements should be closed with a semicolon.

2.1.1 Writing a number, CSS unit or string

Writing a number or CSS unit can be written directly like a CSS property.

--var-name: 1px;

Strings need to be contained in either double quotes ("content") or single quotes ('content').

--var-name: "string contents";

2.1.2 Writing an array

An array can be filled with any value (number, array, boolean, CSS unit or string) of any length. It has a syntax very similar to javascript. The values are separated by commas and the entire array is contained within square brackets ([]).

--var-name: [1, "string", 10vh];

Writing a value to a specific location in the array is also exactly the same as it is in javascript. The array index starts at 0, so accessing the first value will be done as such:

--var-name[0]: "new string";

To append a value to the end of the array, simply write to the -1 index of the array.

--var-name[-1]: "appended string";

2.2 Reading from a variable

To read from a variable simply mention its name anywhere you would normally enter a static value:

--var-name

Reading from an array is also quite simple if you know how to write to an array:

--var-name[1]

3 Calculations

In CSSS, all mathematical operations have to be done within a calc() block, similar to CSS. The exception to this rule are the parentheses of some control flow statements, which also act as calc() blocks.

Most of the syntax here is taken directly from javascript, so anyone familiar with web technologies can learn them quickly.

3.1 Arithmetic operations

Arithmetic operations take 2 values and perform an operation, after which only 1 value remains. Values are always read from the left to the right, regardless of operator type. The 4 types of arithmetic operations supported are addition, subtraction, multiplication, division, modulo and exponentiation.

Operator Type
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulo
^ Exponentiation

Note, however, that strings only support the addition operator. When adding any non-string value to a string the value will be converted to a string and appended to the string.

An example of an arithmetic operation would be:

calc(40px + 60px / 2)

Of which the result would be 50px. Combining values with different units is not a problem, the calc() block will be passed to the output CSS for the browser to resolve.

3.2 Comparison operators

Comparison operators take 2 values and perform an operation, after which only a single boolean remains. There should only be 1 comparison operator per block, but you can start a new parenthesis block if needed. So for example, (false == 8 > 7) would throw an error, while (false == (8 > 7)) will execute normally.

Operator Type
== Equal to
!= Not equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to

The equal to (==) and not equal to (!=) comparison operators will compare any type of value, while all other operators only accept numbers.

Remember that the results of a logical operation should never be passed to a property, as they always return a boolean and no CSS property accepts booleans at this time. An example of using a logical operator could be:

calc(30vh >= 70vw)

Of which the result would be false. Note how only the numbers are compared in this case, the units do no matter.

3.3 Logical operators

Logical operators take 2 booleans and return a single boolean. There can be multiple logical operators within a single calc() block if needed.

Operator Type
&& And
|| Or
! Not

Just like logical operations, the results of a logical operation should never be passed to a property, as they always return a boolean. An example of using a logical operator could be:

calc(!true || false)

Which would return false.

4 Elements

Elements allow scripts to add HTML elements to the output HTML. They consist of a CSS selector with a block of CSS properties.

New elements are always added after the last element in the body tag. All other HTML, like the doctype and head element, will be added automatically. The syntax is as follows:

selector {
    property: value;
}

4.1 Element selectors

The selector defines the type of element that will be added to the HTML. The selector always starts with the tag name, but all other parts can be added in any order.

4.1.1 Tag names

This is the name of the HTML5 tag and should start with a letter ([a-zA-Z]), optionally followed by alphanumeric characters ([a-zA-Z0-9]). An example of this would be:

div

4.1.2 IDs

Element IDs are added to the HTML element by adding a hashtag followed by alphanumeric characters, dashes or underscores ([a-zA-Z0-9_-]). An example of an ID added to a div tag selector would be:

div#id1

IDs should be unique for the entire document, and should therefore never be used in a loop.

4.1.3 Classes

Element classes are added to the HTML element by adding a dot (.) followed by alphanumeric characters, dashes or underscores ([a-zA-Z0-9_-]). An example of an ID added to a div tag selector would be:

div.class1

To add another class to the element, simply add another dot:

div.class1.class2

4.1.4 Attributes

Adding attributes is a little more complicated than the others, they start with an opening bracket ([) followed by the attribute name. The name can contain alphanumeric characters, dashes or underscores ([a-zA-Z0-9_-]). After the name should be a single equality sign (=), followed by the attribute value as a string, or a calc() block that returns a string. Finally, the whole thing ends with a closing bracket (]).

In short the syntax comes down to [name="value"]. For example:

div[data-size="3"]

Elements can have multiple attributes, to add another one simply repeat the block:

div[data-size="3"][data-name="kees"]

There is no requirement to start a custom attribute with the data- prefix, but it is encouraged.

4.2 Element properties

An element property sets the CSS property for the HTML element. This should start with the property name, which should only contain letters and dashes ([a-zA-Z-]), followed by a colon (:). After that follows the property value, which can be either a number, string, value (such as a color) or calc() block. The property terminates at the final semicolon (;).

In short, the syntax comes down to property: value;. For example:

border-width: 2px;

4.2.1 The content property

The content property works differently in CSSS, as it can be added to any element. Use it to write plain text to the document.

4.3 Nesting elements

Elements can be nested within other elements, which will make it their children in the DOM. Simply add them somewhere within the block of the parent element.

For example, take the following example:

h2 {
    content: "All your base are belong to ";
    
    strong {
        content: "us";
    }
}

Which will output the following HTML:

<h2>All your base are belong to <strong>us</strong></h2>

5 Miscellaneous

5.1 Requiring another file

To import other scripts into the current script, use the @require keyword followed by the name and path of the script in single or double quotes (['"]) and terminated with a semicolon (;). For example:

@require "scripts/header.csss";

The path should always be relative to the file calling it.

5.2 Comments

Comments work exactly the same as they do in CSS, they open with /* and close with */. For example:

/* I'm a comment */

5.3 CSS prefixes

Any CSS property that is not fully supported yet in some (older) browsers and need a prefix to work correctly will be added automatically by the interpreter.

For example, take the animation property. For most browsers this property will work out of the box, but some older android browsers require the -webkit- prefix, which will be added automatically.