CSS Prototypes

Contents

three designs

Definining prototypes via the @prototype rule

The @prototype rule allows document authors to structure and abstract meaningful layers in their CSS selector architecture. It also allows browsers to parse far less code, because base classes will not be redefined in every instance of an object. The prototype name is a class selector that identifies the prototype being declared. The '@prototype' keyword must be followed by the prototype name and a declaration block.

The following example defines a prototype based on standard module format:

@prototype .mod {
margin: 10px;
}

Referencing a prototype via the extends property

Using a prototype definition in a CSS declaration should be achieved using the new extends property. UAs should ignore include statement if the prototype does not exist and, if the UA provides an API to the document author, issue a warning via that API.

Examples:

.weatherMod {
extends: .mod;
}

A preprocessor would output the following code:

.mod, .weatherMod{ ... }
.mod .inner, .weatherMod .inner { ... }
.weatherMod { ... }

UAs should respect the original cascade order of the rules declared for both mod and weatherMod when processing @prototype rules. Unlike @mixin property value pairs are not copied to the current location in the code. UAs may choose to process the html as though all elements with the class name weatherMod also had the class name mod.

Multinode prototypes

@@@Prototypes are then modified by any selector which includes the prototype class name. Any subnodes in modifying rulesets become shadow nodes of the prototype and can only be modified by objects that extend the prototype.

.mod .inner {
position: relative;
}

Inner is now a subnode of the mod prototype. It cannot exist idependently from mod and cannot be modified by any class which does not extend mod.@@@

Subnodes become shadow nodes, which means they belong to the prototype object. When the prototype is extended, subnodes are also affected.

Encapsulation

UAs should not allow classes which do not extend a prototype to modify subnodes belonging to the prototype. All subnodes do not belong to a prototype, but rather only those which have been included in a selector string containing the class name associated with that prototype. Consider the following invalid example.

.leftCol .inner {
color:red;
}

UAs should ignore this invalid rule because left col does not extend mod and therefore cannot style inner because it is a subnode of the mod prototype. If a developer API is provided by the UA, a warning should be issued indicating that this rule was ignored.

.leftCol h3 {
color:red;
}

This rule, while bad form, is valid because h3 is not a property node of the mod object, even if h3 happens to be inside a module within the left column.

CSS Object Model: the 'extends' property

'extends'
Value:   <simple selector> | <group>
Initial:   none
Applies to:   all
Inherited:   no
Percentages:   N/A
Media:   all
Computed value:   as specified

This property specifies whether an element extends another element. Its goal is to limit the number of classes which need to be applied to an HTML element for proper code abstraction and to pull the abstraction layer into the CSS where it can more easily be managed or modified throughout the life of the site. Values have the following meanings:

<simple_selector>
A simple selectors, limited to class names.
<group>
Several simple selectors grouped into a comma-separated list.
 

UAs must apply the 'extends' property each time the value matches the selector of another rule. Any portion of the document tree matching the value should be duplicated for the selector on which the extends property was invoked. The specificity and cascading order should exactly match that of the original document tree.

Example(s):

Consider the following example of a main navigation list which extends a base-class nav. Here is the source:

<ul class="mainNav">
<li>Home</li>
<li>About</li>
<li>Products</li>
</ul>

Here is the style sheet controlling the extends property:

.nav{background-color: #e2e2e2; border: solid 1px gray;}
.mainNav{background-image: url(nav.png); extends:.nav;}
Test Suites

If correctly implemented, the following CSS and CSS/HTML solutions would produce the same result as the extends example above. Preprocessors or compilers could be implemented to achieve this result for UAs that do not support the extends property.

The comma-delimiter equivalent quickly becomes unreadable and unmaintainable on style sheets of even average complexity, but is useful as part of a preprocessor or POC.

A preprocessor would output the following code:

.nav, .mainNav{background-color: #e2e2e2; border: solid 1px gray;}
.mainNav{background-image: url(nav.png);}

The multiple class equivalent uses multiple class names to achieve the same rendering. Unfortunately it leads to extraneous and often abstract class names and a dependency on HTML to define CSS abstractions.

Mulitiple class equivalent:

<ul class="nav mainNav">
<li>Home</li>
<li>About</li>
<li>Products</li>
</ul>

Style sheet:

.nav{background-color: #e2e2e2; border: solid 1px gray;}
.mainNav{background-image: url(nav.png); }

Complex Selectors

Only simple selectors may be used to identify or extend prototypes. These simple selectors are limited to class names.

Incorrect usage. Avoid infinite loops.

The following code is invalid.
.foo{extends: .bar}
.bar{extends: .foo}
Multiple extends properties in one ruleset

When extends is declared twice the last definition overwrites the first according to normal rules of the cascade.

.bar {extends: .foo; extends: .moo}

In the example above, bar would extend only moo and would not extend foo.

CSS Object Model: the 'required' property

'required'
Value:   required | optional | integer | inherit
Initial:   optional
Applies to:   all
Inherited:   no
Percentages:   N/A
Media:   all
Computed value:   as specified

This property allows a document author to indicate that the last node in a selector string must be present in the HTML. It can only be used when the node is a subnode of an @prototype. Values have the following meanings:

<required>
The node must be present. If not the UA should issue a warning through relevant developer APIs.
<optional>
The node may or may not be present.
<integer>
The number of nodes required
<inherit>
Inherits value as defined by parent

UAs must add the missing nodes to the prototype if they are not present in the HTML. (@@@Good idea???)