CSS Schema 1.0

Working Draft 6 May 2004

This version:
...
Latest version:
...
Previous version:
...
Author:
Björn Höhrmann, bjoern@hoehrmann.de

Abstract

This specification defines CSS Schema 1.0, a simple Schema language for CSS Profiles. CSS Schemas specify patterns for the structure and content of CSS Style Sheets and optional meta data to simplify processing CSS syntax.

Status of this document

This is a rough initial working draft for discussion among W3C QA Tools Development (qa-dev) participants and other interested parties. It might eventually evolve to a W3C Technical Report. Please send comments to the author and a carbon copy to the www-archive@w3.org mailing list for public archival.

Table of contents

1. Introduction

The design goal of CSS Schema is to ease development and maintenance of Validators and Tools for document formats based on CSS Syntax, primarily focused on CSS itself. CSS Schema should provide sufficient means to determine validity of style sheets according to the respective definition in the following specifications. It should not be necessary to implement specification or profile dependant information to determine the validity of a document.

[add references].

This draft contains a number of additional features and meta data that are not directly required to determine the validity of style sheets, but which are helpful to give proper warnings to the user (e.g., if a style sheet is bound to a specific medium and uses properties inapplicable for it) or are useful for tool authors (e.g., the initial value for a property or whether it is inherited).

2. Use Cases / Background / Motivation / Ideas / Issues

...

For example a user dislikes fixed positioning. Since CSS does not allow to disable specific property/value combinations in user style sheets, the user could setup a validating CSS filter and create a negative Schema like

@property position { value: fixed }

Or in a more extensible fashion there could be a superset of CSS Schema with something like

@ignore { @property position { value: fixed } }

Interesting for authors would be user agent specific schemas, they could aswell setup a validating CSS filter and specify the browser A support schema as positive filter and load documents in browser B. If browsers A and B are interoperable the author would not need to use browser A in order to get an idea of how the document would render in it.

Another rather obvious idea would be to allow validation with multiple schemas and generate a result like

Support Analysis
Declaration CSS 1 CSS 2 ACME Browser 1.0 ACME Browser 2.0
position: fixed no yes no yes
color: rgba(0,0,0,0) no no no yes
...

...

A validator could support Validation Sheets with positive and negative Schemas. For example, CSS allows rgb(...) to specify colors outside the sRGB gamut, but it is likely that an author just made a typo and wants his colors inside the sRGB gamut. There could be one Schema that defines

