JaxServer Stylesheets (file extension .jxss) is a dialect of cascading stylesheets which is compiled it into JavaScript code and outputs processed CSS code. Support for this format has been transparently integrated into JaxServer. JXSS was inspired by SASS, but diverges greatly in syntax and the way it is processed. By compiling into JavaScript, all of the capabilities of the JavaScript language can be used within a stylesheet which provides for power and flexibility within an environment that will be familiar to anyone who uses both CSS and JavaScript regularly.

JXSS makes developing complex stylesheets easier by providing:

JaxServer has seamless support for JXSS. All .jxss files are served as mime type text/css. In JaxServer's development mode, JXSS is dynamically processed. But in production mode, requests to JXSS files are transparently routed to the pre-compiled, cached version of the CSS output, and served as any other CSS file would be. Therefore developing stylesheets with JXSS has no performance disadantages, and provides many important advantages for code reuse and simplification.

CSS Compatibility

Effort has been made to make JXSS syntax largely compatible with CSS. The JXSS preprocessor performs pattern matching and interpretation to convert CSS code into JavaScript. For example, the following is both valid CSS and JXSS:

P {
	padding: 20px;
	background-color: #eee;
}

The JXSS preprocessor compiles that CSS code into the following JavaScript code:

jxss("P",{
"padding" : "20px",
"background-color" : "#eee"
});

Advanced developers can develop directly against the jxss() function if they wish. But the CSS compatibility mode is preferred for readability and writability.

The JavaScript evaluatation stage allows for some powerful new capabilities. CSS values can now be set by JavaScript variables:

var p = 20;
var c = "#eee";

P {
	padding: p;
	background-color: c;
}

The CSS generator sometimes makes assumptions about when to convert numbers into pixel units. The padding value in the previous example will output "20px".

All SVG color values are predefined allowing for universal use of familiar color names like black, white, pink etc.

P {
	color : gold;
	background-color: navy;
}

Many commonly used CSS values have been predefined as strings equal to themselves (eg. var center = "center"):

left right center top bottom justify both auto intrinsic bottomRight bottomLeft topRight topLeft thick thin medium light dark baseline textTop middle textBottom table tableRow tableCell tableCaption tableColumn tableColumnGroup tableFooterGroup tableHeaderGroup tableRowGroup block box inherit visible collapse hidden inline inlineBlock inlineTable listItem runIn relative fixed circle square ellipse none transparent normal bold italic underline nowrap noRepeat repeatX repeatY repeat solid dotted dashed groove ridge inset outset closestSide closestCorner farthestSide farthestCorner contain cover serif sansSerif Arial Helvetica Georgia Impact Lucida Tahoma Verdana Geneva Symbol Palatino Webdings Wingdings

It is through this mechanism that CSS like the following is valid in JXSS:

P {
	vertical-align: middle;
	font-family: Lucida;
}

CSS Incompatibilities

The predefined colors and values are not a complete list of valid CSS values. In cases where a value is needed but is not defined, use a JavaScript string to surround the value:

P {
	background: "unknownproperty";
}

The minus operator is used in many CSS properties and JXSS uses this to assist in CSS compatibility preprocessing, but sometimes it causes problems.

var x = 10;
var y = 7;
P {
	margin : x-y;
}

It is expected that a margin:3 will be printed, but in this situation JXSS will output:

P {
	margin : x-y
}

JXSS pattern matches for word-word, so it believes x-y is a CSS value. To force "JavaScript-mode", either put spaces between variables, or wrap values in braces:

P {
	margin : (x-y)
	// margin : x - y
}

Quotes surrounding a value will force it to become a JavaScript string:

P {
	margin : "x-y"
}

Debugging

JaxServer provides a development debugging mode to help find where errors or CSS/JXSS incompatibilities exist.

The following will produce a JXSS Runtime Error:

var p = 20;
var c = "#eee";

P {
	padding: p;
	background-color: c + unknownvalue;
}

When examining the JaxServer error it will highlight the line where the error occured:

