CSS Advanced Selectors - Functional and Design Specification
Glossary
- Selector: In general, a CSS selector is a pattern to match elements in a document. The associated style declaration is applied to any element that matches the selector pattern.

Note: When discussing CSS in the context of Flex, instead of a document "element" we will use the term "component". It is assumed these components implement the necessary interfaces to participate in the Flex style subsystem.
- Type Selector: A CSS type selector matches instances of a component by local name. For example, the following simple type selector Button matches the component with local name Button (i.e. in Flex the Button component is implemented with the ActionScript class mx.controls.Button).
Button {
color: #CC0000;
}
- Class Selector: A CSS class selector matches components that meet a class condition. The CSS syntax to declare a class selector is to prefix the condition with a dot. You can either declare a class selector as a condition of a type selector, or globally to any type that meets the class condition.
.header {
background-color: #CCCCCC;
}
HBox.footer {
background-color: #999999;
}
Note: In Flex a class condition is met using the styleName attribute on a component. For example, you may have two classes of HBox: "header" and "footer". Above, the first selector applies to any component with styleName="header"; the second selector should only apply to HBox components with styleName="footer" (something that actually needs to be fixed and enforced in Gumbo, as to-date class selectors have only been global and any type in the selector is ignored).
- Pseudo Selectors (for States): A CSS pseudo selector matches components based on an additional condition that may be dynamic and not necessarily defined by the document tree.
Button:selected {
color: #CCCCCC;
}
Button:unselected {
color: #999999;
}
In Gumbo we plan to make use of pseudo selectors to apply styles to components only when they are in a specified state. Flex's use of pseudo selectors are similar to CSS pseudo-element selectors in that they can only be applied to the subject of a selector, but since a components' state is transient they are also like pseudo-class selectors in that they may gain or lose a pseudo-class over time. As such, we simply refer to these selectors in Flex as pseudo-selectors.
- Subject (of a selector): The subject of a selector is the right most simple type selector in a potentially complex set of conditions. In the following examples, Button is the subject of each of these selectors:
VBox Panel Button#button12 {
color: #DDDDDD;
}
VBox.special Button {
color: #CCCCCC;
}
Button:selected {
color: #EEEEEE;
}
Button.special {
color: #FFFFFF;
}
Summary and Background
Cascading Style Sheets (CSS) are used in Flex to apply styles to visual components on the application display list. To-date we've supported simple type selectors and global class selectors. Customers have requested for more advanced CSS selectors and in Gumbo we plan to provide two new selector types - id selectors and descendant selectors - as well as fix class selectors so that they can be a condition of type selectors.
As a B-feature we'd also like to support psuedo-selectors for component states so long as a solution can be found that also performs well.
Usage Scenarios
The usage scenarios for styling components is a general feature and well known feature in Flex. These advanced selector additions simply allow the developer to apply styles to components in a more precise manner.
Detailed Description
Flex maintains a runtime style subsystem to calculate which style properties apply to which components based on their position in the display list (as style properties may be declared for the component or inherited from a parent component).
Calculation of styles is performed at runtime because styleNames, identities, and the display list can change and this impacts which style rules match for a component. When any of these conditions change, style property caches are cleared and need to be recalculated. This may be potentially expensive so opportunities for further optimization will be sought during implementation.
To support more advanced selectors in Gumbo, the data structures that store selectors needs to be changed in both the compiler and the client runtime. Instead of only using the selector String as a key, the subject must first be identified and this should serve as a key to find the collection of rules that apply to this subject. The associated selectors will then be matched at runtime based on a component's local name (type), styleName (class), identity (id), state (pseudo-element) and/or position in the display list (descendant).
Note that identical selectors will be merged into a single style declaration in the compiler as an optimization, with the last property descriptor winning.
When determining the styles for a component at runtime, the following steps need to be taken to find the right selectors.
First, all style declarations that apply for a subject are located. Then the order of precedence needs to be considered. User styles override default styles. Then selector specificity is considered. The W3C's http://www.w3.org/TR/CSS2/cascade.html#specificity suggests calculating selector specificity as follows:
- count the number of ID attributes in the selector (= a)
- count the number of other attributes and pseudo-classes in the selector (= b)
- count the number of element names in the selector (= c)
- ignore pseudo-elements.
Then apply some suitable weight to a, b, c (such as: a*100 + b*10 + c).
If two selectors match in rank, the last one specified wins.
For example, given the following MXML snippet:
After applying following two CSS rules, the FxButton component will have a skin property of type Bar as the second selector chain has a specificity of 101, where as the first selector chain has a specificity of 10.
API Description
Today, Flex components must at least implement the mx.styles.ISimpleStyleClient interface (though typically implement the more complete mx.styles.IStyleClient interface) to participate in the style subsystem at runtime.
To match components based on advanced style selector criteria such as identity, state or descendant position in the display list, we need to introduce a new interface mx.styles.IAdvancedStyleClient.
The constructor for CSSStyleDeclaration will be expanded and the following properties and methods will be added. The compiler will determine the subject and selector and populate these values in generated code. For backwards compatibility, if the selector argument is null, the subject will be interpreted as a simple type selector name or a global class selector if it begins with a dot.
Advanced selectors require more than a simple String to represent the conditions and ancestors. A new mx.styles.CSSSelector class will be added to represent a potential chain of selectors each with conditions and ancestors.
An accompanying enumeration class mx.styles.CSSSelectorKind for the kinds of selectors will be added.
A new mx.styles.CSSCondition class will be added to record each type of selector condition.
Another enumeration class mx.styles.CSSConditionKind will be added for the different kinds of conditions.
Since mx.styles.StyleManager will need to keep track of multiple CSSStyleDeclaration}}s for each subject, we will extend the Flex 3 {{mx.styles.IStyleManager2 interface and introduce a new mx.styles.IStyleManager3 sub-interface:
B Features
We also plan to support pseudo selectors for component states, e.g. Button:stateA would apply only when the matching Button component instances were in state "stateA".
The implementation details are to be determined.
Examples and Usage
See the Glossary section for examples of the kinds of selectors and their usage in Flex.
Additional Implementation Details
To be determined.
Prototype Work
An initial prototype exists in the Gumbo Alpha release.
Compiler Work
Batik's CSS Parser already detects and creates selectors for descendant selectors, conditional id selectors, and pseudo selectors. The Flex compiler will be updated to allow these type of selectors to be defined in Flex style sheets and will generate the appropriate ActionScript code to register them with the runtime style manager.
The flex2.compiler.css.StylesContainer class's extractStyles() method must be updated to allow for more selector types. Similar updates must be made to the flex2.compiler.css.CssCompiler class's extractStyles() method (which is used to compile .css files to .swf modules).
The flex2.compiler.css.StyleDef class needs to be updated to consider more than a boolean switch controlling whether a definition is from a type selector. Instead a subject needs to be identied and multiple selectors (potentially advanced) registered for the subject.
In fact, a major limitation of the current compiler representation is that selectors are not stored by subject, but rather just by type selector name or the class constraint name if it is present - this does not handle when class constraints are applied to type selectors or where there are multiple selectors per subject. The result is the incorrect merging of styles for unrelated subjects.
Accordingly, the StyleDef.vm Velocity Template (and any associated direct AST generation code) will be duplicated to preserve existing behavior and a new section for advanced styles will be created to register the multiple runtime style declarations per subject with the style manager.
For the direct compilation of .css to .swf modules, the StyleModule.vm and StyleLibrary.vm velocity templates (and any associated direct AST generation code) must be duplicated too to handle the new kinds of advanced selectors and multiple selectors per subject.
Web Tier Compiler Impact
None expected.
Flex Feature Dependencies
The style subsystem is something that most features interact with, however, this enhancement attempts to add advanced features to the existing subsystem and other features are not expected to need to change to take advantage of these new capabilities.
Backwards Compatibility
Syntax changes
This feature introduces new CSS syntax that was not valid before and that in itself should not affect backwards compatibility.
Behavior
However, the existing behavior for class conditions is not fully implemented. Now that we're adding more complex conditions for selectors we need to fix how multiple rules are applied for a given subject.
In the following example, the two subjects of the two rules are Button and Text respectively. Both of these selectors make use of a class condition for styleName "customStyle". This is not handled in Flex today as the class constraint is merged for both subjects and the last rule overrides the color property declaration.
Button.customStyle {color:#0000FF; font-style:italic}
Text.customStyle {color:#00FF00;}
The result is that both the Button and the Text field are green and italic. However, the correct behavior is for the Button label to be italic and blue, and the text field to be plain and green. We will fix this in Gumbo.
Note: The compatibility version compiler switch will be checked and if the version is set to version 3 or earlier, we will revert to the simple CSS selector behavior.
Warnings/Deprecation
There is an existing feature where by the compiler warns if unused type selectors are declared. Gumbo introduces more complex selector scenarios, however, we will not detect whether a condition is actually met for a descendant selector. We will only warn if the class matching a simple type selector as the subject of a rule is used or not. If an id selector does not match an id in an Application, we will not give a warning.
Accessibility
TBD.
Performance
Runtime performance of calculating styles may be expensive for descendant selectors. TBD.
Globalization
None known.
Localization
Compiler Features
Any new compiler errors or warning messages related to the new selector types will be added to sdk/modules/compiler/src/java/flex2/compiler_en.properties.
Any new compiler errors or warning messages that are related to the linker (flex2.linker.* packages) will be added to sdk/modules/compiler/src/java/flex2/linker_en.properties.
Framework Features
Localization will be considered for any new runtime error messages introduced during implementation.
Issues and Recommendations
The performance of states-based "pseduo" style declarations is in question.
Documentation
Style documentation will need to be extensively updated to describe the new CSS selector types.
|