CSS Advanced Selectors - Functional and Design SpecificationCSS Advanced Selectors - Functional and Design Specification | Glossary | Summary and Background | Usage Scenarios | Detailed Description | API Description | B Features | Examples and Usage | Additional Implementation Details | Prototype Work | Compiler Work | Web Tier Compiler Impact | Flex Feature Dependencies | Backwards Compatibility | Accessibility | Performance | Globalization | Localization | Issues and Recommendations | Documentation
Glossary
Note: Flex has an alternate special root selector called "global" which functions as the root of the inheriting style protochain. Additional conditions are not meaningful on the "global" selector.
Summary and BackgroundCascading 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 universal class selectors. Customers have requested 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 plan to support psuedo-selectors for component states. Update: With the dropping of the Fx prefix from Spark component names, CSS type selectors must now be namespace qualified to avoid collisions between MX and Spark component names. Namespace qualified type selectors will be resolved to an ActionScript classname in the same manner that an MXML tag would (i.e. through top level manifests configured in flex-config.xml and swc catalog.xml files). See the CSS Namespaces Support specification for more details. Usage ScenariosThe usage scenarios for styling components is a well known feature in Flex. These advanced selector additions simply allow the developer to apply styles to components in a more precise manner. Detailed DescriptionFlex 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 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. New selector typesFlex 3 supports simple type selectors and universal class selectors: Button { color:#00FF00; } /* Simple type selector */
.special { color:#FF0000; } /* Universal class selector */
In Gumbo, in addition to these selectors, we plan to add support for class conditions on type selectors, id selectors, descendant selectors and pseudo-selectors: Button { color:#00FF00; } /* Simple type selector */
.special { color:#FF0000; } /* Universal class selector */
Button.special { color:#FF0000; } /* Type selector with a class condition */
Button#b13 { color:#0000FF; } /* Type selector with an id condition */
#b13 { color:#FF9933; } /* Universal id selector */
Panel VBox Button { color:#990000; } /* Descendant selector */
Button:up { color:#FF9900; } /* Type selector with a pseudo-condition */
:up { color:#FF9933; } /* Universal pseudo-selector */
To support these new selectors the data structures used to store style information 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) and/or position in the display list (descendant). See the Glossary section above for examples and an explanation of each type of selector. The styleName property now supports a list of class selectorsIn Gumbo, the styleName property will be enhanced to support a list of class selectors separated by a space. In the following example, the Button will match on the .redText class selector even though it additionally specifies a list of classes in its styleName property. (It would also match a .smallText class selector if one were declared). <Style>
@namespace "library://ns.adobe.com/flex/spark";
Button.redText {
color:#FF0000;
}
</Style>
<Button styleName="redText smallText" />
CSS selector specificityWhen 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. Developer specified 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:
If two selectors match in rank, the last one specified wins. This means the declaration order must be preserved. For example, given this MXML snippet: <s:Group> <s:Button styleName="sbUpButton" id="upButton" /> </s:Group> After applying the following two CSS rules, the Button 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>
@namespace "library://ns.adobe.com/flex/spark";
.sbUpButton {
skin: Foo;
}
Group #upButton {
skin: Bar;
}
</Style>
Identical selectors and declaration orderIdentical selectors will continue to be merged into a single style declaration in the compiler as an optimization; the last property descriptor declared wins. However, in Flex 3, adding multiple identical selectors were not supported at runtime. The last selector added would override the entire previous selector rather than merging the corresponding property declarations. In Gumbo we will simply retain multiple identical selectors at runtime and the declaration order will be preserved when gathering selector matches. <Style>
@namespace "library://ns.adobe.com/flex/spark";
Button.foo {
color:#FF0000;
}
Button.foo {
font-family:"Arial";
}
</Style>
API DescriptionToday, 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 interface IAdvancedStyleClient extends IStyleClient
{
function get id():String;
function get styleParent():IAdvancedStyleClient;
function matchesCSSState(cssState:String):Boolean;
function matchesCSSType(cssType:String):Boolean;
}
}
The constructor for CSSStyleDeclaration will be modified by relaxing the type to Object to allow for both legacy String selectors and new strongly typed CSSSelector instances, and the following properties and methods will be added. For backwards compatibility, if the selector argument is null, the subject will be interpreted as a simple type selector name or a universal class selector if it begins with a dot. package mx.styles
{
public class CSSStyleDeclaration
{
...
public function CSSStyleDeclaration(selector:Object=null);
...
public function get selector():CSSSelector;
public function set selector(value:CSSSelector):void;
mx_internal function get selectorString():CSSSelector;
mx_internal function set selectorString(value:String):void;
public function get specificity():int;
public function get subject():String;
...
public function matchesStyleClient(object:IAdvancedStyleClient):Boolean;
mx_internal function isAdvanced():Boolean;
mx_internal function getPseudoCondition():String;
...
}
}
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 CSSSelector(subject:String, conditions:Array=null, ancestor:CSSSelector=null);
public function get ancestor():CSSSelector;
public function get conditions():Array; /* of CSSCondition */
public function get specificity():int;
public function get subject():String;
mx_internal function getPseudoCondition():String;
public function matchesStyleClient(object:IAdvancedStyleClient):Boolean;
public function toString():String;
}
}
A new mx.styles.CSSCondition class will be added to record each type of selector condition. package mx.styles
{
public class CSSCondition
{
public function CSSCondition(kind:String, value:String)
public function get kind():String;
public function get specificity():int;
public function get value():String;
public function matchesStyleClient(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:String = "class";
public static const ID:String = "id";
public static const PSEUDO:String = "pseudo";
}
}
Since mx.styles.StyleManager will need to keep track of multiple CSSStyleDeclaration's for each subject, we will update the Flex 3 mx.styles.IStyleManager2 interface as follows: package mx.styles
{
public interface IStyleManager2
{
...
function get typeHierarchyCache():Object;
function set typeHierarchyCache(value:Object):void;
...
function getStyleDeclarations(subject:String):Array; // Array of CSSStyleDeclaration
function hasPseudoCondition(state:String):Boolean;
function hasAdvancedSelectors():Boolean;
}
}
B FeaturesWe also plan to support pseudo selectors for component states. Pseudo selectors can only be specified on the subject of a style declaration selector. In order for components to make use of pseudo selectors, they must implement the mx.styles.IAdvancedStyleClient interface. For non-skinnable Spark components (i.e. those derived from spark.components.supportClasses.GroupBase) and MX components (see Enhanced States Syntax), pseudo selectors are matched based on the value of a component's currentState property. For skinnable Spark components (see Gumbo Skinning), pseudo selectors are matched based on the current skin state, e.g. Button:up {color:#FF0000}
...would apply only when the matching Button component skin was in the "up" state. When a component state changes, the style proto-chain of a component (and any of its children) may need to be recalculated. We will need to pay close attention to whether state changes will actually cause a change in the matching CSS selectors to avoid recalculating styles (and hence redrawing the display list) if no change would be observed. Examples and UsageSee the Glossary section for examples of the kinds of selectors and their usage in Flex. Additional Implementation DetailsTo be determined. Prototype WorkAn initial prototype exists in the Gumbo Alpha release. Compiler WorkBatik'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 ImpactNone expected. Flex Feature DependenciesThe 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 CompatibilitySyntax changesThis feature introduces new CSS syntax that was not valid before and that in itself should not affect backwards compatibility. BehaviorHowever, 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/DeprecationThere 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. AccessibilityTBD. PerformanceRuntime performance of calculating styles may be expensive for descendant selectors. TBD. GlobalizationNone known. LocalizationCompiler FeaturesAny 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 FeaturesLocalization will be considered for any new runtime error messages introduced during implementation. Issues and RecommendationsThe performance of states-based "pseduo" style declarations is in question. DocumentationStyle documentation will need to be extensively updated to describe the new CSS selector types. |
|
| You must be logged in to comment. |
|---|
We did end up getting some support in for pseudo-selectors so if you get a chance to try out a nightly build or wait for beta 1 we'd really appreciate your feedback. For gumbonents, i.e. skinnable components introduced in Gumbo, the pseudo-selector matches against the skin state. For all other components, it matches against the document state that the component instance happens to be in.
I'm fairly new to the Adobe communities and my apologies if this isn't the right place to post my comment. It seems to me that most of the examples I've found relating to styles in Flex show a style being applied to a visual object, like a button, but I am interested in applying styles to html text content displayed in a TextArea, including margins and padding support. I'd like to be able to do create a stylesheet with multiple rules in mxml, give the sheet an ID, and then assign the sheet to the TextArea, so it can be applied to all classes in the TextArea's html content. Something like this:
http://forums.adobe.com/thread/522307?tstart=0
Thanks


I'd like to vote for that: "As a B-feature we plan to support psuedo-selectors for component states."
Cheers, David