High Level CSS preprocessor
Makefile Batchfile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
hss
Makefile
README.md
build.bat
hss.sln
hss.vcproj

README.md

HSS is tool that extends the CSS syntax with powerful features such as variables and nested blocks.

Usage

First you should compile them, it depends on Neko, but if you already have the haxe, then you will no longer need to download Neko.

If you are on Windows platform and don't have the gun make, just run build.bat

Or Download HSS and put it in some place where it can be run from the commandline :

TIP: On OSX and Linux you will have to enable the file to be executable after unzipping, by running the command chmod +x hss

You can then rename you .css file with the extension .hss. Since HSS extends the CSS syntax, it means that every valid CSS valid is a valid HSS file as well.

You can then compile your HSS file into the corresponding CSS file by running the hss command :

hss myfile.hss

You can specify an output directory with -output <dir> if you need it to be different than the hss file one.

TIP: Since every time the HSS file is modified the CSS file needs to be regenerated, it's better if the website itself automatically runs HSS when it notices that the HSS file has changed, and displays errors if any occurs.

Syntax

HSS is a CSS compiler which supports valid CSS syntax, so for every error that occurs during the parsing of the HSS file, it will display and error indicating at which file and which line the error occurred.

HSS also enforce additional syntax rules. While this is valid CSS, the following is not HSS-valid since there is a missing semicolon at the end of the color value :

pre {
    color : #FF0000
}

In that case, you will get an error telling :

myfile.hss:3: Unexpected '}' maybe missing ; Fix all the errors and HSS will then be able to generate the corresponding CSS file.

Property Variables

HSS adds property variables to the CSS syntax.

You can declare a variable with the keyword var and use it in the HSS file by prefixing the variable name with a dollar :

var mycolor = #1111AA;
var myfont = "Trebuchet MS", Arial, sans-serif;

body {
    color : $mycolor;
    font : $myfont;
}

Variables are a very good way to avoid replacing everything in a CSS file every time you want to change a single color value. It also helps designers to remember and easily locate the main colors that are used in a given website.

Block Variables

You can also declare variables that will declare several properties at the same time :

var nomargin = { margin : 0px; padding : 0px; }

pre {
    $nomargin;
    color : #FF0000;
}

Block variables are very useful to share some "behaviors" between unrelated rules. They can be used to improve the way CSS files are organized and makes it much more easy to test style-changes.

The Block Variables also has function features. Since 1.5.2. Note that it's uses semicolon(;) as the parameter separator. because the comma(,) is a valid CSS property value.

var nomargin = { margin : $margin; padding : $padding;}
var pad-4 = 4px;
pre {
  $nomargin(margin = 16 + 2px; padding = -$pad-4); // (name = any css value; ...)
  color : #FF0000;
}

the output:

pre {
  margin: 18px;
  padding: -4px;
  color: #FF0000;
}

Note that the "Block Variables" and "Property Variables" belong to different spaces.

var alpha = {            // Definition a "Block Variables".
  opacity: $alpha;       // Reference to "Property Variables", NOT "Block Variables"
  filter: alpha(opacity=int($alpha*100));  // IE filter and the "int(float)" is a hss function.
  // $alpha;             // It's "Block Variables", but hss will report an error to avoid entering the dead loop.
}

.alpha-80 {
  $alpha(alpha = 0.8);   // use it.
}

var ref = $alpha;        // The right side of the expr will be parsed as "Property Var",
                         // So you can't refer to "Block Variables"

the variables scope

if the name of the "Block Variables" starts with _ then the internal variables will be exported to the current scope.

var vars =  { var color = black;}
.without {
  var color = red;
  $vars();
  color: $color;
}

var _vars = { var color = black;}  // starts with "_"
.with {
  var color = red;
  $_vars();
  color: $color;
}

output:

.without {
  color: red;
}
.with {
  color: black;
}

Nested Blocks

One of the things that are the most annoying with CSS is when you want to avoid class-names clashing. For instance if you declare the following :

.name { font-weight : bold; }