@unit \%;
@function rgb [ <#integer>, <#integer>, <#integer> ] |
              [ <%>, <%>, <%> ] ;

And in addtion a "negative" Schema for addtional checks.

@unit \%;
@warning
{
  @function rgb
    [ <#integer:range(0,255)>,
      <#integer:range(0,255)>,
      <#integer:range(0,255)> ] |
    [ <%:range(0,100)>,
      <%:range(0,100)>,
      <%:range(0,100)> ] ;

  warn: "Color outside sRGB gamut"
}

In this case the CSS Schema at-rules are more like selectors... It might generally be a good idea to think of CSS Schema more as an integration set for "Validation Sheets" with @error, @warning, etc. rules rather than a freestanding format.

It would also be nice to programmatically derive interface definitions or even code from a Schema. For example, if rgb(...) was defined like

@unit \%;
@function rgb [ <#integer:name(red)>,
                <#integer:name(green)>,
                <#integer:name(blue)> ] |
              [ <%:name(red)>,
                <%:name(green)>,
                <%:name(blue)> ] ;

(I admit that it does not look very nice, but that's just syntax...) it would be possible without too much trouble to derive

interface rgb : function
{
  attribute CSSValue red;
  attribute CSSValue green;
  attribute CSSValue blue;
}

and even code that constructs a new rgb object automatically at parse time.

I am still looking for ideas to make shorthand properties more accessible. For example the CSS 3 font shorthand property would be defined somewhat like

@property font
{
  grammar: [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]?
             <'font-size'>
             [ / <'line-height'> ]? <'font-family'>
           ]
           | caption
           | icon
           | menu
           | message-box
           | small-caption
           | status-bar ;
  ...
}

But a rule like

p { font: 600 9pt Charcoal }

is equivalent to

p {
  font-style:       normal;
  font-variant:     normal;
  font-weight:      600;
  font-size:        9pt;
  line-height:      normal;
  font-family:      Charcoal;
  font-stretch:     normal;
  font-size-adjust: none;
}

Which is somewhat odd since it is not possible to specify font-stretch or font-size-adjust in the font declaration. It is thus not possible to derive what a shorthand resolves to directly from the <#grammar>.

A possible solution for this particular problem would be a property or an at-rule that specifies which properties are set to their initial value, something like

@property font
{
  ...
  reset: font-stretch, font-size-adjust;
}

But this would be a rather insuffient. For example, consider the margin property in CSS 1, it is somewhat like

@property margin
{
  grammar: [ <length> | <percentage> | auto ]{1,4} ;
  ...
}

It is a shorthand for margin-top, margin-right, margin-bottom, and margin-left, which property gets which value depends on the number of values specified in the declaration.

There could be an additional modifier for such shorthand properties, for example something like

@property margin
{
  grammar: <'margin-right':and(margin-top,
                               margin-left,
                               margin-bottom)> |

           <'margin-top':and(margin-bottom)>
           <'margin-right':and(margin-left)>   |

           <'margin-top'>
           <'margin-right':and(margin-left)>
           <'margin-bottom'> |

           <'margin-top'>
           <'margin-right'>
           <'margin-bottom'>
           <'margin-left'>
           ;
  ...
}

Not really that nice but in combination with the reset property it should be sufficient to describe all CSS 3 shorthand properties [also display?].

Another concern is modular composition of Schemas. Since CSS3 is modularized some property definitions are split across modules. Since profiles are likely to include some modules and exclude others, I would like to have one schema for each module (profile), thus CSS Schema needs to compensate. The question is how to get the @property infoset for a given context.

The display property (lets forget that it is a more a shorthand in CSS3 for a moment) in css3-box :

@property display
{
  grammar: inline
         | block
         | inline-block
         | list-item
         | run-in
         | compact
         | table
         | inline-table
         | table-row-group
         | table-header-group
         | table-footer-group
         | table-row
         | table-column-group
         | table-column
         | table-cell
         | table-caption
         | ruby
         | ruby-base
         | ruby-text
         | ruby-base-group
         | ruby-text-group
         | none ;

  initial: inline ;
  ...
}

And then there is css3-content which adds

@property display
{
  grammar: normal ;
  initial: normal ;
  ...
}

And css3-ui which adds

@property display
{
  grammar: inline-block | icon ;
  initial: inline ;
  ...
}

The first problem is that if @property must not specify that only the last declaration for the grammar part wins. It could say that multiple definitions have a cumulative effect or it could be explicit (and thus be probably more intuitive) like in

@property display add
{
  grammar: inline-block | icon ;
  ...
}

or some similar syntax. However, the property definitions also disagree on the initial value of the display property. This could be an error but it could also make sense to have differing initial values if it is expected that only some particular modules are implemented without implementing a "base" module, css3-box in this example.

Second problem is that legal values for properties might depend on the context of the property. For example, CSS 2.0 forbids the units em and ex in @page context. How could such a restriction be expressed?

3. Terminology

The keywords "MUST", "SHALL", "MUST NOT", "SHALL NOT", "REQUIRED", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" when used in this document are to be interpreted as described in RFC 2119 [RFC2119]. However, for readability, these words do not appear in all uppercase letters in this specification.

4. The @charset at-rule

Syntax and semantics of the @charset at-rule are defined in [CSS3SYN].

5. The @import at-rule

Syntax and semantics of the @import at-rule are defined in [CSS3SYN].

6. The @profile at-rule

The @profile at-rule is a proposed extension to CSS. It would be used to reference a CSS Schema for Validation much like the <!DOCTYPE ...> document type declaration in SGML/XML documents.

@at-rule profile <url>;

The <url> is a URI to a CSS Schema document. A CSS Schema Validator could use the URI to retrieve a custom schema or resolve it locally if it references a well-known schema location.

It would also be possible to allow some kind of formal public identifier in form of an <identifier> or a <string> to reference well-known schemas but without some entity defining such names it would be quite useless.

@profile rules must be placed immediately after the (optional) @charset rule in the style sheet.

This specification does not define what CSS Schema Validators must do if a style sheet specifies more than one @profile rule.

7. The @macro at-rule

This could also be named @value, @type or something similar.

...

8. The @property-group at-rule

The @property-group assigns a name to a set of property to reference these properties in a specific context. For example, font descriptors as defined in [CSS3-WEBFONTS] [ask Bert to update biblio.ref] would be such a property group that is only allowed inside the @font-face at-rule.

@at-rule property-group <identifier> { [...] }

...

9. The @strip-value at-rule

[find a better name]

...

10. The <#grammar> built-in type

The <#grammar> built-in type is a simple grammar to specify legal property values and various other aspects of style sheets. It is a superset of the property syntax definition grammar as defined in Section 1.4.2 of [CSS21]. The (meta) grammar is given using the simple EBNF notation as defined in Appendix ... [add reference, add link, ask Bert to update biblio.ref] of [XML10].

A <#grammar> is a sequence of Tokens representing (references to) keywords, data types, special symbols or in some cases the <#grammar> of already defined properties. A Token is any of

name
a keyword name.
<name>
a reference to a type declared in the Schema.
<#name>
a reference to a CSS Schema type.
<'name'>
a reference to the <#grammar> of the name property.
, or /
Literally the symbol , or /.

...

Some Tokens may be modified by a Modifier to allow specialized types, for example an integer in a specific range. This specification defines the following modifiers:

range(Min, Max)

<#integer>, <#real>, and unit value types (or derived types) may specify a numerical range for allowed values. The numerical value of the token must be at least the value of Min and (if Max is specified) at most the value of Max. The numerical value of Max must not be smallar than the numerical value of Min.

For example, a grammar like

<#integer:range(0,255)>

causes the following expressions to be

  -1 /* invalid, not an <#integer>                */
  +1 /* invalid, not an <#integer>                */
   0 /* valid, an <#integer> and >= 0 and <= 255  */
  10 /* valid, an <#integer> and >= 0 and <= 255  */
 256 /* invalid, the expression is not <= 255     */

Should real numbers be allowed? Should negative numbers be allowed? Should Min be optional?

...
...

Tokens and Groups may be combined by an Operator in the following ways:

a || b
a conjunction of tokens (one or more of the values may appear in any order)
a | b
a disjunction of tokens (exactly one of the tokens must appear)
a b
a sequence of tokens (all tokens must appear in the specified order)

A sequence is stronger than a conjunction and a conjunction is stronger than a disjunction.

Tokens and combinations of Tokens may be grouped into a Group using square brackets ([ ... ]).

An example with and without grouping. The expressions are equivalent due to the binding rules defined earlier.

  a b   |   c ||   d e
[ a b ] | [ c || [ d e ] ]

Tokens and Groups may be quantified by a Quantifier. A Quantifier is a symbol that specifies how often a token must and/or may appear in a sequence of tokens. The following Quantifiers are defined:

*
shorthand for {0,}
+
shorthand for {1,}
?
shorthand for {0,1}
{Min,Max}
The Token must appear at least Min times and (if Max is specified) at most Max times.

...

S          ::= (#20 | #x9 | #xD | xA)
Digit      ::= [0-9]
Symbol     ::= ('/' | ',')
Name       ::= [a-zA-Z] [a-zA-Z0-9-_]*
Min        ::= Digit+
Max        ::= Digit*
Range      ::= '{' S* Min S* ',' S* Max S* '}'
Quantifier ::= ('+' | '*' | '?' | Range)
Group      ::= '[' S* Expression S* ']'
Modifier   ::= ":" Name ('(' (Name | Symbol | Digit)+ ')')?
Type       ::= Name Modifier?
PropRef    ::= "<'" Type "'>"
SchemaRef  ::= "<#" Type '>'
TypeRef    ::= '<' Type '>'
Keyword    ::= Name
Operator   ::= ('|' | "||" | S*)
Token      ::= (Group | PropRef | TypeRef | SymbolRef | Keyword | Symbol)
QuantToken ::= Token Quantifier? S*
Expression ::= QuantToken | (QuantToken Operator S+ Expression)

[check this grammar]

[consider extending this grammar, e.g. the Symbol terminal]

[add numerical ranges]

[change example for :range, integers may be signed]

[change grammar for name to allow \%]

[Change syntax of min/max for :range]

[update the text below]

An expression is invalid if any of the following conditions apply

11. The @property at-rule

The @property defines a single property.

...

Name: 'value'
Value: <#syntax>
Initial: <#undefined>

The value of the value property is a grammar as defined in section 1.4.2. of [CSS21] [ask Bert to update biblio.ref] [this reference should eventually be updated to the corresponding section in a CSS 3 Module; which one, btw?].

As it might turn out to be complicated to express the grammar based on the grammar itself, the data type of the value might be changed to a <string>.

Using the CSS property value grammar imposes some restrictions on the CSS Schema language as some property values in the CSS specifications are not expressed in this grammar, for example the font-family property uses a <family-name> macro (in CSS Schema terms) for custom font family names, but it does not restrict it in any way. You would thus probably limit the allowed range of values to something like <string> | <identifier>+

The following example Schema fragment would define the margin shorthand property in CSS Level 1:

@property margin
{
  value: [ <length> | <percentage> | auto ]{1,4};
}

...

Name: 'media'
Value: <uri> | none
Initial: all

...

Name: 'initial'
Value: <#syntax>
Initial: <#undefined>

...

Name: 'inherit'
Value: yes | no
Initial: no

...

Name: 'applies'
Value: <uri> | none
Initial: none

...

12. The @function at-rule

@function allows to introduce new functional notation types (such as rgb(...)) to the CSS Schema.

@at-rule function <#syntax>;

...

13. The @unit at-rule

The @unit at-rule is used to introduce new unit value types to the CSS Schema. Unit value types are <number>s followed by a unit identifier like "px" and "em" and depending on the unit preceded by a sign character. The syntax of @unit is:

@at-rule unit <identifier> unsigned?;

The optional unsigned attribute indicates whether a sign character is allowed.

@unit ch;          /* line-height: +2ch is valid                 */
@unit ch unsigned; /* line-height: +2ch is invalid               */
                   /* Assuming @property line-height allows <ch> */

Once a unit is declared, it is available for use in the Schema as a data type [add link]. If there are multiple @unit rules for the same unit identifier, the last @unit specification wins.

For example a Schema for CSS 2.0 would define the following units:

@unit \%;
@unit em;
@unit pt;
@unit cm;
@unit mm;
@unit pt;
@unit in;
@unit ex;
@unit pc;
@unit px;
@unit deg;
@unit rad;
@unit grad;
@unit s unsigned;
@unit ms unsigned;
@unit hz unsigned;
@unit khz unsigned;

14. Data Types

...

<#uri>
See Section 3.5.2 URIs in [CSS3VAL].
<#string>
See Section 3.4 Strings in [CSS3VAL].
<#identifier>
[add reference]
<#integer>
See Section 3.2 Numbers in [CSS3VAL].
<#real>
See Section 3.2. Numbers in [CSS3VAL].
<#urange>
See Section 2.3. Descriptors for Font Data Qualification in [CSS3-WEBFONTS].
<#hexcolor>
See Section 4.2.1. RGB color values in [CSS3COLOR].
<#undefined>
...
<#grammar>
See Section ... [add reference]

15. Selectors

[forthcoming]

Well, what about selectors? Selectors are difficult, I think it would be much too complicated trying to use the property value grammar to define selectors. My basic idea is to analyze what selectors we have got and associated features. For example, CSS Level 1 does not allow do specify multiple class selectors in a simple selector like .class1.class2 and CSS Level 2 does not allow to attach multiple pseudo-elements to a sequence of simple selectors while CSS 3 probably will (e.g., ::before::before). I probably think along these lines:

@pseudo-class root;
@pseudo-class first-child;
@pseudo-class required;
...

@pseudo-element first-letter;
@pseudo-element first-line;
...

@pseudo-class not <#simple-selector>;
@pseudo-class contains <string>;
...

@pseudo-element before <integer>;
@pseudo-element after <integer>;
...

@selector-features
{
  multiple-class-selectors: yes; /* allow .a.b */
  multiple-pseudo-elements: no;  /* disallow ::before::before */
  attribute-exists: yes;         /* allow [attribute] */
  attribute-equals: no;          /* disallow [attribute=value] */
  combinator-child: yes;         /* allow a > b */
  universal-selector: yes;       /* allow * */
  ...
}

One drawback of this approach would be that a new level of CSS might require a revision of CSS Schema aswell. It would be nice if this could be avoided somehow.

I am not sure whether allowing to specify the content model of pseudo-class and pseudo-element arguments in the schema. In a worse case szenario neither CSS Parser nor CSS Schema Validator know anything about selectors so they would not be able to determine selector validity unless the Schema provides the necessary information. It is probably much too eager to support this case...

There should be some means to define which pseudo-elements may be combined (and probably their order, depending on requirements in the CSS specifications involved), for example ::marker::outside::after::repeat-index::alternate might be disallowed or have undefined meaning.

Browser support based feature description is another issue. For example, AFAIR Internet Explorer 6 ignores a selector similar to p:first-line, div:first-line [need to check css-design@yahoogroups.de archives and test it] due to the comma, if you change it to p:first-line , div:first-line it will be honored. That's probably a case out of scope for CSS Schema. However, there might be cases where there is a need for a feature description from the W3C CSS Profile perspective but from a implementation specific limit perspective, the specification should attempt to be consider extensibility in this direction.

16. Conformance

16.1. CSS Schema Validator Conformance

[forthcoming]

16.2. Schema Conformance

[forthcoming]

17. A Sample CSS Schema for CSS3 Module: Color

@namespace dc url(http://purl.org/dc/elements/1.1/) ;
@meta dc:title "CSS3 Module: Color" ;
@meta dc:author "Björn Höhrmann" ;
@base url(http://www.w3.org/TR/2003/CR-css3-color-20030514/) ;

/*

  ISSUES:

  * how to express that attr(..., color) is allowed
    while e.g. attr(..., length) is not?
  * what to write into 'applies'?
  * add media type/group stuff to draft
  * add 'about' property for spec uri refs
  * meta data: my metadata proposal? or @title, etc.? Omit?
  * add @base?

*/

@macro html4colors
    Black
  | Green
  | Silver
  | Lime
  | Gray
  | Olive
  | White
  | Yellow
  | Maroon
  | Navy
  | Red
  | Blue
  | Purple
  | Teal
  | Fuchsia
  | Aqua ;

@macro svgcolors
    aliceblue
  | antiquewhite
  | aqua
  | aquamarine
  | azure
  | beige
  | bisque
  | black
  | blanchedalmond
  | blue
  | blueviolet
  | brown
  | burlywood
  | cadetblue
  | chartreuse
  | chocolate
  | coral
  | cornflowerblue
  | cornsilk
  | crimson
  | cyan
  | darkblue
  | darkcyan
  | darkgoldenrod
  | darkgray
  | darkgreen
  | darkgrey
  | darkkhaki
  | darkmagenta
  | darkolivegreen
  | darkorange
  | darkorchid
  | darkred
  | darksalmon
  | darkseagreen
  | darkslateblue
  | darkslategray
  | darkslategrey
  | darkturquoise
  | darkviolet
  | deeppink
  | deepskyblue
  | dimgray
  | dimgrey
  | dodgerblue
  | firebrick
  | floralwhite
  | forestgreen
  | fuchsia
  | gainsboro
  | ghostwhite
  | gold
  | goldenrod
  | gray
  | green
  | greenyellow
  | grey
  | honeydew
  | hotpink
  | indianred
  | indigo
  | ivory
  | khaki
  | lavender
  | lavenderblush
  | lawngreen
  | lemonchiffon
  | lightblue
  | lightcoral
  | lightcyan
  | lightgoldenrodyellow
  | lightgray
  | lightgreen
  | lightgrey
  | lightpink
  | lightsalmon
  | lightseagreen
  | lightskyblue
  | lightslategray
  | lightslategrey
  | lightsteelblue
  | lightyellow
  | lime
  | limegreen
  | linen
  | magenta
  | maroon
  | mediumaquamarine
  | mediumblue
  | mediumorchid
  | mediumpurple
  | mediumseagreen
  | mediumslateblue
  | mediumspringgreen
  | mediumturquoise
  | mediumvioletred
  | midnightblue
  | mintcream
  | mistyrose
  | moccasin
  | navajowhite
  | navy
  | oldlace
  | olive
  | olivedrab
  | orange
  | orangered
  | orchid
  | palegoldenrod
  | palegreen
  | paleturquoise
  | palevioletred
  | papayawhip
  | peachpuff
  | peru
  | pink
  | plum
  | powderblue
  | purple
  | red
  | rosybrown
  | royalblue
  | saddlebrown
  | salmon
  | sandybrown
  | seagreen
  | seashell
  | sienna
  | silver
  | skyblue
  | slateblue
  | slategray
  | slategrey
  | snow
  | springgreen
  | steelblue
  | tan
  | teal
  | thistle
  | tomato
  | turquoise
  | violet
  | wheat
  | white
  | whitesmoke
  | yellow
  | yellowgreen ;

@macro systemcolors
    ActiveBorder
  | ActiveCaption
  | AppWorkspace
  | Background
  | ButtonFace
  | ButtonHighlight
  | ButtonShadow
  | ButtonText
  | CaptionText
  | GrayText
  | Highlight
  | HighlightText
  | InactiveBorder
  | InactiveCaption
  | InactiveCaptionText
  | InfoBackground
  | InfoText
  | Menu
  | MenuText
  | Scrollbar
  | ThreeDDarkShadow
  | ThreeDFace
  | ThreeDHighlight
  | ThreeDLightShadow
  | ThreeDShadow
  | Window
  | WindowFrame
  | WindowText ;

@macro name <identifier> ;
@macro number <#integer> | <#real> ;
@macro alphavalue <number> ;

@function hsl <number>, <%>, <%> ;

@function hsla <number>, <%>, <%>, <alphavalue> ;

@function rgb [ <#integer>,
                <#integer>,
                <#integer> ] |
              [ <%>,
                <%>,
                <%> ] ;

@function rgba [ [ <#integer>,
                   <#integer>,
                   <#integer> ] |
                 [ <%>,
                   <%>,
                   <%> ] ], <alphavalue> ;

@function attr-color <#identifier>, color ;

@macro color
    <systemcolors>
  | <svgcolors>
  | <html4colors>
  | <rgb>
  | <rgba>
  | <hsl>
  | <hsla>
  | <#hexcolor>
  | transparent
  | currentColor
  | flavor ;

@property color
{
  grammar: <color>
         | <attr-color>
         | initial
         | inherit ;

  initial: <#undefined> ;
  applies: all ;
  inherit: yes ;
  media: visual ;
  about: url(./#color0) ;
}

@property opacity
{
  grammar: <alphavalue>
         | inherit
         | initial ;

  initial: 1 ;
  applies: all ;
  inherit: no ;
  media: visual ;
  about: url(./#opacity) ;
}

@property color-profile
{
  grammar: auto
         | sRGB
         | <name>
         | <uri>
         | inherit
         | initial ;

  initial: auto ;
  applies: all ;
  inherit: yes ;
  media: visual ;
  about: url(./#color-profile) ;
}

@property rendering-intent
{
  grammar: auto
         | perceptual
         | relative-colorimetric
         | saturation
         | absolute-colorimetric
         | inherit
         | initial ;

  initial: auto ;
  applies: all ;
  inherit: yes ;
  media: visual ;
  about: url(./#rendering-intent) ;
}

/* add @color-profile */

/* @color-profile descriptors */

@function local <string> ;
@macro local-profile <local> ;

@property name
{
  grammar: <name> ;
  initial: <#undefined> ;
  media: visual ;
  about: url(./#propdef-color-profile-name) ;
}

@property src
{
  grammar: sRGB
         | <local-profile>
         | <uri>
         | <local-profile> <uri> ;

  initial: sRGB ;
  media: visual ;
  about: ... ; 
}

@property rendering-intent
{
  grammar: auto
         | perceptual
         | relative-colorimetric
         | saturation
         | absolute-colorimetric ;

  initial: auto ;
  media: visual ;
  about: ... ;
}


18. A Sample CSS Schema for CSS Schema

[forthcoming]

19. A Sample CSS Schema for CSS 2.1

@namespace dc url(http://purl.org/dc/elements/1.1/) ;
@meta dc:title "CSS 2.1" ;
@meta dc:author "Björn Höhrmann" ;
@base url(http://www.w3.org/TR/CSS21/) ;

@unit \%;
@unit em;
@unit pt;
@unit cm;
@unit mm;
@unit pt;
@unit in;
@unit ex;
@unit pc;
@unit px;
@unit deg;
@unit rad;
@unit grad;
@unit s unsigned;
@unit ms unsigned;
@unit hz unsigned;
@unit khz unsigned;

@macro length ... ;
@macro percentage ... ;
@macro identifier ... ;
@macro angle ... ;
@macro uri ... ;
@macro integer ... ;
@macro time ... ;
@macro number ... ;
@macro string ... ;
@macro frequency ... ;
@macro color ... ;

@macro absolute-size ... ;
@macro border-style ... ;
@macro border-width ... ;
@macro family-name ... ;
@macro generic-family ... ;
@macro generic-voice ... ;
@macro margin-width ... ;
@macro padding-width ... ;
@macro relative-size ... ;
@macro specific-voice ... ;

@property azimuth
{
  grammar: <angle>
         | [[ left-side
            | far-left
            | left
            | center-left
            | center
            | center-right
            | right
            | far-right
            | right-side ] || behind ]
          | leftwards
          | rightwards
          | inherit ;

  initial: center ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-azimuth) ;
}

@property  background-attachment
{
  grammar: scroll
         | fixed
         | inherit ; 

  initial: scroll ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background-attachment) ;
}

@property background-color
{
  grammar: <color>
         | transparent
         | inherit ; 

  initial: transparent ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background-color) ;
}

@property background-image
{
  grammar: <uri>
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background-image) ;
}

@property background-position
{
  grammar: [ [ <percentage>
             | <length>
             | top
             | center
             | bottom ]
          || [ <percentage>
             | <length>
             | left
             | center
             | right ] ]
         | inherit ;

  initial: 0% 0% ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background-position) ;
}

@property background-repeat
{
  grammar: repeat
         | repeat-x
         | repeat-y
         | no-repeat
         | inherit ; 

  initial: repeat ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background-repeat) ;
}

@property background
{
  grammar: [ <'background-color'>
          || <'background-image'>
          || <'background-repeat'>
          || <'background-attachment'>
          || <'background-position'> ]
         | inherit ;

  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(colors.html#propdef-background) ;
}

@property border-collapse
{
  grammar: collapse
         | separate
         | inherit ; 

  initial: separate ;
  inherit: yes ;
  media: visual ;
  about: url(tables.html#propdef-border-collapse) ;
}

@property border-color
{
  grammar: [ <color> | transparent ]{1,4} | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-color) ;
}

@property border-spacing
{
  grammar: <length> <length>?
         | inherit ; 

  initial: 0 ;
  inherit: yes ;
  media: visual ;
  about: url(tables.html#propdef-border-spacing) ;
}

@property border-style
{
  grammar: <border-style>{1,4}
         | inherit ; 

  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-style) ;
}

@property border-top
{
  grammar: [ <border-width> || <border-style> || <'border-top-color'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-top) ;
}

@property border-right
{
  grammar: [ <border-width> || <border-style> || <'border-top-color'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-right) ;
}

@property border-bottom
{
  grammar: [ <border-width> || <border-style> || <'border-top-color'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-bottom) ;
}

@property border-left
{
  grammar: [ <border-width> || <border-style> || <'border-top-color'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-left) ;
}

@property border-top-color
<'border-right-color'>
<'border-bottom-color'>
<'border-left-color'>
{
  grammar: <color>
         | transparent
         | inherit ; 

  initial: the value of the <'color'> property ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-top-color) ;
}

@property border-top-style
<'border-right-style'>
<'border-bottom-style'>
<'border-left-style'>
{
  grammar: <border-style>
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-top-style) ;
}

@property border-top-width
<'border-right-width'>
<'border-bottom-width'>
<'border-left-width'>
{
  grammar: <border-width>
         | inherit ; 

  initial: medium ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-top-width) ;
}

@property border-width
{
  grammar: <border-width>{1,4}
         | inherit ; 

  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border-width) ;
}

@property border
{
  grammar: [ <border-width> || <border-style> || <'border-top-color'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-border) ;
}

@property bottom
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-bottom) ;
}

@property caption-side
{
  grammar: top
         | bottom
         | inherit ; 

  initial: top ;
  inherit: yes ;
  media: visual ;
  about: url(tables.html#propdef-caption-side) ;
}

@property clear
{
  grammar: none
         | left
         | right
         | both
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-clear) ;
}

@property clip
{
  grammar: <shape>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visufx.html#propdef-clip) ;
}

@property color
{
  grammar: <color>
         | inherit ; 

  initial: depends on user agent ;
  inherit: yes ;
  media: visual ;
  about: url(colors.html#propdef-color) ;
}

@property content
{
  grammar: normal
         | [ <string>
           | <counter>
           | attr(<identifier>)
           | open-quote
           | close-quote
           | no-open-quote
           | no-close-quote ]+
         | inherit ;

  initial: normal ;
  inherit: no ;
  media: all ;
  about: url(generate.html#propdef-content) ;
}

@property counter-increment
{
  grammar: [ <identifier> <integer>? ]+ | none | inherit ;
  initial: none ;
  inherit: no ;
  media: all ;
  about: url(generate.html#propdef-counter-increment) ;
}

@property counter-reset
{
  grammar: [ <identifier> <integer>? ]+ | none | inherit ;
  initial: none ;
  inherit: no ;
  media: all ;
  about: url(generate.html#propdef-counter-reset) ;
}

@property cue-after
{
  grammar: <uri>
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-cue-after) ;
}

@property cue-before
{
  grammar: <uri>
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-cue-before) ;
}

@property cue
{
  grammar: [ <'cue-before'> || <'cue-after'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-cue) ;
}

@property cursor
{
  grammar: [ [<uri> ,]* [ auto
                        | crosshair
                        | default
                        | pointer
                        | move
                        | e-resize
                        | ne-resize
                        | nw-resize
                        | n-resize
                        | se-resize
                        | sw-resize
                        | s-resize
                        | w-resize
                        | text
                        | wait
                        | help
                        | progress ] ] | inherit ;

  initial: auto ;
  inherit: yes ;
  media: visual, interactive ;
  about: url(ui.html#propdef-cursor) ;
}

@property direction
{
  grammar: ltr
         | rtl
         | inherit ; 

  initial: ltr ;
  inherit: yes ;
  media: visual ;
  about: url(visuren.html#propdef-direction) ;
}

@property display
{
  grammar: inline
         | block
         | list-item
         | run-in
         | inline-block
         | table
         | inline-table
         | table-row-group
         | table-header-group
         | table-footer-group
         | table-row
         | table-column-group
         | table-column
         | table-cell
         | table-caption
         | none
         | inherit ; 

  initial: inline ;
  inherit: no ;
  media: all ;
  about: url(visuren.html#propdef-display) ;
}

@property elevation
{
  grammar: <angle>
         | below
         | level
         | above
         | higher
         | lower
         | inherit ; 

  initial: level ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-elevation) ;
}

@property empty-cells
{
  grammar: show
         | hide
         | inherit ; 

  initial: show ;
  inherit: yes ;
  media: visual ;
  about: url(tables.html#propdef-empty-cells) ;
}

@property float
{
  grammar: left
         | right
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-float) ;
}

@property font-family
{
  grammar: [[ <family-name> | <generic-family> ] [, <family-name>| <generic-family>]* ] | inherit ;
  initial: depends on user agent ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font-family) ;
}

@property font-size
{
  grammar: <absolute-size>
         | <relative-size>
         | <length>
         | <percentage>
         | inherit ; 

  initial: medium ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font-size) ;
}

@property font-style
{
  grammar: normal
         | italic
         | oblique
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font-style) ;
}

@property font-variant
{
  grammar: normal
         | small-caps
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font-variant) ;
}

@property font-weight
{
  grammar: normal
         | bold
         | bolder
         | lighter
         | 100
         | 200
         | 300
         | 400
         | 500
         | 600
         | 700
         | 800
         | 900
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font-weight) ;
}

@property font
{
  grammar: [ [ <'font-style'>
            || <'font-variant'>
            || <'font-weight'> ]?
            <'font-size'>
            [ / <'line-height'> ]? <'font-family'> ]
         | caption
         | icon
         | menu
         | message-box
         | small-caption
         | status-bar
         | inherit ;

  initial: see individual properties ;
  inherit: yes ;
  media: visual ;
  about: url(fonts.html#propdef-font) ;
}

@property height
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-height) ;
}

@property left
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-left) ;
}

