Description
CSS was a huge step forward in styling websites. It’s much simpler to be able to define styles in one place, and have them applied to the whole website. It’s much closer to the DRY philosophy that good programmers try to follow. Unfortunately, within a .css file, there’s often unnecessary repetition and redundancy (see what I did there?). DSS tries to fix that.
DSS is a style sheet preprocessor. It’s input is a CSS-like file with extra DSS “directives” (at-rules) to define classes (not the html kind) and constant definitions, or include other style sheets. It also supports calculated values and conditional rules.
DSS is written in Java, and uses the Coco/R compiler generator to parse its input. It’s licensed under the MIT License, so you can use it pretty much however you want to.
Download
Documentation
Hahaha… you weren’t really expecting documentation were you? OK, it is on the TODO list. For now, here’s an example file that shows the basic usage.
@define { /* Define some constants */
foreColor: black;
backColor: white;
width: 42%;
}
@class error<size; style:solid> { /* Define an error class that rules can
"apply". Any declarations inside the class
will be included in the ruleset. Classes
are similar to dynamic mixins in less. They
can have parameters (with optional default
values) that are referenced using
param(name) */
border: param(size) param(style) #800000;
background-color: #F00;
font-weight: bold;
}
@include url(layout.dss); /* Include and process layout.dss. Like @import, but
it's processed by DSS and the result is inserted
into the output. */
html {
color: const(foreColor); /* Reference the named constants */
background-color: @backColor; /* Alternate syntax for constants or class
parameters (parameters have priority) */
}
@media print {
@class error { /* Override the error class inside the @media rule */
apply: error<size:1pt>; /* Extend the original error class */
background-color: white; /* Override the original border style */
}
@define global {
width: 42px; /* "global" forces the constants to be available in the
global scope (but only after this point in the file),
not just inside the "@media print" rule. */
}
div.error {
apply: error; /* We overrode the first error class with a new one that
doesn't need any arguments. */
margin: 1em 0;
}
span.error {
apply: error;
}
}
div.error {
apply: error<size: 1px; style: dotted>; /* This is the first error
class, since we are outside the
"@media print" rule */
margin: 1em 0;
}
span.error {
apply: error<1px>; /* Still the first error class of course. Since
the "style" parameter has a default value, we can skip
it. Arguments can be passed by position or by name. */
}
@if (ie5 || ie6) { /* ie6 would be a constant defined by the program (see the -d
option). Anything except "0" (any unit), "false",
or "no" is true. "||" means "OR", && (AND) "!" (NOT),
and "^" (XOR) are also supported. */
@class has-layout {
zoom: 1;
}
}
@else { /* Yay! */
@class has-layout {
}
}
.box { /* a 100 pixel box (including padding/border) */
@define {
width: 100px;
pad: 10px;
border: 1px;
}
border: const(border) solid;
padding: const(pad);
/* Calculate the width based on the outside width, padding, and border */
width: @calc(const(width) - 2 * const(pad) - 2 * const(border));
/* This next line is an equivalent, but shorter version: */
width: [@width - 2 * @pad - 2 * @border];
p { /* Rule sets can nest. Selectors can start with a '>', '+', or '~' for
child, next sibling, and sibling relationships. The leading
combinator applies to each sub-selector, for example:
p {
> a, span {...}
}
would expand to:
p > a, p > span {...}
NOT
p > a, p span {...}
so you don't need to repeat the '>' symbol.
*/
margin: 0;
padding: prop(margin); /* Set the padding to be the same as the margin */
}
a {
text-decoration: none;
&:hover { /* Use "&" as a placeholder for the parent selector (a in this
case) to squeeze selectors together. Just ":hover" would
default to the descendant selector ("a :hover") which probably
isn't what you want.
*/
text-decoration: underline;
}
}
}
Usage
Although DSS is intended to be used as a library, it can also be run from a command line.
The basic usage is:
java -jar path/to/dss.jar /path/to/dss/file.dss
Without any additional arguments, it will print the resulting CSS file to stdout. You can also specify an output file, to save directly to another file.
The file path can also be a URL. URLs must be absolute (including “http:”, “file:”, etc.).
Options
- -v (--version)
- Show version information and exit.
<dt><kbd>--help</kbd></dt>
<dd>Show help text and exit.</dd>
<dt><kbd>-c</kbd> (<kbd>--compress</kbd>)</dt>
<dd>Compress the CSS output. This option removes unnecessary whitespace from the output. In the future it may optimize other things, like converting declarations to their short-hand forms.</dd>
<dt><kbd>-d</kbd> (<kbd>--define</kbd>) <var>definition</var></dt>
<dd>Define a constant in the global namespace. The syntax is exactly the same as a CSS property, but without the semicolon, i.e. “<code>property-name: value...</code>“. You can have as many definitions as you want (and the maximum command-line length allows, of course).</dd>
<dt><kbd>-o</kbd> <var>output</var></dt>
<dd>File to save the output to.</dd>
<dt><kbd>-w</kbd> (<kbd>--watch</kbd>)</dt>
<dd>Keep DSS running and automatically re-process the file when it changes.</dd>
<dt><kbd>--debug</kbd></dt>
<dd>Keep the DSS directives in the output. This is mostly for my use in development to make sure everything is parsed correctly.</dd>
<dt><kbd>-t</kbd> (<kbd>--test</kbd>)</dt>
<dd>Run a series of tests. Instead of the normal file argument, you should give it a directory containing .dss files, and corresponding .css files with the expected output. For example, if the directory contains a “test.dss” file, it should also have a “test.css” file with the exact (byte for byte) output expected from processing “test.dss”.</dd>
<dt><kbd>--color</kbd></dt>
<dd>Color-code the results from the self-test. The output uses ANSI escape codes, which your console should support.</dd>