Then there is an high possibility that class="name" is used in several different parts of the website, and needs to be styled differently depending on the case.

In order to avoid these problems, it's often needed to specify the context in which is class occurs, which often to the following declarations :

.faq {
    color : #BC683C;
}

.faq .form {
    width : 100px;
}

.faq .form textarea {
    width : 100%;
    height : 80px;
}

.faq .form .name {
    font-weight : bold;
}

.faq ul {
    margin-left : 20px;
    margin-bottom : 20px;
}

In that CSS example, we can see how the natural nested XHTML structure has been "flattened", and how we need to specify before each block the complete context in which the class occurs.

HSS allows then a much more natural way of declaring the same thing, which is called nested blocks. Here's the previous example rewritten by using nested blocks :

.faq {
    color : #BC683C;
    .form {
        width : 100px;
        textarea {
            width : 100%;
            height : 80px;
        }
        .name {
            font-weight : bold;
        }
    }
    ul {
        margin-left : 20px;
        margin-bottom : 20px;
    }
}

As you can see, such nested structure provides much more readability and maintainability than flatten one. Using nested blocks is very good way to express complex structures and avoid class name clashing.

more complex:

a {
    var color = #0366d6;
    var margin = 4px;

    color: #666;
    &.disabled, &:disabled {
        color: lighten($color, 20%);   // color function: darken/lighten/saturate/desaturate/invert
    }
    &:hover > li {
        float: left;
    }
    > span, ~ i {
        font-size: 80%;
    }
    + a {
        margin-left: -$margin;
    }
    &:hover::after {
        content: " \f2b9 ";
    }
    &[href] {
        color: $color;
    }
    &:not([href]):nth-child(2n+1) {
        text-decoration: none;
    }
}

generated css:

a {
    color: #666;
}
a.disabled, a:disabled {
    color: #439AFC;
}
a:hover > li {
    float: left;
}
a > span, a ~ i {
    font-size: 80%;
}
a + a {
    margin-left: -4px;
}
a:hover::after {
    content: " \f2b9 ";
}
a[href] {
    color: #0366d6;
}
a:not([href]):nth-child(2n+1) {
    text-decoration: none;
}

Condition

Support a simple conditional statement that is to use && and || to join exprs, and the left of the expr must be "Property Variable" or -Dname[=value](spaces are not allowed in the definetion) from Console.

var polyfill = { background-color: blue; }
var ie8 = 1;                      // define property var or you can pass "-Die8" from Console
.one {
  $ie8 && $polyfill;              // ifdef $ie8 then $polyfill
}

var alpha = {
  opacity: $alpha / 100.;
  filter: alpha(opacity = $alpha);
}
span {
  $flag || $alpha(alpha = 80);    // if not def $flag then $alpha
}

HSS will not detect the specific value of the left(Property) variable, only determine whether it is defined, and the right side can also be the following values:

$url && @import($url);   // @import, Note: @import only works in top level

.two {
  var blue = #00e;

  $blue && color: $blue; // A CSS Attribute: Value;

  $flags || {            // A Braces Block then all internal exprs will be moved to the current scope
    var blue = #00f;
    &:hover {
      color: $blue;
    }
  }

  $ie8 || $ie9 && {      // The left can be multiple conditions, but parentheses are not supported
    border: 0;
  }
}

the output is:

.two {
  color: #00e;
}
.two:hover {
  color: #00f;
}

Comments

There are two kind of comments possible in HSS, which are the same used in popular syntax such as C/Java. The /* ... */ comment is a multiline comment which is already part of CSS and the // .... comment is used for single-line comment.

p {
//  color : red;
    font-weight : bold;
/*  margin : 0px;
    padding : 0px; */
}

All comments are removed from the CSS output.

CSS Validation

Apart from validating the syntax and providing additional things, HSS also checks the validity of the CSS properties values. For instance the following will not be allowed because of the double 't' :

pre { font-weightt : bold; }

The following also will not be allowed by 'bald' is not a valid value for the property font-weight :