Runtime errors are relatively easy to debug because an exact line number is given. But sometimes a JXSS Compile Error is caused by invalid JavaScript. These are more difficult to debug because exact line numbers are not available. For now, trial and error, by commenting out blocks of JXSS may be necessary to find the source of compile errors.

Functions

JavaScript functions can be used. JXSS includes many built-in functions to assist in CSS compatibility. For example, it includes a rgb() function which computes the hexadecimal value of a color:

P {
	color: rgb(255,40,20);
}

In addition to the built-in functions, custom functions can be defined directly in JXSS code:

function getPadding(margin) {
	return margin + 2;
}

var c = rgb(238,238,238);

P {
	padding: getPadding(1);
	background-color: c;
}

Inline Functions

Anonymous functions can embedded inline with CSS properties:

function getPadding(margin) {
	return margin + 2;
}

P {
	padding: (function() {
		return getPadding(1);
	}());
	background-color: (function() {
		return rgb(238,238,238);
	}());
}

Built-in Functions

rgb( red, green, blue ) - returns color string from the given red, green, blue values, or an RGB array

rgb(0,0,0) // returns "#000"
rgb(102,74,157) // returns "#664A9D"
rgb([102,74,157]) // returns "#664A9D"

rgba( red, green, blue, alpha ) - returns rgba() string

rgba(0,0,0, 0.5) // returns "rgba(0,0,0,0.5)"

alpha( color, opacity ) - adds an alpha value to a given color string

alpha("#000", 0.5) // returns "rgba(0,0,0,0.5)"
alpha("#000", null) // returns "#000"
alpha(rgb(100,50,200),0.7) // returns "rgba(100,50,200,0.7)"

hex2rgb( hex ) - returns RGB array of a hexidecimal color

hex2rgb("#664A9D") // returns [102,74,157]

rgb2hex( colorArray ) - returns hexidecimal string from RGB array

rgb2hex([102,74,157]) // returns "#664A9D"

color2hex( colorString ) - returns hexidecimal string from color string or array

color2hex("#664A9D") // returns "#664A9D"
color2hex(rgb(102,74,157)) // returns "#664A9D"
color2hex(rgba(0,0,0,0.5)) // returns "#664A9D"
color2hex([102,74,157]) // returns "#664A9D"

color2rgb( color ) - returns RGB array (including alpha) from color string

color2rgb("#000") // returns [0,0,0]
color2rgb("#664A9D") // returns [102,74,157]
color2rgb(rgb(102,74,157)) // returns [102,74,157]
color2rgb(rgba(0,0,0,0.5)) // returns [0,0,0,0.5] (alpha is preserved)
color2rgb([102,74,157]) // returns [102,74,157]

url( u ) - returns "url()" as a string for CSS compatibility

url("/path/to/image.png")  // returns "url(\"/path/to/image.png\")"

// useful for variables
var path = "/path/to/image.png"
url(path) // returns "url(\"/path/to/image.png\")"

dataURI( realPath ) - returns base64 encoded data-uri of the file

dataURI(__dirname+'/image.png') // returns "data:image/png;base64,ihEU0KGgN0KGgAgA...."
dataURI('image.png') // defaults to current directory

hue( color, hue ) - resets the hue of the given color

hue('#f00',0.01)  // returns "#FF0F00"

hsl( hue, saturation, lightness ) - returns the hsl() color string

hsl(100, 50, 50) // returns "hsl(100deg,50%,50%)"
hsl('100deg', '50%', '50%') // returns "hsl(100deg,50%,50%)"

hsla( hue, saturation, lightness, alpha ) - returns the hsla() color string

hsla(100, 50, 50, 0.5) // returns "hsl(100deg,50%,50%,0.5)"
hsla('100deg', '50%', '50%', 0.5) // returns "hsl(100deg,50%,50%,0.5)"

hslx( hue, saturation, lightness, alpha ) - normalized version of hsl/hsla()

