JavaScript-Based Style Sheets

"JSSS"
Initial Proposal

Authors:
Lou Montulli montulli@netscape.com
Brendan Eich brendan@netscape.com
Scott Furman fur@netscape.com
Donna Converse converse@netscape.com
Troy Chevalier troy@netscape.com
Date:
Aug 19, 1996
Aug 22, 1996


Abstract

This document specifies a method to attach styles to HTML documents using the existing property-based language JavaScript. This document does not attempt to explain the JavaScript syntax. JavaScript documentation can be found at http://home.netscape.com/comprod/products/navigator/version_2.0/script/script_info/index.html.

1    Basic Concepts

Designing simple style sheets is easy. One only needs to know a little HTML and some simple JavaScript assignment statements. For example, to set the text color of 'H1' elements to blue, one can say:

   document.tags.H1.color = "blue"

The example above is a simple example of using JavaScript to set the color property of all 'H1' tags to "blue". While the example influences only one of manyproperties used in rendering an HTML document, it qualifies as an independent style sheet. Combined with other style sheets it will determine the final presentation of the document.

Further examples within this specification assume "document" is implicitly scoped. Therefore the above example would read:

    tags.h1.color = "blue"

1.1    Containment in HTML

In order for style sheets to influence presentation, the user agent (UA) must be aware of their existence. Another W3C working draft, HTML3 and Style Sheets [4], describes how to link HTML with style sheets:

<HTML>
  <HEAD>
    <TITLE>title</TITLE>
    <LINK REL=STYLESHEET TYPE="text/Javascript"
      HREF="http://style.com/cool" TITLE="Cool">
    <STYLE TYPE="text/javascript">
      tags.H1.color = "blue"
    </STYLE>
  </HEAD>
  <BODY>
    <H1>Headline is blue</H1>
    <P STYLE="color = 'green'">While the paragraph is green.
  </BODY>
</HTML>