@property letter-spacing
{
  grammar: normal
         | <length>
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-letter-spacing) ;
}

@property line-height
{
  grammar: normal
         | <number>
         | <length>
         | <percentage>
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(visudet.html#propdef-line-height) ;
}

@property list-style-image
{
  grammar: <uri>
         | none
         | inherit ; 

  initial: none ;
  inherit: yes ;
  media: visual ;
  about: url(generate.html#propdef-list-style-image) ;
}

@property list-style-position
{
  grammar: inside
         | outside
         | inherit ; 

  initial: outside ;
  inherit: yes ;
  media: visual ;
  about: url(generate.html#propdef-list-style-position) ;
}

@property list-style-type
{
  grammar: disc
         | circle
         | square
         | decimal
         | decimal-leading-zero
         | lower-roman
         | upper-roman
         | lower-latin
         | upper-latin
         | none
         | inherit ; 

  initial: disc ;
  inherit: yes ;
  media: visual ;
  about: url(generate.html#propdef-list-style-type) ;
}

@property list-style
{
  grammar: [ <'list-style-type'> || <'list-style-position'> || <'list-style-image'> ] | inherit ;
  initial: see individual properties ;
  inherit: yes ;
  media: visual ;
  about: url(generate.html#propdef-list-style) ;
}

@property margin-right
{
  grammar: <margin-width>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-margin-right) ;
}

@property margin-left
{
  grammar: <margin-width>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-margin-left) ;
}


@property margin-top
{
  grammar: <margin-width>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-margin-top) ;
}

@property margin-bottom
{
  grammar: <margin-width>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-margin-bottom) ;
}


@property margin
{
  grammar: <margin-width>{1,4}
         | inherit ; 

  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-margin) ;
}