pre { font-weight : bald; }

HSS also enforces some good CSS practices such as :

  • properties declarations must always end with a semicolon (;)
  • URLs must be quoted : don't do url(img.gif) but please use url('img.gif') instead.
  • the background property has a fixed order, which is the following :
  • background : [color] [url] [repeat] [scroll|fixed] [horiz.] [vert.]

Notes

  • HSS does not support any ratio values such as 16px/1.2, because it will be calculated and the result is not what you expect.

  • HSS will try to detect if @media query is valid, but not all the syntax, so in some cases you should use quotes to skip detection

    // Only supports Property Variables in value of the feature/attribute
    var narrow_width = 767px;
    @media only screen and (max-width : $narrow_width) {}
    
    // Hss does not support any ratio value, so you need use quotes to skip detection in media query.
    @media (min-aspect-ratio: "1/1") {}
    
    // quotes for some deprecated type
    @media "tv", "handheld" {}
    
    // You can use quotes almost everywhere
    @media "screen and (min-width: 30em) and (orientation: landscape)" {}
    @media screen and (min-width: 30em) "and (orientation: landscape)" {}
    @media screen "and (min-width: 30em)" and (orientation: landscape) {}

CSS Rules

The whole CSS properties rules that are used to check the property value correctness are listed in the Rules.nml file of the HSS sources. You might want to modify them for your own needs.

Selectors

Here's the list of CSS selectors with their HSS support status, see here for the corresponding explanations :

E : supported
E F : supported
E > F : supported
E + F : supported
E ~ F : supported
DIV.warning : supported
E#myid : supported
E:first-child, E:link, E:hover and other CSS2 and 3 pseudo-classes selectors are supported
E[foo], E[foo=value], E[foo|=value], E[foo~=value], E[foo^=value], E[foo$=value], E[foo*=value] : supported

supported pseudo-classes selectors, Other selectors maybe not supported, but can be used with the CSS function :

.page CSS("h1:placeholder") {
    color : red
}

IE hacks

It's sometimes useful to use non-standard CSS properties, in particular for various IE-specific things. HSS adds a specific command for doing that. Here's a small example how it can be used :

.image {
    my-special-property : CSS("some specific value");
}

In that case, this will simply output the property in the CSS file without checking that it's defined in the CSS standard or that the value is correct.

Operations

It is possible to perform some operations between values :

var scale = 3;
.big {
    width : 50px + 20px;
    height : 30px * $scale;
    color : #FF0000 * 0.7;
    line-height: 120 / 100.; // Important: explicitly declare a float if you want to get a float value
}

Operations between two different units (for instance 50px + 3em) are not allowed.

Hacks Support

  • color : rgba(r,g,b,a); background-color : rgba(r,g,b,a) : will add a solid color default value for browsers which don't support rgba

  • hss-width and hss-height : will generate width and height from which will be subtracted the padding and border values declared in the current block.

  • You can also add @include('some css string') either at the top level or instead of an attribute, this will include raw CSS string in the output, prefixed with the hierarchy classes if any New in 1.4

  • @import("rel_path/to/myhss") can be used to import another hss file, or use @import("rel_path/to/somelib.css") to inject a CSS file directly. Duplicate imported files will be ignored.

    @import("path/to/_vars") // if file name starts with "_" the variables of the file will be exported to current file.
    @import("path/to/reset")
  • hss functions:

    darken, lighten, saturate, desaturate, invert: for color adjustment similar to scss/less, but only accept #RRGGBB and rgb(int,int,int)

    body {
      var gray = #999;
      border-color: darken(rgb(255, 255, 255), 5%);
      color: lighten(invert($gray * 0.5), 5%);
    }

    int(float): convert float to int, you will rarely use it.

  • embed("path/to/image"): for embedding small(less than 24KB) image(png/jpg/gif) as data:image/xxx;base64.

    .logo {
      background-image: embed("logo.png"); // the png is relative to current .hss file.
    }

Credits

The HSS software was developed by Nicolas Cannasse for Motion-Twin.