hslx(0.3, 0.5, 0.3) // returns "hsl(108deg,50%,30%)"
hslx(0.3, 0.5, 0.3, 0.5) // returns "hsla(108deg,50%,30%,0.5)"

saturation( color, saturation ) - resets the saturation of the given color

saturation(rgb(180,0,0),0)  // returns "#5A5A5A"
saturation('#f00',0.5)	  // returns "#BF4040"
saturation(rgba(100,50,200,0.5),1)   // returns "rgba(83,0,250,0.5)"

lightness( color, lightness ) - resets the lightness of the given color

lightness(rgb(180,20,50),0)  // returns "#000"
lightness(rgba(180,20,50,0.4),0.5)  // returns "rgba(229,26,64,0.4)"
lightness('#ff7a20',1)  // returns "#FFF"

getAlpha( color ) - returns the alpha channel value of the given color

getAlpha('#000') // returns null
getAlpha(rgb(100,0,50)) // returns null
getAlpha(rgba(100,0,50,0.4)) // returns 0.4
getAlpha(alpha('#f00',0.8)) // returns 0.8

getHue( color ) - returns normalized hue value of the given color (value returned is between 0 and 1)

getHue(rgb(100,0,50)) // returns 0.9166666666666666
getHue(rgb(20,20,50)) // returns 0.6666666666666666

getSaturation( color ) - returns normalized saturation value of the given color (value returned is between 0 and 1)

getSaturation(rgb(100,0,50)) // returns 1
getSaturation(rgb(20,20,50)) // returns 0.42857142857142855

getLightness( color ) - returns normalized lightness value of the given color (value returned is between 0 and 1)

getLightness(rgb(100,0,50)) // returns 0.19607843137254902
getLightness(rgb(20,20,50)) // returns 0.13725490196078433