@property max-height
{
  grammar: <length>
         | <percentage>
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-max-height) ;
}

@property max-width
{
  grammar: <length>
         | <percentage>
         | none
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-max-width) ;
}

@property min-height
{
  grammar: <length>
         | <percentage>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-min-height) ;
}

@property min-width
{
  grammar: <length>
         | <percentage>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-min-width) ;
}

@property orphans
{
  grammar: <integer>
         | inherit ; 

  initial: 2 ;
  inherit: yes ;
  media: visual, paged ;
  about: url(page.html#propdef-orphans) ;
}

@property outline-color
{
  grammar: <color>
         | invert
         | inherit ; 

  initial: invert ;
  inherit: no ;
  media: visual, interactive ;
  about: url(ui.html#propdef-outline-color) ;
}

@property outline-style
{
  grammar: <border-style>
         | inherit ; 

  initial: none ;
  inherit: no ;
  media: visual, interactive ;
  about: url(ui.html#propdef-outline-style) ;
}

@property outline-width
{
  grammar: <border-width>
         | inherit ; 

  initial: medium ;
  inherit: no ;
  media: visual, interactive ;
  about: url(ui.html#propdef-outline-width) ;
}

@property outline
{
  grammar: [ <'outline-color'> || <'outline-style'> || <'outline-width'> ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: visual, interactive ;
  about: url(ui.html#propdef-outline) ;
}

@property overflow
{
  grammar: visible
         | hidden
         | scroll
         | auto
         | inherit ; 

  initial: visible ;
  inherit: no ;
  media: visual ;
  about: url(visufx.html#propdef-overflow) ;
}

@property padding-top <'padding-right'> <'padding-bottom'> <'padding-left'>
{
  grammar: <padding-width>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-padding-top) ;
}

@property padding
{
  grammar: <padding-width>{1,4}
         | inherit ; 

  initial: see individual properties ;
  inherit: no ;
  media: visual ;
  about: url(box.html#propdef-padding) ;
}

@property page-break-after
{
  grammar: auto
         | always
         | avoid
         | left
         | right
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual, paged ;
  about: url(page.html#propdef-page-break-after) ;
}

@property page-break-before
{
  grammar: auto
         | always
         | avoid
         | left
         | right
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual, paged ;
  about: url(page.html#propdef-page-break-before) ;
}

@property page-break-inside
{
  grammar: avoid
         | auto
         | inherit ; 

  initial: auto ;
  inherit: yes ;
  media: visual, paged ;
  about: url(page.html#propdef-page-break-inside) ;
}

@property pause-after
{
  grammar: <time>
         | <percentage>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-pause-after) ;
}

@property pause-before
{
  grammar: <time>
         | <percentage>
         | inherit ; 

  initial: 0 ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-pause-before) ;
}

@property pause
{
  grammar: [ [<time> | <percentage>]{1,2} ] | inherit ;
  initial: see individual properties ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-pause) ;
}

@property pitch-range
{
  grammar: <number>
         | inherit ; 

  initial: 50 ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-pitch-range) ;
}

@property pitch
{
  grammar: <frequency>
         | x-low
         | low
         | medium
         | high
         | x-high
         | inherit ; 

  initial: medium ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-pitch) ;
}

@property play-during
{
  grammar: <uri> [ mix || repeat ]? | auto | none | inherit ;
  initial: auto ;
  inherit: no ;
  media: aural ;
  about: url(aural.html#propdef-play-during) ;
}

@property position
{
  grammar: static
         | relative
         | absolute
         | fixed
         | inherit ; 

  initial: static ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-position) ;
}

@property quotes
{
  grammar: [<string> <string>]+ | none | inherit ;
  initial: depends on user agent ;
  inherit: yes ;
  media: visual ;
  about: url(generate.html#propdef-quotes) ;
}

@property richness
{
  grammar: <number>
         | inherit ; 

  initial: 50 ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-richness) ;
}

@property right
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-right) ;
}

@property speak-header
{
  grammar: once
         | always
         | inherit ; 

  initial: once ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-speak-header) ;
}

@property speak-numeral
{
  grammar: digits
         | continuous
         | inherit ; 

  initial: continuous ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-speak-numeral) ;
}

@property speak-punctuation
{
  grammar: code
         | none
         | inherit ; 

  initial: none ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-speak-punctuation) ;
}

