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:
Example 19.1. Simplest view
<canvas height="120" width="100%">
  <view height="100" width="100" bgcolor="#663399"/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                  To generate that view with a cascading stylesheet:
Example 19.2. Simplest view with CSS
<canvas height="120" width="100%">
  <stylesheet>
    #gView {
      height: 100;
      width: 100;
      bgcolor: #663399;
    }
  </stylesheet>
  <view id="gView" height="$style{'height'}" width="$style{'width'}" bgcolor="$style{'bgcolor'}"/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                  The $style constraint tells the OpenLaszlo runtime to style an
                        attribute according to the stylesheet. More than one stylesheet can be
                        used in an LZX document; the application of a stylesheet is determined by selectors. 
            
The <boxmodel>
                        
                              mixin
                            adds CSS2 model support to <view>.
            
<boxmodel> implements a subset of the CSS2 box model spec.
            
For a complete description of <boxmodel>, see the
                           Reference.
            
Example 19.3. Simple view with boxmodel
<canvas height="200" width="100%" bgcolor="antiquewhite">
  <stylesheet>
    #thebox {
    padding: 1 3 5 7;
    border-width: 2 4 6 8;
    border-color: cornflowerblue;
    margin: 3 7 11 15;
    }
    text { color: navy; }
    .margin { background-color: aliceblue; }
    .borderwidth { color: white; background-color: cornflowerblue; }
    .padding { background-color: skyblue; }
    .content { background-color: white; }
    colortext { border-width: 1; }
    colortext.margin, colortext.borderwidth { border-bottom-width: 0 }
  </stylesheet>
  
  <class name="colorview" extends="view">
    <attribute name="bgcolor" style="background-color" value="transparent"/>
    <attribute name="fgcolor" style="color" value="black"/>
  </class>
  <class name="colortext" extends="text" with="boxmodel" width="100%" multiline="true">
    <attribute name="bgcolor" style="background-color" value="transparent"/>
    <attribute name="fgcolor" style="color" value="black"/>
  </class>
  
  <colorview styleclass="margin" x="5" y="5">
    <colorview id="thebox" with="boxmodel" styleclass="padding" width="250">
      <colorview styleclass="content" layout="axis: y; spacing:0" width="100%">
        <text>Click me to demonstrate updating:</text>
        <text name="op"/>
        <colortext styleclass="margin">
          <handler name="onmargin" reference="thebox" method="display"/>
          <handler name="oninit" method="display"/>
          <method name="display" args="ignore">
            this.format("margin: %s", thebox.presentAttribute('margin'));
          </method>
        </colortext>
        <colortext styleclass="borderwidth">
          <handler name="onborderwidth" reference="thebox" method="display"/>
          <handler name="oninit" method="display"/>
          <method name="display" args="ignore">
            this.format("borderwidth: %s", thebox.presentAttribute('borderwidth'));
          </method>
        </colortext>
        <colortext styleclass="padding">
          <handler name="onpadding" reference="thebox" method="display"/>
          <handler name="oninit" method="display"/>
          <method name="display" args="ignore">
            this.format("padding: %s", thebox.presentAttribute('padding'));
          </method>
        </colortext>
        <attribute name="attribute" type="string"/>
        <attribute name="amount" type="number"/>
        <handler name="onclick" method="doit"/>
        <handler name="oninit" method="doit"/>
        <method name="doit" args="ignore">
          if (this.attribute) {
          thebox.setAttribute(this.attribute, thebox[this.attribute] + amount);
          }
          var r = Math.floor(Math.random()*3);
          var prefix = ['margin', 'border', 'padding'][r];
          var suffix = ['','width',''][r];
          this.attribute = prefix+['top','right','bottom','left'][Math.floor(Math.random()*4)]+suffix;
          this.amount = Math.round(Math.random()*10);
          op.format("%s += %w", attribute, amount);
        </method>
      </colorview>
    </colorview>
  </colorview>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2011 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  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 19.6. Attribute selector
<canvas height="120" width="100%">
  <stylesheet>
    [name="PurpleView"] {
      width: 100;
      height: 100;
      bgcolor: #9900FF
    }
    [width="200"] {
      bgcolor: #0000FF;
    }
  </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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                     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 tag that creates the node. In the
                              example below, the element selector view matches the
                                 <view> tag:
               
Example 19.8. Element selector
<canvas height="120" width="100%">
  
  <stylesheet>
    view {
      nicebgcolor: #0000FF;
      micebgcolor: #CCCCCC;
    }
  </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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                     ID selectors are identified by # in the stylesheet. The selector applies when it matches a node's ID:
Example 19.10. ID selector
<canvas height="170" width="100%">
  <stylesheet>
    #red {
      width: 100;
      height: 100;
      bgcolor: #FF3333;
    }
    #blue {
      width: 150;
      height: 150;
      bgcolor: #3333FF;
    }
    
  </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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                     Example 19.11. 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 node identified by "fee". The "fum" selector, on the other hand, would only fire if the node had three ancestors "fee", "fi", and "foo".
Example 19.12. Descendant selector
<canvas height="320" width="100%">
  <stylesheet>
    styledbox {
      stylebgcolor: #CCCCCC;
      styleinnercolor: "red";
    }
    styledbox styledbox2 {
      stylebgcolor: #999999;
      styleinnercolor: "blue";
    }
    styledbox styledbox2 styledbox3 {
      stylebgcolor: #666666;
      styleinnercolor: "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>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                     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]](images/warning.png) | Warning | 
|---|---|
| Don't include an underscore in selector names, because the LZX file will not compile. | 
| ![[Warning]](images/warning.png) | Warning | 
|---|---|
| The difference between an attribute selector and a descendant selector is as
                                             little as a spacebar. The attribute selector  | 
The advantage of using stylesheets shows in a slightly more difficult OpenLaszlo application. If a designer wanted to reuse a 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:
Example 19.13. Nested view
<canvas height="220" width="100%">
  <stylesheet>
    #sun {
      bgcolor: #16355E;
      face: "resources/smiley.gif";
    }
    #monarchs {
      bgcolor: #B2B9CB;
      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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                  For styling a view created dynamically with new, it's easiest to
                        define a class, then new instances of the class:
            
