Table of Contents
Cascading Style Sheets (CSS) enable web designers to enhance the power of HTML tags. In old-fashioned HTML, an <H1> tag would make displayed text a little bigger and bolder, but font style, color, and size were left to the browser. With CSS, the web designer can use the <H1> tag to specify those font attributes.
CSS support within OpenLaszlo helps designers who are not fluent with the LZX scripting language maintain the appearance of Laszlo applications.
If an OpenLaszlo application is to be deployed more than once -- but with different colors, sizes, or resources in each deployment, for instance -- the designer can alter those attributes within a stylesheet.
This is the simplest example of an OpenLaszlo view:
To generate that view with a cascading stylesheet:
Example 18.2. Simplest view with CSS
<canvas>
<stylesheet>
#gView {
height: "200";
width: "200";
bgcolor: "0x663399";
}
</stylesheet>
<view id="gView">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
</method>
</view>
</canvas>
|
The applyStyle method (the oninit handler fires applyStyle when the application initializes) tells the OpenLaszlo runtime to look up the style that applies to the view. The variable style is a place to store the current style's values (computed by LzCSSStyle.getComputedStyle), and then style.getPropertyValue("foo") fetches foo's values from the stylesheet for that view.
The advantage of using stylesheets shows in a slightly more difficult OpenLaszlo application -- this example includes a nested view, plus one resource:
Example 18.3. Nested view
<canvas>
<stylesheet>
#gBox {
height: "350";
width: "500";
bgcolor: "0x330099";
x: "0";
y: "0";
}
#gInsideBox {
height: "150";
width: "300";
bgcolor: "0xFFFFFF";
x: "100";
y: "100";
}
</stylesheet>
<view id="gBox">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
var myHorizontalSpace = style.getPropertyValue("x");
this.setX(myHorizontalSpace);
var myVerticalSpace = style.getPropertyValue("y");
this.setY(myVerticalSpace);
</method>
</view>
<view id="gInsideBox">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
var myHorizontalSpace = style.getPropertyValue("x");
this.setX(myHorizontalSpace);
var myVerticalSpace = style.getPropertyValue("y");
this.setY(myVerticalSpace);
</method>
</view>
<view id="gBounce" resource="../resources/smiley.gif" x="100" y="125">
<animatorgroup name="myAnimatorGroup" start="true" process="sequential" >
<animator attribute="y" from="100" to="150" duration="1000" motion="linear"/>
<animator attribute="y" from="150" to="100" duration="1000" repeat="Infinity" motion="easeout"/>
</animatorgroup>
</view>
</canvas>
|
If a designer wanted to reuse this template, no knowledge of OpenLaszlo's LZX language is necessary -- in this example, s/he just has to change the color hexcode(s) and the name(s) of the resource(s) in the stylesheet. For instance:
Example 18.4. Stylesheet change
<canvas>
<stylesheet>
#gBox {
height: "350";
width: "500";
bgcolor: "0x990033";
x: "0";
y: "0";
}
#gInsideBox {
height: "150";
width: "300";
bgcolor: "0xFFFFFF";
x: "100";
y: "100";
}
</stylesheet>
<view id="gBox">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
var myHorizontalSpace = style.getPropertyValue("x");
this.setX(myHorizontalSpace);
var myVerticalSpace = style.getPropertyValue("y");
this.setY(myVerticalSpace);
</method>
</view>
<view id="gInsideBox">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
var myHorizontalSpace = style.getPropertyValue("x");
this.setX(myHorizontalSpace);
var myVerticalSpace = style.getPropertyValue("y");
this.setY(myVerticalSpace);
</method>
</view>
<view id="gBounce" resource="../resources/sourface.png" x="100" y="125">
<animatorgroup name="myAnimatorGroup" start="true" process="sequential" >
<animator attribute="y" from="100" to="150" duration="1000" motion="linear"/>
<animator attribute="y" from="150" to="100" duration="1000" repeat="Infinity" motion="easeout"/>
</animatorgroup>
</view>
</canvas>
|
Several lines of code can be saved by defining a class which contains the guts of the getPropertyValue methods:
Example 18.5. User-defined class
<canvas height="800" width="800">
<stylesheet>
#gBox {
height: "350";
width: "500";
bgcolor: "0x330099";
x: "0";
y: "0";
}
#gInsideBox {
height: "150";
width: "300";
bgcolor: "0xFFFFFF";
x: "100";
y: "100";
}
</stylesheet>
<class name="myStyledView" extends="view">
<handler name="oninit" method="applyStyle" />
<method name="applyStyle">
var style = LzCSSStyle.getComputedStyle( this );
var bgc = style.getPropertyValue( "bgcolor" );
this.setBGColor(bgc);
var myHeight = style.getPropertyValue( "height" );
this.setHeight(myHeight);
var myWidth = style.getPropertyValue( "width" );
this.setWidth(myWidth);
var myHorizontalSpace = style.getPropertyValue("x");
this.setX(myHorizontalSpace);
var myVerticalSpace = style.getPropertyValue("y");
this.setY(myVerticalSpace);
</method>
</class>
<myStyledView id="gBox"/>
<myStyledView id="gInsideBox"/>
<view id="gBounce" resource="../resources/smiley.gif" x="100" y="125">
<animatorgroup name="myAnimatorGroup" start="true" process="sequential" >
<animator attribute="y" from="100" to="150" duration="1000" motion="linear"/>
<animator attribute="y" from="150" to="100" duration="1000" repeat="Infinity" motion="easeout"/>
</animatorgroup>
</view>
</canvas>
|
For comparison's sake, the previous examples use lots of JavaScript -- descending in clunkiness. Simpler still is to use OpenLaszlo's built-in $style constraint for looking up stylesheets. Again, the most basic example of a view, but this time using the $style constraint:
Example 18.6. User-defined class
<canvas height="200" >
<stylesheet>
#gView {
height: "200";
width: "200";
bgcolor: "0x663399";
}
</stylesheet>
<view id="gView" height="$style{'height'}" width="$style{'width'}" bgcolor="$style{'bgcolor'}"/>
</canvas>
|
The ID selector #gView matches the ID gView, and then $style{} assigns attribute values according to the #gView stylesheet.
The more complex example:
Example 18.7. Nested view class
<canvas height="350" width="700">
<stylesheet>
#sun {
bgcolor: "0x16355E";
face: "../resources/smiley.gif";
}
#monarchs {
bgcolor: "0xB2B9CB";
face: "../resources/sourface.png";
}
</stylesheet>
<simplelayout axis="x" spacing="10"/>
<class name="bouncebox">
<view name="outer" x="0" y="0" width="200" height="200" bgcolor="$style{'bgcolor'}">
<view name="inner" x="50" y="50" bgcolor="0xFFFFFF" width="${immediateparent.width-100}" height="${immediateparent.height-100}" />
<view name="gBounce" source="$style{'face'}" x="50" y="50">
<animatorgroup name="myAnimatorGroup" start="true" process="sequential" >
<animator attribute="y" from="50" to="150" duration="1000" motion="linear"/>
<animator attribute="y" from="50" to="100" duration="1000" repeat="Infinity" motion="easeout"/>
</animatorgroup>
</view>
</view>
</class>
<bouncebox id="monarchs" />
<bouncebox id="sun" />
</canvas>
|
For styling a view created dynamically with new, it's easiest to define a class, then new instances of the class:
Example 18.8. Borrowing styled attributes from a dummy view
<canvas debug="true">
<stylesheet>
mookie {
height : "25";
width : "25";
bgcolor : "0x0000FF";
}
blaylock {
title : "Blaylock";
bgcolor : "0xFF0000";
}
wilson {
height : "25";
width : "200";
fgcolor : "0xFF00FF";
text : "Wilson";
}
</stylesheet>
<class name="mookie" x="200" height="$style{'height'}" width="$style{'width'}" bgcolor="$style{'bgcolor'}"/>
<class name="blaylock">
<window title="$style{'title'}" x="250" height="100" width="150" bgcolor="$style{'bgcolor'}"/>
</class>
<class name="wilson" >
<text text="$style{'text'}" x="400" height="$style{'height'}" width="$style{'width'}" fgcolor="$style{'fgcolor'}"/>
</class>
<button text="Dynamically create Mookie">
<method event="onclick">
canvas.mookieView=new mookie(canvas, {});
</method>
</button>
<button text="Dynamically create Blaylock" y="50">
<method event="onclick">
canvas.blaylockWindow=new blaylock(canvas, {});
</method>
</button>
<button text="Dynamically create Wilson" y="100">
<method event="onclick">
canvas.wilsonText=new wilson(canvas, {});
</method>
</button>
</canvas>
|
The stylesheet is a collection of rules that apply to the LZX document. Each rule applies to one aspect of the document, and consists of two parts: selector and declaration.
The selector comes before the curly brace, the declaration after. In the example above, an LZX element with id="myView" and bgcolor="$style{'bgcolor'} within its declaration will get a blue background color.
CSS support for OpenLaszlo enables four types of selectors:
Attribute
Element
ID
Descendant
The attribute selector applies when it corresponds to a node's attribute (for instance, name or width):
Example 18.11. Attribute selector
<canvas height="150" width="200">
<stylesheet>
[name="PurpleView"] {
width: "100";
height: "100";
bgcolor: "0x9900FF"
}
[width="200"] {
bgcolor: "0x0000FF";
}
</stylesheet>
<simplelayout axis="x" spacing="10"/>
<class name="myPurpleView">
<view name="PurpleView" height="$style{'height'}" width="$style{'width'}" bgcolor="$style{'bgcolor'}"/>
</class>
<class name="myWiderView">
<view name="hoo" height="100" width="200" bgcolor="$style{'bgcolor'}"/>
</class>
<myPurpleView/>
<myWiderView/>
</canvas>
|
The class myPurpleView contains a view whose name corresponds to the stylesheet selector [name="PurpleView"], so each of its $style rules is applied. The class myWiderView contains a view whose width fires the $style that applies to its background color.
The element selector applies when it matches the name of the node itself:
Example 18.13. Element selector
<canvas height="200" width="200">
<stylesheet>
view {
nicebgcolor: "0x0000FF";
micebgcolor: "0xCCCCCC";
}
</stylesheet>
<view height="100" width="100" bgcolor="$style{'nicebgcolor'}"/>
<view height="75" width="75" bgcolor="0xFFFFFF"/>
<view height="50" width="50" bgcolor="$style{'micebgcolor'}"/>
</canvas>
|
ID selectors are identified by # in the stylesheet. The selector applies when it matches a node's ID:
Example 18.15. ID selector
<canvas height="200" width="200">
<stylesheet>
#red {
width: 100;
height: 100;
bgcolor: "0xFF3333";
}
#blue {
width: 150;
height: 150;
bgcolor: "0x3333FF";
}
</stylesheet>
<simplelayout axis="x" spacing="5" />
<class name="gBox" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}" />
<gBox id="red" />
<gBox id="blue" />
</canvas>
|
Example 18.16. Descendant example
fee fi {
property: "car";
}
fee fi foo {
property: "cart";
}
fee fi foo fum {
property: "cartman";
}
|
A selector in an ancestor/descendant hierarchy applies when its ancestors do. In the snippet above, the "fee" selector depends on no ancestors, so it would always fire on an LzNode identified by "fee". The "fum" selector, on the other hand, would only fire if the LzNode had three ancestors "fee", "fi", and "foo".
Example 18.17. Descendant selector
<canvas width="400" height="400">
<stylesheet>
styledbox {
stylebgcolor: "0xCCCCCC";
styleinnercolor: "0xFF0000"; // red
}
styledbox styledbox2 {
stylebgcolor: "0x999999";
styleinnercolor: "0x0000FF"; // blue
}
styledbox styledbox2 styledbox3 {
stylebgcolor: "0x666666";
styleinnercolor: "0x00FF00"; // green
}
</stylesheet>
<class name="styledbox" height="100" width="100" bgcolor="$style{'stylebgcolor'}">
<view name="snow" x="10" y="10" height="10" width="10" bgcolor="$style{'styleinnercolor'}"/>
</class>
<class name="styledbox2" height="100" width="100" bgcolor="$style{'stylebgcolor'}">
<view name="braxton" x="10" y="10" height="10" width="10" bgcolor="$style{'styleinnercolor'}"/>
</class>
<class name="styledbox3" height="100" width="100" bgcolor="$style{'stylebgcolor'}">
<view name="jackson" x="10" y="10" height="10" width="10" bgcolor="$style{'styleinnercolor'}"/>
</class>
<styledbox id="comet" x="200" y="0">
<styledbox2 id="shock" x="-100" y="100">
<styledbox3 id="storm" x="-100" y="100"/>
</styledbox2>
</styledbox>
<styledbox2/>
<styledbox3/>
</canvas>
|
In the example above, the instances of styledbox2 and styledbox3 at the end of the script don't appear on the canvas at all, because there's no stylesheet information for styledbox2 unless it descends from styledbox, and no stylesheet information for styledbox3 unless it descends from stylebox and stylebox2.
![]() |
Warning |
|---|---|
|
Don't include an underscore in selector names. Your LZX files will not compile. |
|
![]() |
Warning |
|---|---|
|
The difference between an attribute selector and a descendant selector is as little as a spacebar. The attribute selector person[name='george'] (no space between person and name) selects a person whose name is george, but the descendant selector person [name='george'] selects a view named george which is a child of the view named person. |
|
An instance of an LzNode -- most likely a view, or some other OpenLaszlo element -- can trigger more than one selector in the stylesheet. In such cases, CSS gives precedence according to rules of specificity. In general, the more specific the selector, the higher its precedence. For instance, the ID of a view is more specific (can only apply to one view) than view itself (applies to every view).
Within OpenLaszlo's CSS support, the order of specificity is (in ascending order):
Element
Attribute
ID
This example uses all three selectors:
Example 18.18. Specificity
<canvas width="350" height="150">
<stylesheet>
view {
height: "50";
width: "50";
bgcolor: "0xFF0000";
}
[name='blue'] {
height: "50";
width: "50";
bgcolor: "0x0000FF";
}
#green {
height: "50";
width: "50";
bgcolor: "0x006600";
}
</stylesheet>
<simplelayout axis="x" spacing="25"/>
<view id="red" name="red" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}"/>
<view id="blue" name="blue" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}" />
<view id="green" name="green" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}" />
</canvas>
|
The first view -- red -- fires the element selector, because its ID is not "green", and its name is not "blue". It is an instance of a "view" element, which triggers the element selector. The second view -- blue -- fires the name selector; its ID is not "green", but the next selector in order of priority is attribute, which name='blue' matches. The third view -- green -- hits the highest-priority selector; id='green' matches the ID selector #green, and looks up that stylesheet.
![]() |
Warning |
|---|---|
|
Style selectors: Under w3's CSS specificity rules, the highest-priority selector is "style='foo'", which directly looks up the foo stylesheet. The OpenLaszlo implementation does not support "style='foo'" because that expression cannot be used as a Laszlo property or attribute. |
|
In some cases, more than one selector of the same type will be triggered. In this example, the view short fires two selectors: [height="50"] and [width="100"]. Neither selector takes precedence because they are both attribute selectors, so a tiebreaker has to be invoked. The selector closest to the bottom of the stylesheet prevails.
Example 18.19. Lexical order
<canvas height="200" width="345">
<stylesheet>
[height="50"] {
height: "50";
width: "100";
bgcolor: "0xFF0000";
}
[width="100"] {
height: "50";
width: "100";
bgcolor: "0x0000FF";
}
</stylesheet>
<simplelayout axis="y" spacing="10"/>
<view name="short" width="100" height="50" bgcolor="$style{'bgcolor'}"/>
<view y="75">
<text text="If I'm red, the first stylesheet was triggered."/>
</view>
<view y="100">
<text text="If I'm blue, the second stylesheet was triggered."/>
</view>
</canvas>
|
Copyright © 2002-2007 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.