@property speak
{
  grammar: normal
         | none
         | spell-out
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-speak) ;
}

@property speech-rate
{
  grammar: <number>
         | x-slow
         | slow
         | medium
         | fast
         | x-fast
         | faster
         | slower
         | inherit ; 

  initial: medium ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-speech-rate) ;
}

@property stress
{
  grammar: <number>
         | inherit ; 

  initial: 50 ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-stress) ;
}

@property table-layout
{
  grammar: auto
         | fixed
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(tables.html#propdef-table-layout) ;
}

@property text-align
{
  grammar: left
         | right
         | center
         | justify
         | inherit ; 

  initial: <'left'> if <'direction'> is <'ltr'>; <'right'> if <'direction'> is
<'rtl'> ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-text-align) ;
}

@property text-decoration
{
  grammar: none | [ underline || overline || line-through || blink ] | inherit ;
  initial: none ;
  inherit: no (see prose) ;
  media: visual ;
  about: url(text.html#propdef-text-decoration) ;
}

@property text-indent
{
  grammar: <length>
         | <percentage>
         | inherit ; 

  initial: 0 ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-text-indent) ;
}

@property text-transform
{
  grammar: capitalize
         | uppercase
         | lowercase
         | none
         | inherit ; 

  initial: none ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-text-transform) ;
}