rgb2hsl( colorArray ) - returns normalized HSL array from the RGB array (values returned are between 0 and 1

rgb2hsl([100,0,50]) // returns [0.9166666666666666,1,0.19607843137254902]

hsl2rgb( colorArray ) - returns RGB array from normalized HSL array from the, returns floating point RGB values

hsl2rgb([0.916666,1,0.196078]) // returns [99.99978,0,50.00028999911994]

color2hsl( colorString ) - returns normalized HSL array from color string

color2hsl(rgb(100,0,50)) // returns [0.9166666666666666,1,0.19607843137254902]
color2hsl('#ffa0b5') // returns [0.9631578947368421,1,0.8137254901960784]

HSLtoRGB( hue, saturation, lightness ) - returns RGB array from the common HSL values (hue in degrees, saturation & lightness as percentages), note: the values are imprecise due to rounding

// H=20° S=50% L=20%
HSLtoRGB(20,50,20) // returns [77,43,25]
rgb(HSLtoRGB(20,50,20)) // returns "#4D2B19"

RGBtoHSL( red, green, blue ) - returns common HSL array from the RGB values, note: the values are imprecise due to rounding

RGBtoHSL(77,43,25) // returns [21,51,20]

lighten( color, ratio ) - increases the lightness value by the given ratio

lighten('#A0465A', 0) // returns "#A0465A" (no change)
lighten(rgb(160,70,90), 0.1) // returns "#B04D63" (10% lighter)
lighten(rgb(160,70,90), 1) // returns "#F0DCE1" (100% lighter)
lighten(rgb(160,70,90), 2) // returns "#FFF" (200% lighter results in total white)

darken( color, ratio ) - decreases the lightness value by the given ratio

darken('#A0465A', 0) // returns "#A0465A"
darken(rgb(160,70,90), 0.1) // returns "#903F51"
darken(rgb(160,70,90), 1) // returns "#000"
darken(rgb(160,70,90), 2) // returns "#000"

saturate( color, ratio ) - increases the saturation value by the given ratio

saturate('#A0465A', 0) // returns "#A0465A"
saturate(rgb(160,70,90), 0.1) // returns "#A54258"
saturate(rgb(160,70,90), 1) // returns "#CD1941"
saturate(rgb(160,70,90), 2) // returns "#E60033"

desaturate( color, ratio ) - decreaces the saturation value by the given ratio

desaturate('#A0465A', 0) // returns "#A0465A"
desaturate(rgb(160,70,90), 0.1) // returns "#9B4B5D"
desaturate(rgb(160,70,90), 1) // returns "#737373"
desaturate(rgb(160,70,90), 2) // returns "#737373"

blueshift( color, amount ) - increases the hue value by the given amount (0 = 0°, 1 = 360°)

blueshift('#A0465A', 0) // returns "#A0465A"
blueshift(rgb(160,70,90), 0.1) // returns "#A06646"
blueshift(rgb(160,70,90), 1) // returns "#A0466E"

redshift( color, amount ) - decreates the hue value by the given amount (0 = 0°, 1 = 360°)

redshift('#A0465A', 0) // returns "#A0465A"
redshift(rgb(160,70,90), 0.1) // returns "#A0468E"
redshift(rgb(160,70,90), 1) // returns "#A04646"

font( fontFamily, fileName, fontWeight, fontStyle ) - outputs a @font-face web font (see Web Fonts)

font("Droid Sans","DroidSans-Bold","bold","normal")

linearGradient( direction , stops ) - CSS3 linear-gradient macro function (see Linear Gradients)

linearGradient(topRight,[[blue,0],[red,1]]);

radialGradient( hPosition, vPosition, shape, size, stops ) - CSS3 radial-gradient macro function (see Radial Gradients)

linearGradient(topRight,[[blue,0],[red,1]]);

HSL computation example can be seen in Examples.

There are additional functions for CSS3 transitions and transforms compatibility.

Data URI's

The dataURI() function can be used along with the url() function to embed images directly into CSS files:

A {
	background-image:url(dataURI("image.png"))
}

Outputs:

A {
	background-image : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA....")
}

JavaScript Imports

JavaScript functions and variables can be saved separately from the JXSS code:

Source of mylib.js:
function getPadding(margin) {
    return margin + 2;
}

var c = rgb(238,238,238);

The @import directive is used to import the file:

@import "mylib.js"

P {
    padding: getPadding(1);
    background-color: c;
}

JavaScript libraries which contain formulas, themes, layout calculations, and global settings can be used across many JXSS files in this manner.

JXSS Imports

Entire JXSS rulesets can be saved separately to be reused among many different JXSS files:

Source of mytheme.jxss:
P {
    padding: getPadding(1);
    background-color: c;
}

The @import directive is also used to import the contents of a .jxss file:

@import "mylib.js"
@import "mytheme.jxss"

In both cases, when @import is used to include a JavaScipt or JXSS file, the contents of that file will be pasted into the file being processed.

To maintain CSS compatibility, in JXSS if @import is used to include a .css file the @import directive will be copied as-is in the output CSS.

Also see include() function.

Mixins

Mixins are JavaScript objects, whose properties will be copied to the CSS rule. Use the @() operator in a JXSS ruleset to include a mixin object:

var mixin = {
    padding : 2
};
 
P {
    @(mixin);
    background-color: white;
}

Outputs:

P {
	background-color : #FFF;
	padding : 2px
}

Padding appears last because mixins are processed after regular rules.

Mixin Functions

Functions can be embedded in a mixin to generate properties:

DIV.mixinfn {
	color : black;
	@(function() {
		var mixin = {};
		mixin.background = rgb(100,30,200);
		return mixin;
	}());
}

Outputs:

DIV.mixinfn {
	color : #000;
	background : #641EC8
}

Multiple Mixins

Several mixin objects can be included in two different ways:

var mixin1 = {
	padding : 2
};
var mixin2 = {
	margin : 2
};
P.one {
	@(mixin1);
	@(mixin2);
}
P.two {
	@(mixin1, mixin2);
}

Outputs:

P.one {
	padding : 2px;
	margin : 2px
}
P.two {
	padding : 2px;
	margin : 2px
}

Nested Rulesets

CSS rules can be nested inside one another which eliminates redundancy and aids readibilty:

P {
	border: 1px solid blue;
	A {
		color : red;
	}
}

Outputs:

P {
	border : 1px solid blue
}
P A {
	color : #F00
}

Selector Appending

By default, nesting adds a space between selectors, use the + operator to append selectors together:

P {
	border: 1px solid blue;
	A {
		color : red;
		text-decoration: none;
		+:hover {
			text-decoration: underline;
		}
	}
}

Outputs:

P {
	border : 1px solid blue
}
P A {
	color : #F00;
	text-decoration : none
}
P A:hover {
	text-decoration : underline
}

Macros

JXSS macros are special properties which generate other properties automatically. These are used to generate browser-specific extensions and attempts to make some improvements to CSS by cutting down repetition.

The font macro allows for all the font-* CSS properties to be declared using a nested block:

P {
	font : {
		family : Arial;
		weight : bold;
		size : 10pt;
	}
}

Outputs:

P {
	font-family : Arial;
	font-weight : bold;
	font-size : 10pt
}

Macro Objects

Macros can be set by JavaScript objects:

var f = {
	family : 'Arial',
	weight : 'bold',
	size : '10pt'
};

P {
	font : f
}

Or by functions which return an object:

function fontmacro(size) {
	if (!size) size = 10;
	return {
		family : 'Arial',
		weight : 'bold',
		size : size+'pt'
	};
}

P {
	font : fontmacro(11)
}

The @ directive can be used to set the macro default:

P {
	font : {
		@ : bold 12px/20px Arial;
		family : Lucida;
	};
}

Outputs:

P {
	font : italic bold 12px/20px Arial;
	font-family : Lucida
}

Padding and Margin Macros

JXSS has identical margin and padding macros for handling the top, bottom, left, and right properties:

var ones = {
	left : 1,
	right : 1,
	top : 1,
	bottom : 1
};
P {
	padding : ones;
	margin : ones;
}

Pixels are the default. If the macro is being defined by a JavaScript object, the units must be strings:

var ones = {
	left : "1em",
	right : "1em",
	top : "1em",
	bottom : "1em"
};
P {
	padding : ones;
	margin : {
		left : 1em;
		right : 1em;
		top : 1em;
		bottom : 1em;
	}
}

Border Macro

The border macro accepts width/style/color values:

P {
	border : {
		width : 2;
		style : solid;
		color : black;
	}
}

The macro also accpets individual values for the left/right/top/bottom borders. The @ directive format can also be used to set the default CSS border property from within the nested block.

P {
	border : {
		@ : 1px solid red;
		width : 2;
		style : dashed;
		color : yellow;
		left : {
			width : 1;
			style : solid;
			color : yellow;
		};
		right : {
			width : 1;
			style : solid;
			color : yellow;
		};
		top : {
			width : 1;
			style : solid;
			color : yellow;
		};
		bottom {
			width : 1;
			style : solid;
			color : yellow;
		};
	};
}

Border-Radius Macros

The border-radius macro is for writing the new CSS3 border-radius property, it will write the appropriate browser-specific extensions. The macro can also be nested within an existing border macro using simply radius:

DIV.one {
	border-radius : 4
}
DIV.two {
	border : {
		radius : 4
	}
}

Outputs:

DIV.one {
	-o-border-radius : 4px;
	-moz-border-radius : 4px;
	-webkit-border-radius : 4px;
	border-radius : 4px
}
DIV.two {
	-o-border-radius : 4px;
	-moz-border-radius : 4px;
	-webkit-border-radius : 4px;
	border-radius : 4px
}

The border macro also accepts an object defining the individual values for each corner (top-left, top-right, bottom-left, bottom-right).

DIV.three {
	border-radius : {
		top-left : 3;
		top-right : 4;
		bottom-left : 5;
		bottom-right : 6;
	};
}
DIV.four {
	border : {
		@ : 1px solid black;
		radius : {
			top-left : 3;
			top-right : 4;
			bottom-left : 5;
			bottom-right : 6;
		}
	}
}
DIV.five {
	// short-hand syntax
	border-radius : 3 4 5 6;
}

// camel case must be used here because this is a javascript object, not JXSS
var radiusMacro = {
	topLeft : 3,
	topRight : 4,
	bottomLeft : 5,
	bottomRight : 6,
};
DIV.six {
	border-radius : radiusMacro;
}
DIV.seven {
	border : {
		@ : 1px solid black;
		radius : radiusMacro;
	}
}

Pixels are the default, but other units can be used:

DIV.one {
	border-radius : 1em
}

Opacity Macro

The opacity macro outputs the appropriate code for IE:

DIV.transparent {
	opacity : 0.4;
}

Outputs:

DIV.transparent {
	opacity : 0.4;
	filter : alpha(opacity=40)
}

Box-Shadow Macro

The CSS3 box-shadow macro accepts an array for the values, or a 2D array for a list of box-shadow values. The browser-specific extensions are automatically generated:

A.boxshadow {
	box-shadow:[rgb(0,0,0,0.4),0,1,5]
}
A.boxshadows {
	box-shadow:[
		[1,1,1,rgba(92,64,147,0.9)],
		[3,3,3,rgba(92,64,147,0.7)],
		[6,6,6,rgba(92,64,147,0.5)],
		[9,9,9,rgba(92,64,147,0.3)]
	];
}

Outputs:

A.boxshadow {
	-o-box-shadow : 0px 1px 5px rgba(0,0,0,0.4);
	-moz-box-shadow : 0px 1px 5px rgba(0,0,0,0.4);
	-webkit-box-shadow : 0px 1px 5px rgba(0,0,0,0.4);
	box-shadow : 0px 1px 5px rgba(0,0,0,0.4)
}
A.boxshadows {
	-o-box-shadow : 1px 1px 1px rgba(92,64,147,0.9),3px 3px 3px rgba(92,64,147,0.7),
	6px 6px 6px rgba(92,64,147,0.5),9px 9px 9px rgba(92,64,147,0.3);
	-moz-box-shadow : 1px 1px 1px rgba(92,64,147,0.9),3px 3px 3px rgba(92,64,147,0.7),
	6px 6px 6px rgba(92,64,147,0.5),9px 9px 9px rgba(92,64,147,0.3);
	-webkit-box-shadow : 1px 1px 1px rgba(92,64,147,0.9),3px 3px 3px rgba(92,64,147,0.7),
	6px 6px 6px rgba(92,64,147,0.5),9px 9px 9px rgba(92,64,147,0.3);
	box-shadow : 1px 1px 1px rgba(92,64,147,0.9),3px 3px 3px rgba(92,64,147,0.7),
	6px 6px 6px rgba(92,64,147,0.5),9px 9px 9px rgba(92,64,147,0.3)
}

Text-Shadow Macro

The text-shadow macro makes the syntax almost identical to box-shadow:

A.textshadow {
	text-shadow:[rgba(92,64,147,0.4),0,2,2]
}
A.textshadows {
	text-shadow:[
		[rgba(92,64,147,0.9),1,1,1],
		[rgba(92,64,147,0.7),3,3,3],
		[rgba(92,64,147,0.5),6,6,6],
		[rgba(92,64,147,0.3),9,9,9]
	];
}

Outputs:

A.textshadow {
	text-shadow : rgba(92,64,147,0.4) 0px 2px 2px
}
A.textshadows {
	text-shadow : rgba(92,64,147,0.9) 1px 1px 1px,rgba(92,64,147,0.7) 3px 3px 3px,
	rgba(92,64,147,0.5) 6px 6px 6px,rgba(92,64,147,0.3) 9px 9px 9px
}

Linear Gradients

The JXSS macro for linear gradient backgrounds is in the form a built-in function. Syntax is:

 background-image : linearGradient( direction , [ stops...] )

direction can set the direction of the gradient:

stops is a 2-dimensional array of color-stop values in the form:

[
	[ color1, stopValue1 ],
	[ color2, stopValue2 ],
	...
]

Where colors are a color string (hex or rgb()), and stopValues are a ratio between 0 and 1.

Example:

DIV.one {
	background-image : linearGradient(topRight,[
		[blue,	0],
		[green, 0.5],
		[red, 	1]
	]);
}

The stop values can be generated by a function:

function rainbowGradient(color) {
	var num = 6;
	var stops = [], shift;
	for (var i=0;i<=num;i++) {
		shift = i/num;
		stops.push([ blueshift(color,shift), shift ]);
	}
	return stops;
}
DIV.rainbow {
	background-image : linearGradient('33deg',rainbowGradient(rgb(255,100,50)));
}

See linear-gradient in Examples.

Radial Gradients

The radial-gradient macro is similar to linear-gradient, but uses the radialGradient() function. Browser-specific exentions for *-radial-gradient are written automatically. However, this does not yet support the old Webkit extension -webkit-gradient() which is required for IOS support.

 background-image : radialGradient( hPosition, vPosition, shape, size, [ stops... ] )

hPosition and vPosition sets the position of the gradient using:

shape can be either:

size can be one of:

stops is a 2-dimensional array of color-stop values in the form:

[
	[ color1, stopValue1 ],
	[ color2, stopValue2 ],
	...
]

Example:

background-image : radialGradient(center,top,circle,cover,[
	[yellow, 0],
	[red, 1]
]);

See radial-gradient in Examples.

Transitions and Transform Macros & Functions

JXSS includes transition and transform macros, and the following built-in functions are to assist in their development:

Here is an example using almost all of them along with how nesting can be used to activate transitions:

DIV.transition {
	border: 1px solid black;
	background: grey;
	transition: all 3s ease-in;
}
DIV.transitionhover {
	border: 1px solid block;
	background: #fff;
	+:hover {
		border: 5px solid red;
		background-color: #c0c0c0;
		transition: 'border 1s linear, background-color 1s linear .1s';
	}
}
DIV.transitionpadding {
	border: 1px solid block;
	background: #fff;
	padding-left: 20;
	opacity : 1;
	+:hover {
		opacity : 0.5;
		padding-left: 200;
		background-color: #c0c0c0;
		transition: 'padding-left 2s ease-out, opacity 2s ease-out';
	}
}

DIV.translate {
	border: 1px solid blue;
	transform: translate(100,20);
}

DIV.rotate {
	border: 1px solid green;
	transform: translate(100,70)+' '+rotate(70);
	display:block;
	width:300px;
	height:30px;
}

DIV.transitionrotate {
	display:block;
	width : 300px;
	height : 30px;
	border: 1px solid black;
	background: #ccc;
	+:hover {
		background: #c0c0c0;
		transform: translate(30,40)+' '+rotate(10);
		transition: -webkit-transform 1s linear;
	}
}
DIV.transitionrotate {
	// using both -webkit-transform and -moz-transform in 
	// the same transition rule causes safari/chrome to fail
	// but using a secondary css rule like this does work
	// a variable could be used to share values between the rules
	+:hover {
		transition: -moz-transform 1s linear;
	}
}

DIV.matrix {
	transform: matrix(1, -0.2, 0, 1, 0, 0);
}

DIV.scale {
	transform-origin: top left;
	transform: scale(4,2);
}

DIV.transitionproperties {
	transform-origin: bottom left;
	transition-property: left, top, background, -webkit-transform;
	transition-duration: '2s, 2s, 1s, 1s';
	transition-timing-function: ease-out, ease-in, linear, ease-in-out;
	transition-delay: '0, 0, 0, 1s';
}

Compare the JXSS to its css output.

Web Fonts

JXSS can create CSS3 @font-face references in a more concise manner. Just place font files into the JaxServer /static/fonts directory:

Then use the built-in font() function to refer to the font files. The format is:

font( fontFamily, fileName, fontWeight, fontStyle );

fontWeight, fontStyle are optional and default to "normal".

Example:

font("Droid Sans","DroidSans","normal","normal")
font("Droid Sans","DroidSans-Bold","bold","normal")

P {
	font-family : Droid Sans
}

Outputs:

@font-face {
	font-family:Droid Sans;
	src:url("/static/fonts/DroidSans.ttf") format("truetype");
	font-weight:normal;
	font-style:normal;
}
@font-face {
	font-family:Droid Sans;
	src:url("/static/fonts/DroidSans-Bold.ttf") format("truetype");
	font-weight:bold;
	font-style:normal;
}
P {
	font-family : Droid Sans
}

JXSS will look for TTF, WOFF, EOT, OTF, and SVG files and add them to the @font-face ruleset. Any font conversion software can be used to produce the other formats for greater browser coverage.

Escaping JXSS

JXSS is an extension of JXP. If the JXP is escaped, raw CSS can be written. Use the familiar <% and %> tags:

P {
	border : 5 + 2
}
%>
P.raw {
	border : 5 + 2
}
<%
P {
	border : 7px
}
P.raw {
	border : 5 + 2
}

Support for @media

CSS @media syntax is supported in JXSS:

@media print {
	body { font-size: 10pt }
}
@media screen {
	body { font-size: 13px }
}
@media screen, print {
	body { line-height: 1.2 }
}

Includes

JXSS includes work exactly the same way as JXP includes do. This differs from the @import directive. Import will copy the contents of the file, whereas the include() function will execute the file and print the output.

Global variables can also be passed into the file being included. In this manner, complex layouts and themes can be produced.

Source of master.jxss:
include('slave.jxss',{borderWidth:6,borderColor:red});

Included file:

Source of slave.jxss:
if (typeof borderWidth=='undefined') borderWidth = 1;
if (typeof borderColor=='undefined') borderColor = black;

P {
	border : {
		width : borderWidth;
		style : solid;
		color : borderColor;
	}
}

In order for slave.jxss to compile and run independently, the variables used should be defined as shown.

Because JXSS is processed inside a JavaScript sandbox it is perfectly acceptable to use global variables in JXSS.

Browser Specific Includes

It is important to note that JXSS files always output static CSS. Although while in JaxServer's development environment it is possible to do browser sniffing directly inside JXSS, this should be avoided. In production mode, static CSS files are generated which will strip out the ability to sniff browsers, or pass variables of any kind.

To get around this static nature of CSS, an alternative strategy can be employed to generate CSS files specifically for certain browsers or platforms. This is normally a convoluted process, but using JXSS and JXP together provides for a flexible templating environment where it can be achieved effectively.

The strategy involves creating one master "layout" JXSS which contains browser sniffing, but the browser variable will be passed in from another JXSS file:

Source of layout.jxss:
if (typeof browser=='undefined') browser = 'unknown';

var color = '#c0c0c0';

if (browser=='firefox') {
	color = red;
}
else if (browser=='ie') {
	color = blue;
}

P {
	background-color : color;
}

Then create individual JXSS files for each browser:

Source of layout_ff.jxss:
include('layout.jxss',{browser:'firefox'});

Source of layout_ie.jxss:
include('layout.jxss',{browser:'ie'});

JXP templates, which are always dynamic, can then use browser sniffing to load the appropriate layout-*.jxss file.

Source of layout.jxp:
<html>
<head>
<%
var browser = '';
if (userAgent.indexOf('Firefox')>-1) browser = '_ff';
else if (userAgent.indexOf('MSIE')>-1) browser = '_ie';
%>
<link type="text/css" rel="stylesheet" href="layout<%=browser%>.jxss" />
</head>
<body>
<p><%~userAgent%></p>
</body>
<html>

This results in several, nearly duplicate stylesheets, but requires very little additional programming.

Examples

To try JXSS for yourself and more, install JaxServer and following the JaxServer JXSS tutorial on how to set up and host JXSS files.