Common rules

1. Spaces

No spaces are allowed outside of the quoted values, use backslash '\' to replace space, e.g. use far-right\behind instead of "far-right behind" to describe a value for "azimuth". Exception: keyword "about", as described further.

2. Includes

To insert an external file, use the @include keyword, e.g.

@include "../bar/foo.txt";

The line above will be replaced with a content of foo.txt. Unlike described in section below, use " " - quotation only. @include-declaration cannot be nested, e.g. you can use as many @include keywords in *.lex - files as you wish, but not in the files to be included recursively

3. Strings

Strings can be written using double or single quotes. Double quotes cannot occur inside double quotes - use single quotes instead and vice versa.

"this is a 'string'"
'this is a "string"'

4. Declarations

A declaration consists of an attribute name followed by a declaration block. A declaration-block starts with a left curly brace ({) and ends with the matching right curly brace (}) and includes a list of zero or more semicolon-separated (;) declarations.

4.1 Attribute

Attributes with the same value set may be grouped to a comma-delimited list.

padding-top {...declarations...}
padding-right {...declarations...}

may be (and this is even better for increasing the speed of lexical analysis) grouped like

padding-top, padding-right {

Unlike CSS rules, the parser reads only one attribute or attribute group at a time. Thus,

background-color { ...declarationA... }
background-color { ...declarationB... }

will be not merged by the parser; the declaration A will be used because the parser halts after reading first attribute name and it's declaration.

4.2 Values

A values declaration consists of a property, followed by a colon (:), followed by a value(s). Close the attribute with a semicolon if more values follow.

4.3 Keywords in values-blocks

The following keywords are used:


enum if the attribute has enumeration, e.g.
enum: thin medium thick inherit;
enum: custom_value1 custom_value2 @common-types.generic-fonts;
enum: @common-types.colors-common

If you use the default @common-types declaration, declaration name may be omitted , i.e.
enum: custom-value1 custom-value2 .size-relative;

Read more in @common-types block description.


units is a keyword for units from the @units-section, multiple values allowed.

Additionally may be used keywords :

"string", "decimal-all", "decimal-positive", "decimal-negative", "float-all",
"float-positive", "float-negative", "font-list", "rgb-percengage", "rgb-bytes"


units: angle-decimal; produces error if value is 2.4rad
units: angle-real produces error if value is 2rad
units: angle-decimal angle-real; produces neither error for 2.4rad nor for 2rad.
units: string; expects a " or ' - enclosed value string
units: decimal-all; expects a whole number
units: decimal-all; float-all expects any number
units: rgb-bytes; match if given value is rgb(R,G,B) where RGB are in range byte (0-255)


default is default value for the attribute. This value may be omitted; or use default:none instead. e.g.

default: "my favorite color";


dialog is a keyword for dialog used in property editor. Use dialog: none or omit this value if there is no dialog expected

Following values are implemented:

dialog: color;
dialog: css-color; (an additional rgb - return allowed)
dialog: url;
dialog: css-url; (an additional url(...) - return allowed)
dialog: image:
dialog: css-image; (see above)
dialog: datetime;
dialog: font: (system font only: no multiple fonts)
dialog: font-face; (a multiple font-face dialog)
dialog: clipping; (clip dialog)
dialog: units; (a visual select of length or percentage units)
dialog: border-style: (a visual select of border style)

Units dialog allow various suffixes to modify its behaviour:

dialog: units-<suffix>, where following siffixes used:

allowabsolute - allow absolute units (like 2px, 7pt, 3pc, 4in, 0.5mm, 10cm)
allowrelative - allow relative units (1em, 2ex)
allowpercentage - allow percent values (50%)
allownegative - a return value may be negative
allowfloating - a return value may be not a whole number only
allowall - allow any length or percentage value; used with deny-suffixes, s. below.

Also, dialog: units-allowall and dialog: units has the same meaning; ONLY in this case, allowall may be omitted.

denyabsolute - do not allow absolute units
denyrelative - do not allow relative units
denypercentage - do not allow percentage
denynegative - do not allow negative values
denyfloating - allow whole numbmers only

if you use deny-suffixes, allowall may NOT be omitted. Also an entry like dialog: units-denyrelative will be completely misunderstood by lexer; hereby no  units are available at all and dialog is useless.


dialog: units-allowabsolute-allowrelative-allownegative;
- allow absolute and relative values; there may be negative. Percentages and floating-point numbers are not allowed

dialog: units-allowall-denypercentage;
- allow all except percentage


allowed values:

no|off|false (default; may be omitted)

e.g. read-only:yes;

set read-only:yes if you want to restrict direct user input into property editor. Note that at least one from enum: or dialog: propertis must be assigned in this case.


allowed values:

no|off|false (default; may be omitted)

i.e. multiple: yes;

Default No.

The lexer does not validate multiple values. To perform a basic multiple-value validation, use the keywords max-values and min-values described below. A shorthand-property defined in @shorthand-properities section does not need be marked as multiple; the validation occures at the basis of subproperties description.


allowed values: number between 1 and 255. Default: not defined

i.e. max-values:4;

The keyword will be ignored in all non-multiple sections. The lexer splits the values string into the value-list, receives the list counter and produces "Too many values" error, if the counter is greater than the max-values.


allowed values: number between 0 and 255. Default: 0

i.e. min-values: 1;

The keyword will be ignored in all non-multiple sections. The lexer splits the values string into the values list, receives the list counter and generates the "Too less values" error, if the counter is less than the min-values. If both max-values and min-values are defined, the lexer checks the value range. If min-values is larger then max-values, it will be ignored by lexer.


Prescribe when the CSS property editor should be updated. The following values are allowed:

on-enter - when user press ENTER-key, select a value from popup list or confirm property dialog
by-input - while user modifies editor content

Default value on-enter, in this case keyword may be omitted.


allowed values:

none (default; may be omitted)

e.g. revertable:validate;

escape: the property reverts to a previous value by pressing ESC key
validate: the property reverts to a previous value if new value is invalid or by pressing ESC.


Sort values in property value list on the basis of given attribute.

allowed values:


i.e. sort-values:descend;

The default value is no, in this case the keyword may be omitted.


allowed values:

no|off|false (default; may be omitted)

e.g. skip-check:yes;

set skip-check:yes if you want to ignore syntax check for the values, even if the attribute "enum" and /or "units" is used.


allowed values:

no|off|false (default; may be omitted)

e.g. skip-check-values:yes;

set skip-check-values:yes if you want to ignore syntax check for the values, even if the attribute "enum" is used. Units matching stays hereby enabled


allowed values:

no|off|false (default; may be omitted)

e.g. skip-check-units:yes;

set skip-check-units:yes if you want to ignore syntax check for values, even if the attribute "units" is used. Enum matching stay hereby enabled


A short attribute description. Example:

border-width: {
about: The border width properties specify the width of the border area.;

The about: pair must be a single line. It must be quoted if there are control chars like colon, semicolon or curly brackets inside.


Link to attribute description. Example:

border-width: {
help: "box.html#propdef-border-width";

It is used together with the @internal-settings rule, see below



Browser compatibility for the described property. The values are all, none or list of named browsers from the @browsers section.


browser-support-full:NS5 NS6 IE5 IE55 IE6;
browser-support-partial:NS4 IE4;


allowed values:

yes|on|true (default; may be omitted)

Set visible: false if you want to declare a property but suspend it from lexer (also "Unknown property" - error will be produced), top-level nodes of property inspector and autocomplete.

An example of usage in CSSl Level1.lex:

The property border-style is a part of CSS Level 1, but the subproperties border-<left|right|top|bottom>-style are not. You can declare such properties anyway and make them invisible via visible: false:

border-top-style, border-right-style, border-bottom-style, border-left-style {
enum: none dotted dashed solid double groove ridge inset outset;
default: none;
visible: false;

Add it also in @shorthand-properties:

@shorthand-properties {
border-style: border-top-style, border-right-style, border-bottom-style, border-left-style;

Thus, now the lexer can check all the values as well as assign subnodes to the border-style node in the property inspector. But the Unknown property-error will be further generated for single border-<side>-style because it is not a part of given implementation.

4.4 Empty blocks

A block may be empty, i.e.
my_attribut {


In this case, the parser will not generate the "Unknown property" - error, but will not check if value is legal neither.

5. End of the file

Insert a line containing >>END to stop the parser reading anything after this line. So you can add custom notes, even HTML-formatted text to display in the user agent.

6. Reserved @-keywords

Reserved @-keywords are:


See the descriptions below.

7. Rules for @units section

Use Regexp syntax for single value. You can also use a space-delimited list of the regular expressions. When retrieving a list, any expression in the list that includes spaces, commas or quotes will be enclosed in double quotes, and any double quotes in a string will be duplicated. my-units: "regexp with spaces" simple_regexp "regexp,with,commas" regexp_with""quotes " regexp"" with quotes and spaces";

There are some special keywords that can be used inside the @units-declaration:


string: matches when the value is single or double-quoted string, like described in (3)
decimal-positive: matches if the value is positive whole number, i.e. 12345
float-positive: matches if the value is positive real number, i.e. 0.12 or .12 or 1.0
decimal-negative: matches if the value is negative whole number, i.e -12345
float-negative: matches if the value is positive real number, i.e. -0.12 or -.12 ot -1.0
decimal-all and float-all : matches decimal or real numbers, respectively
font-list: matches valid font-family description.
link: matches valid "url([link])" declaration. Note that url itself will be NOT validated.
rgb-percentage: matches valid rgb(R%,G%,B%) color value with range check (0-100%)
rgb-bytes: matches valid rgb(R,G,B) color value with range check (0-255)

Note: It is not possible to check the existence of a named font. So, "font-list: can only check the format of the font-family value as well as whether it contains at least one generic font. I.e. to allow percentage, string, negative float or positive integer value, use something like:

my-elaborate-unit: [-\d]% string float-negative decimal-positive;

Example (as declared in

@units {
  absolute-units: [-\d]p[xtc]\b [-\d]in\b [-\d][mc][m]\b 0;
  absolute-units-positive: [\d]p[xtc]\b [\d]in\b [\d][mc][m]\b 0;
  relative-units: [-\d]e[mx]\b 0;
  percentage: [-\d]% 0;
  colors: #[\d]\b #[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\b #[\d]\b #[0-9a-
fA-F][0-9a-fA-F][0-9a-fA-F]\b rgb-percentage rgb-bytes;
  angle: [-\d]deg\b [-\d]grad\b [-\d]rad\b;
  frequence: [-\d]Hz\b [-\d]kHz\b;
  time: [-\d]ms\b [-\d]s\b;
  link: link;
  string: string;
  decimal-positive: decimal-positive;
  float-positive: float-positive;
  decimal-negative: decimal-negative;
  float-negative: float-negative;
  decimal-all: decimal-all;
  font-list: font-list

8. @common-types - type declaration by default.

After this declaration you can add @-declarations at your convenience. To get enum types from @-declaration use syntax. I.e.

my-attribute {
enum: custom-value1 custom-value2 @custom-at-declaration.custom-fonts;

If you use default @common-types declaration, declaration name may be omitted , i.e.
enum: custom-value1 custom-value2 .size-relative;

The lexer will get values for .size-relative from @common-types list and value list will look like:

custom-value1 custom-value2 larger smaller

8.1 Parser engine settings for url()

The value lists may be inserted into @common-types of custom @-declaration via url() directive. A value under url() must always be a relative path to the file where the declaration is inserted, in Windows or Unix-notation:

url(mylist.txt) seeks for a file in the current directory.
url(includes/mylist.txt) or url(includes\mylist.txt) seeks for a file in the subdirectory "includes".
url("../../Program files/mylist.txt") go 2 levels up and into "Program files" directory

parse|no-parse|relpace-returns-only: enables or disables value parser engine.

A default value is "parse" and can be omitted. If no-parse, the content of an url() will be inserted as-is; additional switch replace-returns-only replaces CL, RF or their combinations with a single space.
If parse (default), the following attributes can be used:

delimited-by: values delimiter. For chars<32 use notation #ASCII-No, e.g. #10 for LF, default value:
comma (,)
first-char: char where parsing begins. Default none (begins from 1st char)
last-char: char where parsing halts. Default none (parse up to the end of the string)
ignore-chars: comma-delimited list of the first chars of the value to be ignored
ignore-values: a comma-delimited list of values to be ignored
trim|trim-left|trim-right|no-trim: cut spaces left, right or around values. Default no-trim
lower-case|upper-case|capitalize|as-is: values modifier. Default as-is
Spaces in attributes are allowed only within strings (enclosed in "" or ''). Thus, the notation: ignore-values ("foo, bar") is valid, but bar matches [space]bar. The notation ignore-values (foo, bar) is invalid and parser does not read "ignore-values" attribute at all
WARNING: Getting a value list via url() significantly slows down the parser engine. To increase the lexer speed, avoid using url() and set values directly into the property list.

Example (as declared in
@common-types {
  screen-fonts: &dynamic;
  printer-fonts: &dynamic;
  generic-fonts: serif sans-serif cursive fantasy monospace;
  size-absolute: xx-small x-small small medium large x-large xx-large;
  size-relative: larger smaller;
  absolute-and-relative-positive-units: [\d]p[xtc]\b [\d]in\b [\d][mc][m]\b [\d]e[mx]\b;
  colors-common: black gray maroon red green lime olive yellow navy blue purple fuchsia teal
  aqua silver white;
  colors-system: activeborder activecaption appworkspace background buttonface buttonhighlight
buttontext captiontext graytext highlight highlighttext inactiveborder inactivecaption infobackground
infotext menu menutext scrollbar threeddarkshadow threedface threedhighlight threedlightshadow
threedshadow window windowframe windowtext;
  colors-all: url(../html/ delimited-by("|") first-char("[") last-char("]") ignore-chars("@") trim

Language-dependend rules

9. @internal-settings

This section used for various uncategorized parser settings .

help-base-url is a top location of used dialect documentation
help-base-local is always relative to \help_system\

Do not add slash or backslash at begin of help-base-local value. The settings are used together with the "help" keyword of each property description

@internal-settings {
help-base-local: css2/

The sections described below are usually dialect-dependent and it is better not to include them in
the include-files.

10. @-keywords - parser settings for at-keywords used in a dialect.

What keywords are allowed in the described CSS-dialect and how the parser must scan its content?


allow- parse keyword content.

allow-line: parses a line until a semicolon after declaration
allow-block: parses keyword content as a common declaration block
allow-subset: parses content recursively, use it i.e. with @media node.

deny- produces error "Unknown @at - keyword"

deny-block produces error, but followed block will be parsed
deny-line produces error and skips until a semicolon at the end of the declaration

ignore- produces no error

ignore-block parses followed block
ignore-line skips until a semicolon at the end of declaration

The formatter encloses ignored keywords in output file in comment-delimiters.


@at-keywords {
  allow-line: import charset;
  allow-subset: media;
  allow-block: page;
  deny-line: namespace;
  ignore-line font-face;


Allowed values: semicolon-reset | no-reset | fatal-error

Default: semicolon-reset, may be omitted.

"semicolon-reset" means that parser scans up to the next semicolon and adds an Unknown @-keyword node  just like a @charset or @import node, without a block. When node added, parser waits for the next token like a selector or @-keyword (also no attributes or values). This is the safest method.

"no-reset" forces parser to ignore any semicolon and parse up to the next opened curly bracket.
"fatal-error" means that parser generates fatal error and halts. Use this directive on your own risk.

11. @shorthand-properties - a shorthand-properties definition

@shorthand-properties section could be used to check whether one or more properties were redefined inside of the selector. Notation: property-name: property-child-1 property-child-2 property-child-N


@shorthand-properties {
  font: font-style font-variant font-weight font-size line-height font-family;
  margin: margin-left margin-top margin-right margin-bottom;
  padding: padding-left padding-top padding-right padding-bottom;
  border: border-width border-style color;
  border-top: border-width border-style color;
  border-right: border-width border-style color;
  border-bottom: border-width border-style color;
  border-left: border-width border-style color;
  list-style: list-style-type list-style-image list-style-position;
  background: background-color background-image background-repeat background-attachment background-position

12. @Group-file - grouping of attributes


@group-file {
default: "CSS Level";

The parser seeks for a file with the same name in the same folder, but with the *.group extension. If  no files are found, attributes cannot be grouped. To ungroup the attributes explicitly, even if the file does exists, use the default: none; In this case, the whole @group-file section cannot be omitted.

The format of group - file based on INI file format

[Group name 1]

[Group name 2]

You can also repeat attributes in several groups, if for example you want to use the Favorites group for frequently used attributes:

attribut_1 'from Group name 1
attribut_2_1 'from Group name 2

The property editor appends all ungrouped (and unknown) attributes to the end of the list.

13.@pseudo - Pseudo-classes and pseudo-elements

What pseudo-classes and / or pseudo-elements are allowed? A selector notation like

#new_id[..attributes...]:pseudo-description will produce a PseudoClass or PseudoElement-error, if "pseudo-description" name is not found in the pseudo-classes or pseudo-elements declarations, respectively.


@pseudo {
pseudo-classes: first-child link visited hover active focus lang;
pseudo-elements: first-line first-letter before after

14. Special rules (@special-rules)

A list of selectors / rules with an different behaviour
-limited-by: limited allowed properties to list below
-pseudo-classes: allow additional pseudo-classes to given rule


@special-rules {
@page-limited-by: margin-top margin-right margin-bottom margin-left margin;
@page-pseudo-classes: left right first;

15. Dynamic shorthand properties (@dynamic-properties)

Some shorthand properties have different meanings depending on their count: margin, padding, border-width and so one. I.e, padding: If there is only one value, it applies to all sides. If there are two values, the top and bottom borders are set to the first value and the right and left are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values, they apply to the top, right, bottom, and left, respectively.

The section @dynamic-properties can bias its behaviour and dynamically create subproperties list for given value.

Notation: property-name-<values-count>: <subproperties-list>


margin-2: margin-(top-bottom) margin-(left-right)

If the values count exceeds the maximum defined values count, the maximum count will be used,
and the rest is included in the (unassigned)-node.
Example: margin: 1px 2px 3px 4px 5px

looks in the property inspector like

- margin
    margin-top 1px
    margin-right 2px
    margin-bottom 3px
    margin-left 4px
    (unsupported) 5px

Respectively, margin: 1px 2px foo

looks like

- margin
    margin-(top-bottom) 1px
    margin-(left-right) 2px
    (unsupported) foo

Note that fake shorthand-subproperties like "margin-(top-bottom)" must be defined anywhere in lexer file and marked with visible: false to provide property and value check. The round brackets in the property description are optional; we use them only to differ fake properties from real properties. If you don't like them, feel free to modify the lexer file as you want.