@property top
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-top) ;
}

@property unicode-bidi
{
  grammar: normal
         | embed
         | bidi-override
         | inherit ; 

  initial: normal ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-unicode-bidi) ;
}

@property vertical-align
{
  grammar: baseline
         | sub
         | super
         | top
         | text-top
         | middle
         | bottom
         | text-bottom
         | <percentage>
         | <length>
         | inherit ; 

  initial: baseline ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-vertical-align) ;
}

@property visibility
{
  grammar: visible
         | hidden
         | collapse
         | inherit ; 

  initial: visible ;
  inherit: yes ;
  media: visual ;
  about: url(visufx.html#propdef-visibility) ;
}

@property voice-family
{
  grammar: [[<specific-voice> | <generic-voice> ],]* [<specific-voice> | <generic-voice> ] | inherit ;
  initial: depends on user agent ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-voice-family) ;
}

@property volume
{
  grammar: <number>
         | <percentage>
         | silent
         | x-soft
         | soft
         | medium
         | loud
         | x-loud
         | inherit ; 

  initial: medium ;
  inherit: yes ;
  media: aural ;
  about: url(aural.html#propdef-volume) ;
}

@property white-space
{
  grammar: normal
         | pre
         | nowrap
         | pre-wrap
         | pre-line
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-white-space) ;
}

