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:
- code reuse (DRY)
- use of JavaScript variables and functions
- nested rulesets
- mixins
- file imports
- web font support
- data URI handling (embed images into CSS)
- color calculation functions
- convenient "macros" for CSS3 extensions
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:
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:
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:
- as an offset position (eg. "80px 50px")
- as an angle in degress (eg. "30deg")
- left
- right
- top
- bottom
- topLeft
- topRight
- bottomLeft
- bottomRight
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:
- number of pixels (eg 50, or "50px")
- percentage as a string (eg. "50%")
- top
- left
- right
- bottom
- center
shape can be either:
- circle
- ellipse
size can be one of:
- closestSide
- closestCorner
- farthestSide
- farthestCorner
- contain
- cover
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:
- traslate(x,y)
- scale(x,y)
- scaleX(x)
- scaleY(y)
- skew(ax,ay)
- skewX(ax)
- skeyY(ay)
- matrix()
- rotate(deg)
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.
include('slave.jxss',{borderWidth:6,borderColor:red});
Included file:
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:
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:
include('layout.jxss',{browser:'firefox'});
include('layout.jxss',{browser:'ie'});
JXP templates, which are always dynamic, can then use browser sniffing to load the appropriate layout-*.jxss file.
<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
- The "kitchen sink" example tries to make use of every possible parsing routine:
- HSL functions utilizing the raw jxss() function for generated class names:
- Linear Gradient:
- Radial Gradient:
- Transitions & Transforms:
To try JXSS for yourself and more, install JaxServer and following the JaxServer JXSS tutorial on how to set up and host JXSS files.