Example 19.14. Styled views created dynamically
<canvas height="150" width="100%">
  <stylesheet>
    mookie {
      height : 25;
      width : 25;
      bgcolor : #0000FF;
    }
    blaylock {
      title : "Blaylock";
      bgcolor : #FF0000;
    }
    wilson {
      height : 25;
      width : 200;
      fgcolor : #FF00FF;
      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">
    <handler name="onclick">
      canvas.mookieView=new lz.mookie(canvas, {});
    </handler>
  </button>
  <button text="Dynamically create Blaylock" y="50">
    <handler name="onclick">
      canvas.blaylockWindow=new lz.blaylock(canvas, {});
    </handler>
  </button>
  <button text="Dynamically create Wilson" y="100">
    <handler name="onclick">
      canvas.wilsonText=new lz.wilson(canvas, {});
    </handler>
  </button>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                  CSS attribute selectors automatically update when the value of an attribute specified by
                        the selector changes. For example: button[mouse=down] will listen for
                        changes to the mouse attribute and will only apply when
                           button.mouse == 'down'.
            
The following example demonstrates the use of dynamic CSS. Click on the color buttons to toggle the colors; click on the color swatches to see the CSS description.
Example 19.15. Dynamic CSS
<canvas width="100%" height="500" debug="true"> 
  <debug x="30%" width="65%" y="5%" height="90%"/>
  <stylesheet>
    /* default, should only be seen if things are broken */
    colorswatch { background-color: orange }
    /* Static for buttons */
    colorbutton[color=red] {background-color: red }
    /* `lime` is the HTML name for rgb(0,255,0) */
    colorbutton[color=green] {background-color: lime }
    colorbutton[color=blue] {background-color: blue }
    /* dynamic single selectors that apply to individual swatches */
    [red=off] colorswatch { background-color: cyan; opacity: 0.2 }
    [red=on] colorswatch { background-color: red; opacity: 0.95 }
    [green=off] colorswatch { background-color: magenta; opacity: 0.2 }
    [green=on] colorswatch { background-color: lime; opacity: 0.95 }
    [blue=off] colorswatch { background-color: yellow; opacity: 0.2 }
    [blue=on] colorswatch { background-color: blue; opacity: 0.95 }
    /* dynamic compound selectors that apply to mixer colorswatch */
    [red=off] [green=off] [blue=off] [name=mixer] colorswatch { background-color: black; opacity: 1 }
    [red=off] [green=off] [blue=on] [name=mixer] colorswatch { background-color: blue; opacity: 1 }
    [red=off] [green=on] [blue=off] [name=mixer] colorswatch { background-color: lime; opacity: 1 }
    [red=off] [green=on] [blue=on] [name=mixer] colorswatch { background-color: cyan; opacity: 1 }
    [red=on] [green=off] [blue=off] [name=mixer] colorswatch { background-color: red; opacity: 1 }
    [red=on] [green=off] [blue=on] [name=mixer] colorswatch { background-color: magenta; opacity: 1 }
    [red=on] [green=on] [blue=off] [name=mixer] colorswatch { background-color: yellow; opacity: 1 }
    [red=on] [green=on] [blue=on] [name=mixer] colorswatch { background-color: white; opacity: 1 }
  </stylesheet>
 <!-- button to toggle an attribute which should trigger style change -->
  <class name="colorbutton" width="40" height="20" align="center">
    <attribute name="bgcolor" style="background-color"/>
    <attribute name="color" type="string"/>
    <text fgcolor="white" text="${this.parent.on}" align="center"/>
    <attribute name="on" type="string" value="off"/>
    <handler name="onclick">
      this.setAttribute('on', this.on === 'on' ? 'off' : 'on' );
    </handler>
  </class>
  <!-- color swatch that is styled by background-color and opacity -->
  <class name="colorswatch" height="60" width="60" bgcolor="gray" align="center">
    <attribute name="swatchcolor" style="background-color" type="color"/>
    <attribute name="swatchopacity" style="opacity" value="1"/>
    <handler name="onclick">
      Debug.clear();
      Debug.explainStyleBindings(this);
    </handler>
    <view name="swatch" x="5" y="5" height="50" width="50">
      <attribute name="bgcolor" value="${parent.swatchcolor}"/>
      <attribute name="opacity" value="${parent.swatchopacity}"/>
    </view>
  </class>
  <!-- nested views with red, green, blue attributes that dynamically change
       to demonstrate the applicability of compound dynamic selectors  -->
  <view x="5%" y="5%" width="20%" height="80%" layout="axis: y; spacing: 5">
    <text width="100%" multiline="true">
      Toggle the red, green, and blue buttons on and off to
      dynamically update the applicable CSS selectors.  Click on a color
      swatch to explain the applicability of the CSS selectors.
    </text>
    <attribute name="red" value="${this.toggle.on}" type="string"/>
    <colorbutton name="toggle" color="red"/>
    <colorswatch/>
    <view width="100%" layout="axis: y; spacing: 5">
      <attribute name="green" value="${this.toggle.on}" type="string"/>
      <colorbutton name="toggle" color="green"/>
      <colorswatch/>
      <view width="100%" layout="axis: y; spacing: 5">
        <attribute name="blue" value="${this.toggle.on}" type="string"/>
        <colorbutton name="toggle" color="blue"/>
        <colorswatch/>
        <view width="100%" name="mixer" layout="axis: y; spacing: 5">
          <text align="center">Mixer</text>
          <colorswatch id="mixer"/>
        </view>
      </view>
    </view>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
  * Copyright 2010 Laszlo Systems, Inc.  All Rights Reserved.                   *
  * Use is subject to license terms.                                            *
  * X_LZ_COPYRIGHT_END ****************************************************** -->
                  An instance of a node -- 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 19.16. Specificity
<canvas height="70" width="100%">
  <stylesheet>
    view {
      height: 50;
      width: 50;
      bgcolor: #FF0000;
    }
    [name='blue'] {
      height: 40;
      width: 40;
      bgcolor: "blue";
    }
    #green {
      height: 30;
      width: 30;
      bgcolor: rgb(0,102,0);
    }
  </stylesheet>
  <view layout="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" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                  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]](images/warning.png) | Warning | 
|---|---|
| Style selectors: Under W3C'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 19.17. Lexical order
<canvas height="120" width="100%">
  <stylesheet>
    [height="50"] {
      height: 50;
      width: 100;
      bgcolor: #FF0000;
    }
    [width="100"] {
      height: 50;
      width: 100;
      bgcolor: #0000FF;
    }
  </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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
     * Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
     * Use is subject to license terms.                                            *
     * X_LZ_COPYRIGHT_END ****************************************************** -->
                     A stylesheet can be imported by using
when the stylesheet is in its typical format:
Example 19.19. Imported stylesheet example
<!--begin foo.css-->
#gPhilip {
    width: 300;
    height: 200;
    bgcolor: #8F008F;
}
<!--end-->
<!--The LZX file-->
<canvas>
	<stylesheet src="foo.css" />
	<view id="gPhilip" width="$style{'width'}" height="$style{'height'}" bgcolor="$style{'bgcolor'}"/>
</canvas>
Copyright © 2002-2010 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.