@property widows
{
  grammar: <integer>
         | inherit ; 

  initial: 2 ;
  inherit: yes ;
  media: visual, paged ;
  about: url(page.html#propdef-widows) ;
}

@property width
{
  grammar: <length>
         | <percentage>
         | auto
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visudet.html#propdef-width) ;
}

@property word-spacing
{
  grammar: normal
         | <length>
         | inherit ; 

  initial: normal ;
  inherit: yes ;
  media: visual ;
  about: url(text.html#propdef-word-spacing) ;
}

@property z-index
{
  grammar: auto
         | <integer>
         | inherit ; 

  initial: auto ;
  inherit: no ;
  media: visual ;
  about: url(visuren.html#propdef-z-index) ;
}

Acknowledgments

[acknowledgments]

References

Normative references

[CSS21]
Bert Bos; et al. Cascading Style Sheets, level 2 revision 1. 25 February 2004. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2004/CR-CSS21-20040225
[CSS3-WEBFONTS]
Michel Suignard; Chris Lilley. CSS3 module: Web Fonts. 2 August 2002. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2002/WD-css3-webfonts-20020802
[CSS3SYN]
L. David Baron. CSS3 module: Syntax. 13 August 2003. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2003/WD-css3-syntax-20030813
[CSS3VAL]
Håkon Wium Lie; Chris Lilley. CSS3 module: Values and Units. 13 July 2001. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2001/WD-css3-values-20010713
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. Internet RFC 2119. URL: http://www.ietf.org/rfc/rfc2119.txt
[XML10]
Tim Bray; et al. Extensible Markup Language (XML) 1.0 (Third Edition). 4 February 2004. W3C Recommendation. URL: http://www.w3.org/TR/2004/REC-xml-20040204

Informative references

[CSS3-WEBFONTS]
Michel Suignard; Chris Lilley. CSS3 module: Web Fonts. 2 August 2002. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2002/WD-css3-webfonts-20020802
[CSS3COLOR]
Tantek Çelik; Chris Lilley. CSS3 Color Module. 14 May 2003. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2003/CR-css3-color-20030514