The example shows three ways to combine style directives and HTML:

  • the 'LINK' element to link an external style sheet
  • a 'STYLE' element inside the 'HEAD' element
  • and a 'STYLE' attribute on an element inside 'BODY'. This option mixes style with content with a corresponding loss of the advantages of traditional style sheets
  • The 'LINK' element references alternative style sheets that the reader can select, while imported style sheets are automatically merged with the rest of the style sheet.

    Traditionally, UAs have silently ignored unknown tags. As as result, old UAs will ignore the 'STYLE' element, but its content will be treated as part of the document body, and rendered as such. During a transition phase, 'STYLE' element content may be hidden using SGML comments:

      <STYLE><!--
        tags.H1.color = "blue"
      --></STYLE>
    

    Since the 'STYLE' element is declared as "CDATA" in the DTD (as defined in [4]), conformant SGML parsers will not consider the above style sheet to be a comment that is to be removed.

    1.2    Inheritance

    In the first example, the color of 'H1' elements was set to blue. Suppose we have an 'H1' element with an emphasized element inside:

      <H1>The headline <EM>is</EM> important!</H1>
    

    If no color has been assigned to 'EM', the emphasized "is" will inherit the color of the parent element, so it will also appear in blue. Other style properties are likewise inherited.

    Inheritance starts at the oldest ancestor, at the top-level element. In HTML, this is the 'HTML' element which is followed by the 'BODY' element. In order to set a "default" style property, one can use 'BODY' as selector:

      with(tags.BODY) {
        color = "black";
        bgColor = "white";
      }
    

    This will be effective even when the author has omitted the 'BODY' tag (which is legal) since the parser will infer the missing tag. The example above sets the text color to be black and the background color to white.

    Some style properties are not inherited from the parent element to the child element. Most often it is intuitive why this is not the case. For example, the 'background' property does not inherit, but the parent element's background will shine through by default.

    1.3    Class as Selector

    To increase the granularity of control over elements, HTML3 proposes a new attribute: 'CLASS'. All elements inside the 'BODY' element can be classed and the class can be addressed in the style sheet. The keyword 'all' is used to specify that all tags within the class are effected by the style property:

    <HTML>
     <HEAD>
      <TITLE>Title</TITLE>
      <STYLE TYPE="text/javascript">
        classes.punk.all.color = "#00FF00"
      </STYLE>
     </HEAD>
     <BODY>
      <H1 CLASS=punk>Way too green</H1>
     </BODY>
    </HTML>
    

    The normal inheritance rules apply to classed elements; they inherit values from their ancestors in the document structure.

    Only one class can be specified per selector. 'classes.punk.rap' is therefore an invalid selector. (Contextual selectors, described below, can have one class per simple selector.)

    1.4    ID as Selector

    HTML3 also introduces the 'ID' attribute which is guaranteed to have a unique value over the document. It can therefore be of special importance as a style sheet selector. The 'ID' attribute allows particular stylistic exceptions to be expressed.

      ids.z098y.letterSpacing = "0.3em"
    
      <P ID=z098y>Wide text</P>
    

    1.5 Combining Classes and IDs as Selectors

    It is sometimes desirable to reference only those tags that are within a particular set defined by a class. By specifying the tag name instead of using the 'all' keyword, only those tags matching the name and within the class will be effected.

    <style type="text/javascript">
    classes.foo.H1.color = "red"
    </style>
    <h1 class="foo">This should be red</h1>
    <h1>This should be in the normal document color</h1>


    This example sets all 'H1' tags that belong to the class "foo" to the color red.

    1.6    Contextual Selectors

    Inheritance saves designers typing. Instead of setting all style properties, one can create defaults and then list the exceptions. To give 'EM' elements a different color, one may specify:

      with(tags) {
        H1.color = "blue";
        EM.color = "red";
      }

    When this style sheet is in effect, all emphasized sections within or outside 'H1' will turn red. Perhaps one only wanted 'EM' elements within 'H1' to turn red; this can be specified with a native JavaScript method that assigns a search pattern, based on arguments, to a function called "contextual":

      contextual(tags.H1, tags.EM).color = "red"

    The selector is now a search pattern on the stack of open elements. This type of selector is referred to as a "contextual selector". Contextual selectors consist of several simple selectors as arguments to the "contextual" function. Only elements that match the last simple selector (in this case the 'EM' element) are addressed, and only so if the search pattern matches. Contextual selectors look for ancestor relationships, but other relationships (e.g. parent-child) may be introduced in later revisions. In the example above the search pattern matches if 'EM' is a descendant of 'H1'; that is, if 'EM' is inside an 'H1' element.

      with(tags) {
          contextual(UL, LI).color = "red";
          contextual(UL, UL, LI).color = "blue";
      }

    Here, the first selector matches 'LI' elements with at least one 'UL' ancestor. The second selector matches a subset of the first: 'LI' elements with at least two 'UL' ancestors. The conflict is resolved by the second selector being more specific due to the longer search pattern.

    Contextual selectors can look for tags, classes, IDs or combinations of these:

      contextual(tags.DIV, tags.P).color = "green";
      contextual(classes.reddish.all, tags.H1).color = "red";
      contextual(ids.x78y, tags.CODE).background = "blue";

    The first selector matchies all P tags within a DIV tag. The second selector matches all H1 elements with an ancestor class 'reddish'. The third selector matches all 'CODE' elements that are descendants of the element with 'ID=x78y'.

    1.7    Comments

    Textual comments are defined by JavaScript and are similar to those in the C and C++ programming language:

      tags.EM.color = "red";  /* red, really red!! */
      tags.B.color = "blue";  // blue, really blue

    Comments cannot be nested.

    2.0    Typographical Elements

    Some common typographic effects are associated not with structural elements but rather typographical items as formatted on the canvas. Here we attempt to demonstrate some common effects.

    2.1    The 'firstLine' Style

    The following is used to apply special styles to the first line as formatted on the canvas:

      <STYLE TYPE="text/javascript">
        tags.P.firstLine.fontStyle = "small-caps";
      </STYLE>
    
      <P>The first line of an article in Newsweek.
    

    On an text-based UA, this could be formatted as:

      THE FIRST LINE OF AN
      article in Newsweek.
    

    (In the above example, the UA chose to replace small-caps text with capital letters since small-caps fonts were not available. This specification does not describe how UAs should render documents when the necessary resources, such as colors and fonts, are not available.)

    The lines array can be indexed to apply a style to any particular line within a block element.

    2.2    The 'firstLetter' Style

    The 'firstLetter' style is used for "initial caps" and "drop caps" which are common typographic effects. This is how you could make a dropcap initial letter span two lines:

    <HTML>
     <HEAD>
      <TITLE>Title</TITLE>
      <STYLE TYPE="text/javascript">
       with(tags){
         P.fontSize = "12pt";
         P.lineHeight = "12pt";
         P.firstLetter.fontSize *= 2;  // 200%
         P.firstLetter.float = "left";
         SPAN.textTransform = "uppercase";
       }
      </STYLE>
     </HEAD>
     <BODY>
      <P><SPAN>The first</SPAN> few words of an article in The Economist.</P>
     </BODY>
    </HTML>
    

    (The 'SPAN' element is being proposed as a new character-level element for HTML3.)

    If a text-based UA supports the 'firstLetter' style, the above could be formatted as:

      ___
       | HE FIRST few words
       | of an article in the
      Economist..

    The 'firstLetter' style can be attached only to a block-level element.

    3.0    Using Programming Language Constructs in Style Sheets

    JavaScript is a powerful programming language. It can therefore be used to do things ordinary style sheet languages could not. For instance, functions and assigned values may be used to make the expression of style information easier for the style sheet creator. In addition, complex calculations and the querying of external properties reflected into the JavaScript scope maybe used to calculate property values in new and unique ways.

    3.1    Assigning Style-Evaluating Functions

    To assign a style function to a tag, one can use the "apply" property. The function assigned to the "apply" property will be run each time the tag is encountered:

    <style type=text/javascript>
    evaluate_style() {
     if (color == "red"){
       color = "blue";
       fontStyle = "italic";
     } else if (color == "blue"){
       color = "green";
       fontWeight = "bold";
       fontStyle = "normal";
     } else if (color == "green") {
       color = "red";
       fontStyle = "medium";
     }
    }
    tag.UL.color = "green";
    tag.UL.apply = evaluate_style();
    </style>

    This style when applied to a nested list can have the following effect:

    Functions can be assigned to any addressable tag as follows:

    Much more complicated and/or useful examples can be imagined.

    3.2 Evaluating Expressions for Property Values

    Any property can be assigned the result of a JavaScript expression. JavaScript expressions can be used to calculate complicated values and to query other properties which may be reflected.

    Here is an example:

    tags.IMG.width = (500 * 4/3) * .3;
    tags.IMG.width = .50 * document.width;
    if(visual.colorDepth > 2) {
      body.bgColor = "white";
      body.color = "blue";
    } else {
      body.bgColor = "black";
      body.color = "white";
    }

    As more properties are reflected into JavaScript, the expressive power increases dramatically. Style sheets will be able to customize the document to the user's particular environment.

    3.3 Simplifying Assignment Using Methods

    Methods can be used to simplify the assignment of some values. For instance the assignment of margins can be made easier as follows:

        // manual assignment
        with(tags.P) {
            topMargin = 30;
            bottomMargin = 30;
            rightMargin = 30;
            leftMargin = 30;
        }
    
        // assignment using a method
        tags.P.margins(30, 30, 30, 30);
    

    4    Precedence Rules

    More than one style sheet can influence the presentation simultaneously. There are two main reasons for this feature: modularity and author/reader balance.

    A style sheet designer can combine several (partial) style sheets to reduce redundancy:
      <style src="http://www.style.org/punk"></style>
      <style src="http://www.style.org/funk"></style>
      
      <style language=text/javascript>
              tags.H1.color = "red"     /* override imported sheets */
      </style>
    Both readers and authors can influence the presentation through style sheets. To do so, they use the same style sheet language thus reflecting a fundamental feature of the web: everyone can become a publisher. The UA is free to choose the mechanism for referencing personal style sheets.

    Sometimes conflicts will arise between the style sheets which influence the presentation. The order in which styles are read in defines the precedence order with the last style taking precedence. The exception to that rule is that reader's style sheets always take precedence over author's style sheets. Both reader and author rules override UA's default values.

    4.1    Precedence Order for Tags, ID's and Classes

    To find the value for an element/property combination, the following algorithm should be followed:

    1. Find all declarations that apply to the element/property in question. Declarations apply if the selector matches the element in question. If no declarations apply, the inherited value is used. If there is no inherited value (this is the case on the root element and for properties that do not inherit), the initial value is used.
    2. Sort the declarations by explicit weight.
    3. Sort by origin: the reader's style sheets override the author's style sheets which override the UA's default values.
    4. Sort by specificity of selector: more specific selectors will override more general ones. To find the specificity, count the number of ID attributes in the selector (a), the number of CLASS attributes in the selector (b), and the number of tag names in the selector (c). Concatenating the three numbers (in a number system with a large base) gives the specificity. Some examples:
    5.   tags.LI                    /* a=0 b=0 c=1 -> specificity =   1 */
        contextual(UL LI)*         /* a=0 b=0 c=2 -> specificity =   2 */
        contextual(UL OL LI)*      /* a=0 b=0 c=3 -> specificity =   3 */
        classes.foo.all            /* a=0 b=1 c=0 -> specificity =  10 */
        classes.foo.LI             /* a=0 b=1 c=1 -> specificity =  11 */
        ids.x34y                   /* a=1 b=0 c=0 -> specificity = 100 */
      
      *arguments have been shortened for these examples.  UL == tags.UL, etc.
      
    6. Sort by order specified: if two rules have the same weight, the latter specified should live.

    The search for the property value can be terminated whenever one rule has a higher weight than the other rules that apply to the same element/property combination.

    A 'STYLE' attribute on an element should be considered as if an ID attribute had been specified at the end of the style sheet. For example:

    <P style='color = "blue"'>a paragraph of text</p>

    The UA may choose to honor other stylistic attributes (e.g. 'ALIGN') as if a 'STYLE' attribute had been used. When in conflict with other stylistic attributes, the 'STYLE' attribute should win.

    5    Formatting model

    This document suggests a simple box-oriented formatting model. Each block-level element (e.g. 'H1' and 'P', but not 'EM') is surrounded by a box. The size of the box is the sum of the element width (i.e. formatted text or image), the padding, the border and the margins:

        _______________________________________
       |                                       |
       |           margin (transparent)        |
       |   _________________________________   |
       |  |                                 |  |
       |  |        border                   |  |
       |  |   ___________________________   |  |
       |  |  |                           |  |  |
       |  |  |     padding               |  |  |
       |  |  |   _____________________   |  |  |
       |  |  |  |                     |  |  |  |
       |  |  |  |  content            |  |  |  |
       |  |  |  |_____________________|  |  |  |
       |  |  |___________________________|  |  |
       |  |_________________________________|  |
       |_______________________________________|
    
                |    element width    |
    
       |               box width               |
    
    

    The size of the margin, border and padding are set with the 'margin', 'border' and 'padding' properties respectively. The padding area uses the same background as the element itself (set with the 'background' property). The color and style for the border is set with the 'border' property. The margins are always transparent, so the parent element will shine through.

    The following example shows how margins and padding format a 'UL' element with two children. To simplify the diagram there are no borders.

        <STYLE TYPE="text/javascript">
          with(tags.UL) {
            bgColor = "red";
            topMargin = A;
            rightMargin = B;
            bottomMargin = C;
            leftMargin = D;
            topPadding = E;
            rightPadding = F;
            bottomPadding = G;
            leftPadding = H:
          }
          with(tags.LI) {
            color = "white";
            background = "blue";     /* so text is white on blue */
            margins(a, b, c, d);      /* margins is a method that simplifies the assignment of the 4 margin widths */
            paddings(e f g h);
          }
        </STYLE>
        ..
        <UL>
          <LI>1st element of list
          <LI>2nd element of list
        </UL>
    
       _______________________________________________________
      |                                                       |
      |    A      UL margin (transparent)                     |
      |    _______________________________________________    |
      | D |                                               | B |
      |   |    E   UL padding (red)                       |   |
      |   |    _______________________________________    |   |
      |   | H |                                       | F |   |
      |   |   |    a   LI margin (transparent,        |   |   |
      |   |   |        so red shines through)         |   |   |
      |   |   |    _______________________________    |   |   |
      |   |   | d |                               | b |   |   |
      |   |   |   |    e    LI padding (blue)     |   |   |   |
      |   |   |   |                               |   |   |   |
      |   |   |   | h  1st element of list      f |   |   |   |
      |   |   |   |                               |   |   |   |
      |   |   |   |    g                          |   |   |   |
      |   |   |   |_______________________________|   |   |   |
      |   |   |                                       |   |   |
      |   |   |     max(a, c)                         |   |   | <- note the max
      |   |   |                                       |   |   |
      |   |   |    _______________________________    |   |   |
      |   |   |   |                               |   |   |   |
      |   |   | d |    e    LI padding (blue)     |   |   |   |
      |   |   |   |                               |   |   |   |
      |   |   |   | h  2nd element of list      f |   |   |   |
      |   |   |   |                               |   |   |   |
      |   |   |   |    g                          |   |   |   |
      |   |   |   |_______________________________|   |   |   |
      |   |   |                                       |   |   |
      |   |   |   c    LI margin (transparent,        |   |   |
      |   |   |        so red shines through)         |   |   |
      |   |   |_______________________________________|   |   |
      |   |                                               |   |
      |   |    G                                          |   |
      |   |_______________________________________________|   |
      |                                                       |
      |   C                                                   |
      |_______________________________________________________|
    

    Technically, padding and margin properties are not inherited. But, as the example shows, the placement of an element is relative to ancestors and siblings so these elements' padding and margin properties have an effect on their children.

    If the border width had been set (the default value is '0'), the border would have appeared between the padding and the margins.

    5.1    Vertical formatting

    The width of the margins specify the minimum distance to the edges of surrounding boxes. Two or more adjoining margins (i.e., with no border, padding or content between them) are collapsed to use the maximum of the margin values. In the example above, the margins between the two 'LI' elements are collapsed by using the maximum of the first LI element's 'margin-bottom' and the second LI element's 'margin-top'. Similarly, if the padding between the 'UL' and the first 'LI' element (the "E" constant) had been zero, the margins of the UL and first LI elements should have been collapsed.

    In the case of negative margins, the absolute maximum of the negative adjoining margins should be deducted from the maximum of the positive adjoining margins.

    5.2    Horizontal formatting

    Seven length units influence the horizontal dimension of a box: left margin, left border, left padding, width, right padding, right border, right margin. Added up, these have to be equal to the width of the parent element. Therefore, one cannot specify values for all properties and expect them to be honored. The relative strengths between them are as follows:

    1. left border
    2. right border
    3. left padding
    4. right padding
    5. width
    6. left margin
    7. right margin

    By default, the value of the 'width' property is 'auto' which means it will be automatically calculated based on the other properties' values. However, if 'width' is assigned another value, or the dimensions don't add up for other reasons, the property with the lowest rank will be assigned 'auto', i.e. automatically calculated.

    5.3    Lists

    Elements with a 'display' property value of 'list-item' are preceded by a label. The type of label is determined by the 'list-style' property. The label is not considered to be a part of the content, and will be placed outside the content. The rendering of the label should be based on the font and color properties of the element it belongs to.

    5.4    The Canvas

    The canvas is the part of the UA's drawing surface onto which documents are rendered. No structural element of a document corresponds to the canvas. This creates a problem when the document doesn't fill the whole canvas: how should the unfilled area be rendered? HTML extensions have set a precedence in this area; attributes on the 'BODY' element set the background of the whole canvas. To support designers' expectations, we introduce a special rule to find the canvas background:

    If the 'background' value of the 'HTML' element is different from 'transparent' then use it, else use the 'background' value of the 'BODY' element. If the resulting value is 'transparent', the rendering is undefined.

    This rule allows:

      <HTML STYLE="background = 'http://style.com/marble.png'">
      <BODY STYLE="bgColor = 'red'">

    In the example above, the canvas will be covered with "marble". The background color of the 'BODY' element (which may or may not fully cover the canvas) will be red.

    Until other means of addressing the canvas become available, we recommend setting canvas properties on the 'BODY' element.

    5.5    Floating elements

    Using the 'float' property, elements can be declared to be outside the normal flow of elements. For example, by setting the 'float' property of an image to 'left', the normal flow will wrap around on the right side. The image's position will be taken from the margin properties.

    <STYLE>
      with(tags.IMG) {
        float = "left";
        leftMargin = "2em";
      }
    </STYLE>
    
    <BODY>
    <IMG SRC=star.gif>
    <P>Some text to show how text wraps around floating images
    </BODY>
    

    The above example could be formatted as:

          ___
         |   |Some text
         | * |to show how
         |___|text wraps
      around floating images
    

    Vertical bars and underscore characters are used to indicate the bounding box of the image.

    Typically, only image elements are set to be floating. However, there is nothing that prevents the 'float' property to be used on other elements:

      with(tags.H1) {
        fontSize = "medium";
        float = "left";           /* run-in header */
      }
    

    5.6    Replaced Elements

    A replaced element is an element which is replaced by content pointed to from the element. For example, in HTML, the IMG element is replaced by the image pointed to by the SRC attribute. One can assume that replaced elements come with their own intrinsic width and height. If the value for 'width' is 'auto', the intrinsic width should be used as the width of the element. If a value other than 'auto' is specified in the style sheet, this value should be used and the replaced element should be resized accordingly (the resize method will depend on the media type). The 'height' property is used in the same manner.

    6    Properties

    Style sheets influence the presentation of documents by assigning values to style properties. This section lists the defined style properties and their corresponding list of possible values.

    6.1    Notation for Property Values

    In the text below, the allowed values for each property are listed with a syntax like the following:

    Value: N | NW | NE
    Value: [ <length> | thick | thin ]{1,4}
    Value: <url>? <color> [ / <color> ]?
    Value: <url> || <color>

    The words between "<" and ">" give a type of value. The most common types are <length>, <percentage>, <url>, <number> and <color>; these are described in the section on units. The more specialized types (e.g. <font-family> and <border-style>) are described under the property where they appear.

    Other words are keywords that must appear literally. The slash (/) is also considered a keyword.

    Several things juxtaposed mean that all of them must occur, in the given order. A bar (|) separates alternatives: one of them must occur. A double bar (A || B) means that either A or B or both must occur, in any order. Brackets ([]) are for grouping. Juxtaposition is stronger than the double bar, and the double bar is stronger than the bar. Thus "a b | c || d e" is equivalent to "[ a b ] | [ c || [ d e ]]".

    Every type, keyword, or bracketed group may be followed by one of the following modifiers:

    6.2    Font Properties

    Setting font properties will be among the most common uses of style sheets. Unfortunately, there exists no well-defined and universally accepted taxonomy for classifying fonts, and terms that apply to one font family may not be appropriate for others. E.g. 'italic' is commonly used to label slanted text, but the term is not appropriate for sans-serif fonts (whose slanted fonts are called 'oblique'). This specification suggests a liberal terminology for describing fonts, and a level of detail similar to common desktop publishing applications.

    Additional font characteristics are being worked on in the W3C Fonts working group.

    6.2.1    'fontSize'

    Value: <absolute-size> | <relative-size> | <length> | <percentage>
    Initial: medium
    Applies to: all elements
    Inherited: yes
    Percentage values: relative to parent element's font size

    <absolute-size>
    An <absolute-size> keyword is an index to a table of font sizes computed and kept by the UA. Legal values are: [ xx-small | x-small | small | medium | large | x-large | xx-large ]. On a computer screen a scaling factor of 1.5 is suggested between adjacent indexes; if the 'medium' font is 10pt, the 'large' font could be 15pt. Different media may need different scaling factors. Also, the UA should take the quality and availability of fonts into account when computing the table. The table may be different from one font family to another.
    <relative-size>
    A <relative-size> keyword is interpreted relative to the table of font sizes and the font size of the parent element. Legal values are: [ larger | smaller ]. For example, if the parent element has a font size of 'medium', a value of 'larger' will make the font size of the current element be 'large'. If the parent element's size is not close to a table entry, the UA is free to interpolate between table entries or round off to the closest one. The UA may have to extrapolate table values if the numerical value goes beyond the keywords.

    If the value is a number, it is interpreted as a relative keyword where a value of '1' is equivalent to 'bigger'. For example, if the parent element has a font size of 'medium', a value of '-2' will make the font size of the current element be 'x-small'.

    Length and percentage values should not take the font size table into account when calculating the font size of the element.

    For most properties, length values refer to the font size of the current element. On the 'font-size' property' length units (e.g. 'em' and 'ex'), refer to the font size of the parent element.

    Note that an application may reinterpret an explicit size, depending on the context. For example, inside a VR scene, a font may get a different size because of perspective distortion.

    Examples:

      tags.P.fontSize = "12pt";        /* absolute size: be careful! */
      tags.BLOCKQUOTE.fontSize = -1;
      tags.EM.fontSize = +1;          /* the '+' is optional */
      tags.EM.fontSize *= 1.50;       /* increase by 150% */
      tags.EM.fontSize = "1.5em";

    If the suggested scaling factor of 1.5 is used, the latter three rules are identical.

    6.2.2    'fontStyle'

    Value: normal | italic || small-caps | oblique || small-caps | small-caps
    Initial: normal
    Applies to: all elements
    Inherited: yes
    Percentage values: N/A

    Legal combinations of the values are:

    If the preferred font style cannot be accomplished, the UA should make best efforts to find acceptable substitutions. Often, an 'oblique' font can be substituted by an 'italic' font. If 'small-caps' are not available, capital letters of a smaller font size can be used to render small characters if the resolution of the output medium is appropriate for this.

      tags.H1.fontStyle(small-caps, italic);     // a helper method is called
      contextual(tags.H1, tags.EM).fontStyle = "italic";

    In the example above, emphasized text within 'H1' will appear in normal lower-case italic.

    6.2.3    'lineHeight'

    Value: <number> | <length> | <percentage>
    Initial: UA specific
    Applies to: block-level elements
    Inherited: yes
    Percentage values: refers to the font size of the element itself

    The property sets the the distance between two adjacent lines' baselines. It only applies to block-level elements.

    When a numerical value is specified, the line height is given by the font size of the current element multiplied with the numerical value. This differs from a percentage value in the way it inherits: when a numerical value is specified, child elements will inherit the factor itself, not the resultant value (as is the case with percentage and other units).

    Negative values are not allowed.

    The three rules in the example below have the same resultant line height:

      with(tags.DIV) {
        lineHeight = 1.2;
        fontSize = "10pt";     /* number */
        lineHeight = "1.2em;
        fontSize = "10pt";   /* length */
        lineHeight *= 1.20   /* 120% */
        fontSize = "10pt";    /* percentage */

    It is suggested that UAs set the initial value to be a number in the range of 1.0 to 1.2.

    6.3    Color and Background Properties

    6.3.1    'color'

    Value: <color>
    Initial: UA specific
    Applies to: all elements
    Inherited: yes
    Percentage values: N/A

    This property describes the text color of an element, i.e. the "foreground" color. There are different ways to specify red:

      with(tags.EM) {
      color = "red";              /* natural language */
      color = rgb(255,0,0);       /* RGB rage 0-255   */
      }

    6.3.2    'background'

    Value: <url>
    Initial: empty
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

  • This property describes the background of an element, the surface onto which the content (such as text) is rendered.
  • Corresponding example:

      tags.BODY.background = "http://foo.com/background.jpg";


    6.3.3   'bgColor'

    Value: <color>
    Initial: empty
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

  • This property describes the background of an element, the surface onto which the content (such as text) is rendered.
  • Corresponding example:

      tags.BODY.bgColor = "red";

    6.4    Text Properties

    6.4.1    'wordSpacing'

    Value: normal | <length>
    Initial: normal
    Applies to: all elements
    Inherited: yes
    Percentage values: N/A

    The length unit indicates an addition to the default space between words. Values can be negative, but there may be implementation-specific limits. The UA is free to select the exact spacing algorithm. The word spacing may also be influenced by justification (which is a value of the 'align' property).

       tags.H1.wordSpacing = 4

    Here, the word-spacing between each word in 'H1' elements would be increased with 4 pixels.

    6.4.2    'letter-spacing'

    Value: normal | <length>
    Initial: normal
    Applies to: all elements
    Inherited: yes
    Percentage values: N/A

    The length unit indicates an addition to the default space between characters. Values can be negative, but there may be implementation-specific limits. The UA is free to select the exact spacing algorithm. The letter spacing may also be influenced by justification (which is a value of the 'align' property).

      tags.BLOCKQUOTE.letterSpacing = "0.1em"

    Here, the word-spacing between each character in 'BLOCKQUOTE' elements would be increased with '0.1em'.

    6.4.3    'text-decoration'

    Value: none | [ underline | overline | line-through | blink ]+
    Initial: none
    Applies to: all elements
    Inherited: no, but see clarification below
    Percentage values: N/A

    This property describes decorations that are added to the text of an element. If the element has no text (e.g. the IMG element in HTML) or is an empty element (e.g. "<EM></EM>"), this property has no effect.

    The color(s) required for the text decoration should be derived from the 'color' property value.

    This property is not inherited, but children elements should match their ancestor. E.g., if an element is underlined, the line should span the child elements. The color of the underlining will remain the same even if descendant elements have different 'color' values.

      tags.BLOCKQUOTE.textDecoration = "underline"

    We expect UA vendors to propose several new values on this property. Formatters should treat unknown values as 'underline'.

    6.4.4    'verticalAlign'

    Value: baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage>
    Initial: baseline
    Applies to: all elements
    Inherited: yes
    Percentage values: refer to the 'line-height' of the element itself

    The property affects the vertical positioning of the element. One set of keywords is relative to the parent element:

    'baseline'
    align the baseline of the element with the baseline of the parent
    'middle'
    align the vertical midpoint of the element (typically an image) with the baseline plus half the x-height of the parent
    'sub'
    subscript the element
    'super'
    superscript the element
    'text-top'
    align the top of the element with the top of the parent element's font
    'text-bottom'
    align the bottom of the element with the bottom of the parent element's font

    Another set of properties are relative to the formatted line that the element is a part of:

    'top'
    align the top of the element with the tallest element on the line
    'bottom'
    align the bottom of the element with the lowest element on the line

    Using the 'top' and 'bottom' alignment, unsolvable situations can occur where element dependencies form a loop.

    Percentage values refer to the 'line-height' of the element itself. E.g., a value of '-100%' will lower the element to where the baseline of the next line should have been.

    6.4.5    'textTransform'

    Value: capitalize | uppercase | lowercase | none
    Initial: none
    Applies to: all elements
    Inherited: yes
    Percentage values: N/A

    'capitalize'
    uppercases the first character of each word
    'uppercase'
    uppercases all letters of the element
    'lowercase'
    lowercases all letters of the element
    'none'
    neutralizes inherited value.

    The actual transformation in each case is human language and UA dependent.

      tags.H1.textTransform = "uppercase";

    The example above would put 'H1' elements in uppercase text.

    6.4.6    'textAlign'

    Value: left | right | center | justify
    Initial: UA specific
    Applies to: block-level elements
    Inherited: yes
    Percentage values: N/A

    This property describes how text is aligned within the element. The actual justification algorithm used is UA and human language dependent.

    Example:

    tags.P.textAlign = "center"

    Note that alignments are relative to the width of the element, not the canvas. If 'justify' is not supported, the UA will supply a replacement. Typically, this will be 'left' for western languages.

    6.4.7    'textIndent'

    Value: <length> | <percentage>
    Initial: 0
    Applies to: block-level elements
    Inherited: yes
    Percentage values: refer to parent element's width

    The property specifies indentation that appears before the first formatted line. 'text-indent' may be negative, but there may be implementation-specific limits. An indent is not inserted in the middle of an element that was broken by another (such as 'BR' in HTML).

    Example:

     tags.P.textIndent = "3em"
    

    6.5    Box Properties

    See the formatting model (section 4) for examples on how to use the box properties.

    6.5.1    'leftMargin', 'rightMargin', 'topMargin', 'bottomMargin', 'margins'

    Value: [ <length> | <percentage> | auto ]{1,4} (for 'margin' property)
    Initial: 0
    Applies to: all elements
    Inherited: no
    Percentage values: refer to parent element's width

    These properties set the margin of an element: the 'margin' property sets the border for all four sides while the other properties only set their respective side.

    For the 'margin' property, the four lengths apply to top, right, bottom and left respectively.

        tags.BODY.margins("1em", "2em", "3em", "2em"} /* top=1em, right=2em, bottom=3em, left=2em */

    The 'margins' method is a shorthand way of setting all the margin values at the same place in the style sheet. These properties allow only one value. The last rule of the example above is equivalent to the example below:

      with(tags.BODY) {
        topMargin = "1em";
        rightMargin = "2em";
        bottomMargin = "3em";
        leftMargin = "2em";
      }
    

    The margins express the minimal distance between the borders of two adjacent elements. See the formatting model (section 4) for an example.

    When margin properties are applied to replaced elements (e.g. IMG), they express the minimal distance from the replaced element to any of the content of the parent element.

    Negative margin values are allowed, but there may be implementation-specific limits.

    6.5.2    'topPadding', 'rightPadding', 'bottomPadding', 'leftPadding', and 'paddings'

    Value: [ <length> | <percentage> | auto ]{1,4}
    Initial: 0
    Applies to: all elements
    Inherited: no
    Percentage values: refer to parent element's width

    The property describes how much space to insert between the border and the content (e.g. text or image). The order is top, right, bottom, left.

    The surface of the padding area is set with the 'background' property.

      tags.H1.paddings("1em", "2em", "3em", "2em"} /* top=1em, right=2em, bottom=3em, left=2em */
      tags.H1.bgColor = "white"

    The 'paddings' method is a shorthand way of setting all the padding values at the same place in the style sheet. These properties allow only one value. The last rule of the example above is equivalent to the example below:

      with(tags.BODY) {
        topPadding = "1em";
        rightPadding = "2em";
        bottomPadding = "3em";
        leftPadding = "2em";
      }

    The example above sets a 1em padding on all sides. The 'em' unit is relative to the element's font.

    Padding values cannot be negative. See the formatting model (section 4) for more on these properties.

    6.5.3    'borderStyle'

    Value: none | solid
    Initial: medium none
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

    Sets the existance and style of a border around an object. Any unknown border style should be treated as "so¸¦.

    6.5.3    'borderWidth'

    Value: number
    Initial: medium none
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

    Sets the width of a border around an object in pixels, points or "em" units.

    6.5.4    'width'

    Value: <length> | <percentage> | auto
    Initial: auto
    Applies to: all elements
    Inherited: no
    Percentage values: refer to parent element's width

    This property can be applied to text elements, but it is most useful with inline images and similar insertions. The width is to be enforced by scaling the image if necessary. When scaling, the aspect ratio of the image should be preserved if the 'height' property is 'auto'.

    Example:

      ids.first-image.width = 100;

    See the formatting model (section 5) for a description of the relationship between this property and the margin and padding.

    6.5.5    'height'

    Value: <length> | auto
    Initial: auto
    Applies to: block-level and replaced elements
    Inherited: no
    Percentage values: N/A

    This property can be applied to text, but it is most useful with inline images and similar insertions. The height is to be enforced by scaling the image if necessary. When scaling, the aspect ratio of the image should be preserved if the 'width' property is 'auto'.

    Example:

    ids.first-image.height = 50;

    If applied to a textual element, the height can be enforced with e.g. a scrollbar.

    6.5.6    'float'

    Value: <side-flow>
    Initial: none box
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

    Using the 'float' property, one can set an element to be floating and indicate how other content will wrap around it.

    <side-flow>
    Legal values are: [left | right | none]. If no value is specified, 'none' is assumed. With the value 'none', the element will be displayed where it appears in the text. With a value of 'left' ('right') the margin properties will decide the horizontal positioning of the image and the text will float on the right (left) side of the image. With a value of 'left' or 'right', the element is treated as block-level (so, e.g. the 'text-align' property can be set).

    This property is most often used with inline images.

    6.5.7    'clear'

    Value: none | left | right | both
    Initial: none
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

    This property specifies if an element allows floating elements on its sides. More specifically, the value of this property lists the sides where floating elements are not accepted. With 'clear' set to 'left', an element will be moved below any floating element on the left side. With 'clear' set to 'none', floating elements are allowed on all sides. Example:

      tags.H1.clear = "left"
    

    6.6    Classification Properties

    These properties classify elements into categories more than they set specific visual parameters.

    6.6.1    'display'

    Value: block | inline | list-item | none
    Initial: according to HTML
    Applies to: all elements
    Inherited: no
    Percentage values: N/A

    This property indicates if an element is inline (e.g. 'EM' in HTML), block-level (e.g. 'H1' in HTML), or a block-level list item (e.g. 'LI' in HTML). For HTML documents, the initial value will be taken from the HTML specification.

    A value of 'none' turns the display of the element, including children elements and the surrounding box, off.

      with(tags) {
       P.display = "block" 
       EM.display = "inline" 
       LI.display = "list-item" 
       IMG.display = "none" 
      }

    The last rule turns the display of images off.

    Note that HTML defines what elements are block-level (called "Block Structuring Elements") and inline (called "Phrase Markup"), and this may be hardcoded into some UA implementations.

    6.6.2    'listStyle'

    Value: <keyword>
    Initial: disc outside
    Applies to: elements with 'display' property value 'list-item'
    Inherited: yes
    Percentage values: N/A

    The 'list-style' property describes how list items (i.e. elements with a 'display' value of 'list-item') are formatted.

    <keyword>
    Legal values are: [disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none]. If no value is specified, 'disc' is assumed.

    This property can be set on any element, and it will inherit normally down the tree. However, the 'list-style' will only be displayed on elements with a 'display' value of 'list-item'. In HTML this is typically the case for the 'LI' element.

      with (tags) {
       UL.listStyle = "disc"
       OL.listStyle = "decimal"        /* 1 2 3 4 5 etc. */
       OL.listStyle = "lower-roman"    /* a b c d e etc. */
      }
    
    

    6.6.3    'whiteSpace'

    Value: normal | pre | nowrap
    Initial: according to HTML
    Applies to: block-level elements
    Inherited: yes
    Percentage values: N/A

    Declares how white space inside the element should be handled: the 'normal' way (where white space is collapsed), as 'pre' (which behaves like the 'PRE' element in HTML) or as 'nowrap' (where wrapping is done only through BR elements):

      tags.PRE.whiteSpace = "pre"  /* initial value */
    

    7   Units

    7.1    Length Units

    The format of a length value is an optional sign character ('+' or '-', with '+' being the default) immediately followed by a unit converting function which contains a number as an argument

    Some properties allow negative length units, but this may complicate the formatting model and there may be implementation-specific limits. If a negative length value cannot be supported, it should be clipped to the nearest value that can be supported.

    There are three types of length units: relative, pixel and absolute. Relative units specify a length relative to another length property. Style sheets that use relative units will more easily scale from one medium to another (e.g. from a computer display to a laser printer). Percentage units (described below) and keyword values (e.g. 'x-large') offer similar advantages.

    Child elements inherit the computed value, not the relative value:

      with (tags.BODY) {
        fontSize = "12pt"
        textIndent = "3em"  /* i.e. 36pt */
      }
      tags.H1.fontSize = "15pt"
    

    In the example above, the 'textIndent' value of 'H1' elements will be 36pt, not 45pt.

    These relative units are supported:

      with(tags) {
      H1.margin: "0.5em"        /* ems, the height of the element's font */
      H1.margin: "1ex"        /* x-height, ~ the height of the letter 'x' */
      P.font-size: "12px"    /* pixels, relative to canvas */

    Pixel units, as used in the last rule, are relative to the resolution of the canvas, i.e. most often a computer display. If the pixel density of the output device is very different from that of a typical computer display, the UA should rescale pixel values. The suggested "reference pixel" is the visual angle of one pixel on a device with a pixel density of 90dpi and a distance from the reader of an arm's length.

    Absolute length units are useful only when the physical properties of the output medium is known. These absolute units are supported:

      with(tags) {
       H1.margin: "0.5in"      /* inches, 1in = 2.54cm */
       H2.line-height: "3cm")   /* centimeters */
       H3.word-spacing: "4mm"  /* millimeters */
       H4.font-size: "2pt"    /* points, 1pt = 1/72 in */
       H4.font-size: "1pi"     /* picas, 1pc = 12pt */
    }

    7.2    Color Units

    A color is a either a color name or a numerical RGB specification.

    The suggested list of color names is: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, and yellow. These 16 colors are taken from the Windows VGA palette and will also be used in forthcoming HTML 3.2. The RGB values for these color name are not defined in this specification.

      with(tags) {
       BODY.color = "black"
       bgColor = "white"
       H1.color = "maroon"
       H2.color = "olive"
      }
    

    RGB colors are specified in the sRGB color space as defined in the appendix of [6]. UAs should make reasonable efforts to render colors accurately according to the sRGB specification.

    Values outside the numerical ranges should be clipped. The three rules below are therefore equivalent:

      with(tags.EM.color) {
       rgb(255,0,0)        /* integer range 0 - 255 */
       rgb(300,0,0)        /* clipped to 255 */
       rgb(110%, 0%, 0%)   /* clipped to 100% */
      }
    

    7.4    URL

    A Uniform Resource Locator (URL) is identified with a functional notation:

      tags.BODY.background = "http://www.bg.com/pinkish.gif"

    Partial URLs are interpreted relative to the source of the style sheet, not relative to the document:

      tags.BODY.background = "yellow"
    

    Section 8 Editing considerations

    Expressing styles through JavaScript allows the author to generate dynamic effects for the document. While this is highly desirable in an interactive medium it can cause problems when using an editor designed for static documents.

    It is suggested that editors that are designed to edit static documents render a page using the dynamic style sheet as input and then create a static representation from the rendered instance. This process does lose information since the document will no longer have dynamic expressions.

    Authers who generate dynamic styles by hand or by using a dynamic editor should not expect to be able to use a static editor, just as those authors who generate GIF animations should not expect to be able to use GIF editors that do not support animation.

    Section 9 Printing considerations

    This section is unfinished

    Special considerations should be made by authors for how a page should look when printed. Since JavaScript can query the capabilities of a rendering engine it should be possible to dynamically adjust the appearence of a document when printing. For example, a style sheet author may use a JavaScript expression to test if the rendering engine supports color. Since most printers are black and white the author may choose to use italics and bold, or different fonts to represent what otherwise may have been expressed using different colors.

    In the future this specification should be extended to set printer specific styles like page headers and footers. Page break boundaries would also be a desirable feature.

    10 References

    [4] HTML3 and Style Sheets (http://www.w3.org/pub/WWW/TR/WD-style.html)