Adobe Open Source
   Home     Projects     Source     Documentation     Forums    About
Welcome Guest | Sign In
 

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).

  • id Selector: A CSS id selector matches components that meet an id condition. The CSS syntax to declare an id condition is to prefix the id with a hash sign.
    #button13 {
    background-color: #CCCCCC;
    }
    
    Button#button13 {
    background-color: #999999;
    }

    Note: In Flex an id condition is met by setting the id attribute on a particular component.

  • Descendant Selector: A CSS descendant selector matches components depending on their relationship to ancestor components in the document. A descendant selector allows you to match components based on whether they descend (i.e. are children, grandchildren, great grandchildren, etc...) from particular types of components.
    Panel Button {
    color: #CCCCCC;
    }
    
    VBox Panel Button {
    color: #999999;
    }

    Note: In Flex the ancestor/descendant relationship is determined based on the display list. Styles are only applied to components in the display list and thus when matching based on a relationship to an ancestor component, those ancestors must also be in the display list.

  • 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:

<Group>
   <FxButton styleName="sbUpButton" id="upButton" />
</Group>

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.

<Style>
    .sbUpButton {
        skin: Foo;
   } 

   Group #upButton {
    skin: Bar;
  }
</Style>

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.

package mx.styles
{

public class IAdvancedStyleClient extends IStyleClient
{
public function get currentState():String;

public function get id():String;

public function get styleParent():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.

package mx.styles
{

public class CSSStyleDeclaration
{
...

public function CSSStyleDeclaration(subject:String=null, selector:CSSSelector=null);

...

mx_internal function get selector():CSSSelector;

public function get subject():String;


...

public function isAdvanced():Boolean;

public function isMatch(object:IAdvancedStyleClient):Boolean;

public function isPseudoSelector():Boolean;

...
}

}

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.

package mx.styles
{

public class CSSSelector
{

public function get ancestor():CSSSelector;

public function get conditions():Array; /* of CSSCondition */

public function get kind():uint;

public function get specificity():uint;

public function get value():String;


public function isPseudoSelector():Boolean;

public function isMatch(object:IAdvancedStyleClient):Boolean;

public function toString():String;
}

}

An accompanying enumeration class mx.styles.CSSSelectorKind for the kinds of selectors will be added.

package mx.styles
{

public class CSSSelectorKind
{
    public static const TYPE_SELECTOR:uint = 1;
    public static const DESCENDANT_SELECTOR:uint = 2;
    public static const CONDITIONAL_SELECTOR:uint = 3;
}

}

A new mx.styles.CSSCondition class will be added to record each type of selector condition.

package mx.styles
{

public class CSSCondition
{

public function get kind():uint;

public function get specificity():uint;

public function get value():String;

public function isMatch(object:IAdvancedStyleClient):Boolean;

public function toString():String;
}

}

Another enumeration class mx.styles.CSSConditionKind will be added for the different kinds of conditions.

package mx.styles
{

public class CSSConditionKind
{
    public static const CLASS_CONDITION:uint = 1;
    public static const ID_CONDITION:uint = 2;
    public static const PSEUDO_CONDITION:uint = 3;
}

}

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:

package mx.styles
{

public class IStyleManager3 extends IStyleManager2
{

function get typeHierarchyCache():Object;
function set typeHierarchyCache(value:Object):void;


function addStyleDeclaration(decl:CSSStyleDeclaration, update:Boolean=false):void;

function getStyleDeclarations(subject:String):Object; // Ordered map of selector String, CSSStyleDeclaration

function hasPseudoSelector(subject:String):Boolean;

function hasAdvancedSelectors():Boolean;
}

}

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.

Flex SDK Project
Home
About
Versions
Downloads
Source
Bug Database
Submitting a Patch
Developer Documentation
Forums
License

Pages
Comments

Other Projects
BlazeDS
Cairngorm
Corelib
FlexUnit

More related projects ›
More Adobe projects ›
You must be logged in to comment.

 
Last Modified: 2008-10-22 17:39:57.0
Powered by Atlassian Confluence 2.7.1, the Enterprise Wiki.

Company | Online Privacy Policy | Terms of Use | Contact Us | Accessibility | Report Piracy | Permissions & Trademarks

Copyright @ 2008 Adobe Systems Incorporated.
Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.
Search powered by Google