Cascading
Style Sheets (CSS) are a standard mechanism for declaring text styles in
HTML and most scripting languages. A style sheet is a collection
of formatting rules for types of components or classes that include
sets of components. Flex supports the use of CSS syntax and styles
to apply styles to components.
The dremsus.com blog has several examples of using CSS with
Flex.
In CSS syntax, each declaration associates a style name, or selector,
with one or more style properties and their values. You define multiple
style properties in each selector by separating each property with
a semicolon. For example, the following style defines a selector
named myFontStyle:
<?xml version="1.0"?>
<!-- styles/ClassSelector.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Style>
.myFontStyle {
fontSize: 15;
color: #9933FF;
}
</fx:Style>
<s:VGroup>
<!-- This button has the custom style applied to it. -->
<s:Button id="myButton" styleName="myFontStyle" label="Click Me"/>
<!-- This button uses default styles. -->
<s:Button id="myButton2" label="Click Me"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
In this example, myFontStyle defines
a new class of styles, so it is called a class selector.
In the markup, you can explicitly apply the myFontStyle style
to a control or class of controls.
A type selector implicitly applies itself to all components
of a particular type, as well as all subclasses of that type. If
you use type selectors, then you must be sure to define namespaces
with the @namespace directive in the CSS so that
Flex. This is because classes in different packages often share
the same class name.
The following
example defines a type selector named Button:
The executing SWF file for the previous example is shown below:
Flex applies this style to all Button controls, and all subclasses
of Button controls in the Spark namespace. If you define a type
selector on a container, that style applies to all children of that
container if the style is an inheriting style.
Flex also supports id, descendent, and pseudo selectors.
When discussing CSS in Flex, the subject of a selector
is the right-most simple type selector in a potentially-complex
selector expression. In the following example, the Button is the
subject of the selectors:
When determining styles for a new component instance, Flex examines
all the parent classes looking for type selectors. Flex applies
settings in all type selectors, not just the exact match. For example,
suppose that class MyButton extends Button. For
an instance of MyButton, Flex first checks for a MyButton type selector.
Flex applies styles in the MyButton type selector, and then checks
for a Button type selector. Flex applies styles in the Button selector,
and then checks for a UIComponent type
selector. Flex stops at UIComponent. Flex does not continue up the
parent chain past UIComponent because Flex does not support type
selectors for Sprite (the
parent of UIComponent) or any of Sprite’s parent classes, up to
the base Object class.
Note: The names of class selectors cannot include
hyphens in Flex. If you use a hyphenated class selector name, such
as my-class-selector, Flex ignores the style.
You can programmatically define new class and type selectors
using the StyleManager class.
You can access the top-level StyleManager by using the styleManager property
of the Application object. For more information, see Using the StyleManager class.
About selector names
When applying style properties with CSS in a <fx:Style> block
or in an external style sheet, the best practice is to use camel-case
without hyphens for the style property, as in fontWeight and fontFamily (rather
than font-weight and font-family).
This matches the convention of using camel-case property names in
MXML.
To make development easier, however, Flex supports both the camel-case
and hyphenated syntax in style sheets, as the following example
shows:
The executing SWF file for the previous example is shown below:
In ActionScript or an MXML tag, you cannot use hyphenated style
property names, so you must use the camel-case version of the style
property. For the style name in a style sheet, you cannot use a
hyphenated name, as the following example shows:
.myClass { ... } /* Valid style name */
.my-class { ... } /* Not a valid style name */
About namespaces in CSS
Some Spark and MX components share the same local name.
For example, there is a Spark Button component (in the spark.components.*
package) and an MX Button component (in the mx.controls.* package).
To distinguish between different components that share the same
name, you specify namespaces in your CSS that apply to types.
For example, you can specify that a particular selector apply
to all components in the Spark namespace only. To specify a namespace
in CSS, you declare the namespace with the @namespace directive,
followed by the namespace’s library in quotation marks. The following
example defines the Spark namespace and uses the “s” as an identifier:
@namespace s "library://ns.adobe.com/flex/spark";
The following are valid namespace directives in Flex 4 that refer
to the manifests in the related SWC files:
library://ns.adobe.com/flex/spark
library://ns.adobe.com/flex/mx
If you do not use type selectors in your style sheets, then you
are not required to use the @namespace rule.
After you specify a namespace’s identifier, you can use it in
CSS selectors. The following example uses the Spark namespace for
the Button components and the MX namespace for the Box containers:
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/NamespaceIdentifierExample.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:myComps="*"
>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
s|Button {
fontSize:16;
}
mx|VBox {
color:red;
}
</fx:Style>
<mx:VBox>
<!-- This Spark button is red, and has a fontSize of 16. -->
<s:Button label="Click Me, Too"/>
</mx:VBox>
</s:Application>
The executing SWF file for the previous example is shown below:
You can also specify that a particular selector apply to mixed
nested namespaces. This is common if you are using descendant selectors.
You can exclude an identifier, in which case the declared namespace
becomes the default namespace. The following example uses the default
namespace:
For custom components, you can define your own style namespace;
that style namespace must match the component’s namespace. For example,
components in the myComponents package use the style namespace “myComponents.*”,
as the following example shows:
The executing SWF file for the previous example is shown below:
For custom components that are in the top level package, you
can use an “*” for the namespace. However, you cannot use wildcard
namespace prefixes, such as “*|” to match any namespace.
You can create your own namespace. This can be useful if you
want to defines type selectors for custom components. The following
example creates a new namespace for the classes in the mx.charts.chartClasses.*
package. It then applies the new styles to just the DataTip class
in that package:
<?xml version="1.0"?>
<!-- charts/DataTipStyles.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="srv.send()"
height="600">
<fx:Declarations>
<!-- View source of the following page to see the structure of the data that Flex uses in this example. -->
<mx:HTTPService id="srv" url="http://aspexamples.adobe.com/chart_examples/expenses-xml.aspx"/>
<!-- To see data in an HTML table, go to http://aspexamples.adobe.com/chart_examples/expenses.aspx -->
</fx:Declarations>
<fx:Style>
@namespace chartClasses "mx.charts.chartClasses.*";
chartClasses|DataTip {
fontFamily: "Arial";
fontSize: 12;
fontWeight:bold;
fontStyle:italic;
}
</fx:Style>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel title="Bar Chart">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:BarChart id="myChart"
dataProvider="{srv.lastResult.data.result}"
showDataTips="true">
<mx:verticalAxis>
<mx:CategoryAxis categoryField="month"/>
</mx:verticalAxis>
<mx:series>
<mx:BarSeries
yField="month"
xField="profit"
displayName="Profit"/>
<mx:BarSeries
yField="month"
xField="expenses"
displayName="Expenses"/>
</mx:series>
</mx:BarChart>
<mx:Legend dataProvider="{myChart}"/>
</s:Panel>
</s:Application>
The executing SWF file for the previous example is shown below:
About inheritance in CSS
If you
set an inheritable style property on a parent container, its children
inherit that style property. For example, if you define fontFamily as Times for
a Panel container,
all children of that container will also use Times for fontFamily,
unless they override that property. If you set a noninheritable style
on a parent container, only the parent container uses that style;
the children do not use that style. For more information on inheritable
style properties, see About style inheritance.
In general, color and text styles are inheritable, regardless
of which theme they are in (Spark or Halo) or how they are set (by
using style sheets or the setStyle() method).
The following are exceptions to the rules of inheritance:
If you use the global selector in a
CSS style definition, Flex applies those style properties to all
controls, regardless of whether the properties are inheritable. For
more information, see Using the global selector.
The values set in type selectors apply to the target class
as well as its subclasses, even if the style properties are not
inheritable. For example, if you define a Group type selector, Flex
applies all styles in that selector to Group and VGroup controls
because VGroup is a subclass of Group.
In general, you should avoid using type selectors for commonly-used
base classes like Group. Group is a class that Spark skins are based
on. Setting styles on the Group type selector might cause unexpected
results because the skins will have styles applied that you might
not oridinarily expect to apply.
The following example illustrates this issue. All labels and
button labels are yellow, even though only one label and one button
is explicitly in a group. The reason is that the LabelSkin and ButtonSkin
classes that define the skins for the Label and Button components,
are based on the SparkSkin class. The SparkSkin class is a subclass
of Group.
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/TypeSelectorInheritance.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
s|Group {
color:#FFCC33;
}
</fx:Style>
<s:VGroup>
<s:Button label="This Button is in a VGroup and its label is yellow."/>
<s:Label text="This Label is in a VGroup and its text is yellow."/>
</s:VGroup>
<s:Button label="This Button is not in a Group, but it is still yellow."/>
<s:Label text="This Label is not in a Group, but it is still yellow."/>
</s:Application>
The executing SWF file for the previous example is shown below:
CSS differences
There are some major differences in Flex between support
of CSS and the CSS specification:
Flex supports subclassing selectors. For example, if
you specify a Box type selector, Flex applies the styles to all
subclasses of Box, including VBox and HBox. This applies to all
classes in the Flex framework’s class hierarchy below UIComponent.
In this case, UIComponent is considered a “stop class.”
Flex supports a subset of the style properties that are available
in CSS. Flex controls also have unique style properties that are
not defined by the CSS specification.
Flex controls only support styles that are defined by the
current theme. If a theme does not use a particular style, applying
that style to a control or group of controls has no effect. For
more information, see About themes.
Flex style sheets can define skins for controls using the
Embed keyword. For more information, see Skinning MX components.
The CSS 3 wildcard namespace prefix syntax of *| that matches
any namespace (including no namespace) is not supported. For more
information, see Using Cascading Style Sheets.
The universal selector scoped to a particular CSS namespace
is not supported. Namespaces are not known at runtime in Flex and
as such the universal selector remains universal no matter what
namespace it is scoped to in CSS.
If you apply multiple class selectors to a component, the
order of preference that the styles is applied is the order in which
they appear in the styleName property’s space-delimited
list, not the order in which they are defined in the CSS block or
external style sheet.
The implementation of the CSS Media Query feature in Flex
supports only the “screen” type. No other media types are supported.
About class selectors
Class
selectors define a set of styles (or a class) that you can apply
to any component. You define the style class, and then point to
the style class using the styleName property of
the component’s MXML tag. All components that are a subclass of
the UIComponent class support the styleName property.
The following example defines a new style myFontStyle and
applies that style to a Button component by assigning the Button
to the myFontStyle style class:
<?xml version="1.0"?>
<!-- styles/ClassSelector.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Style>
.myFontStyle {
fontSize: 15;
color: #9933FF;
}
</fx:Style>
<s:VGroup>
<!-- This button has the custom style applied to it. -->
<s:Button id="myButton" styleName="myFontStyle" label="Click Me"/>
<!-- This button uses default styles. -->
<s:Button id="myButton2" label="Click Me"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
You can apply multiple class selectors by separating them with
a space in the styleName property. The order of
preference that the styles is applied is the order in which they
appear in the space-delimited list, not the order in which they
are defined in the CSS block or external style sheet. The following
example applies both class selectors to the first button:
<?xml version="1.0"?>
<!-- styles/MultipleStyleNames.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Style>
.myFontStyle {
fontSize: 22;
}
.myOtherFontStyle {
color: #9933FF;
}
</fx:Style>
<s:VGroup>
<!-- This button has the custom style applied to it. -->
<s:Button id="myButton"
styleName="myFontStyle myOtherFontStyle"
label="Click Me"/>
<!-- This button uses default styles. -->
<s:Button id="myButton2" label="Click Me"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
Class selector names must start with a period when you access
them with the getStyleDeclaration() method, as
the following example shows:
The executing SWF file for the previous example is shown below:
You do not precede the class selector with a period when you
use the styleName property for inline styles.
About type selectors
Type
selectors assign styles to all components of a particular type.
When you define a type selector, you are not required to explicitly
apply that style. Instead, Flex applies the style to all classes
of that type. Flex also applies the style properties defined by
a type selector to all subclasses of that type.
When you use type selectors, you are required to specify which
namespace each type appears in with the @namespace directive.
The following example shows a type selector for Button controls:
The executing SWF file for the previous example is shown below:
In this example, Flex applies the color style
to all Spark Button controls in the current document, and all Button
controls in all the child documents. In addition, Flex applies the color style
to all subclasses of the Spark Button class.
You can set the same style declaration for multiple component
types by using a comma-separated list of components. The following
example defines style information for all Spark Button, TextInput,
and Label components:
The executing SWF file for the previous example is shown below:
You can
use multiple type selectors of the same name at different levels
to set different style properties. In an external CSS file, you
can set all Spark Button components to use the Blue color for the
fonts, as the following example shows:
The executing SWF file for the previous example is shown below:
The local style declaration does not interfere with external
style declarations. Flex applies only the style properties that
you specified. The result of this example is that Spark Label controls
that are children of the current document use Blue for the color
and 10 for the font size.
All styles are shared across all documents in an application
and across all applications that are loaded inside the same application.
For example, if you load two SWF files inside separate tabs in an
MX TabNavigator container, both SWF files share the external style
definitions.
When you assign styles to a type selector, all subclasses of
that selector’s type (the class) are affected by the styles. For
example, if you create a type selector for Group, the styles are
also applied to VGroup and HGroup instances because those classes
are subclasses of Group.
Using compound selectors
You
can mix class and type selectors to create compound style declarations.
For example, you can define the color in a class selector and the
font size in a type selector, and then apply both to a component:
The executing SWF file for the previous example is shown below:
If you later remove one of the selectors (for example, call the StyleManager class’ clearStyleDeclaration() method
on the type or class selector), the other selector’s style settings
remain.
Using id selectors
Flex supports using an id selector. Flex applies styles
to a component whose id matches the id selector in the CSS. To define
an id selector, specify the id of the component with a pound sign
(#) followed by the id string. The id selector can be qualified
by the type or by itself.
The following example shows two ways to use an id selector:
The executing SWF file for the previous example is shown below:
Using descendant selectors
Descendant selectors are applied to components in a document,
depending on their relationship to other components in the document.
A descendant selector lets you apply styles to a component based
on whether they descend (are children, grandchildren, or great grandchildren)
from particular types of components.
When a component matches multiple descendant selectors, it adopts
the style of the most closely-related ancestor. If there are nested
descendant selectors, the component uses the styles defined by the
selector that most closely matches its line of ancestors. For example,
a Spark Button control within a VGroup within another VGroup matches
a descendant selector for “s|VGroup s|VGroup s|Button” rather than
a descendant selector for “s|VGroup s|Button”.
The following example shows four selectors. The first class selector
applies to all Button instances. The first descendant selector applies
to the second button, because that Button’s parent is a VGroup.
The second descendant selector applies to the third Button, because
that Button is a child of an HGroup and a VGroup. The last descendant
select applies to the last Button, because that Button is a child
of a VGroup within a VGroup.
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/CSSDescendantSelectorExample.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
s|Button {
fontSize:16;
}
s|VGroup s|Button {
color:red;
}
s|VGroup s|HGroup s|Button {
color: blue;
}
s|VGroup s|VGroup s|Button {
color: green;
}
</fx:Style>
<!-- This button has a fontSize of 16. -->
<s:Button label="Click Me"/>
<s:VGroup>
<!-- This button is red, and has a fontSize of 16. -->
<s:Button label="Click Me, Too"/>
</s:VGroup>
<s:VGroup>
<s:HGroup>
<!-- This button is blue, and has a fontSize of 16. -->
<s:Button label="Click Me, Also"/>
</s:HGroup>
</s:VGroup>
<s:VGroup>
<s:VGroup>
<!-- This button is green, and has a fontSize of 16. -->
<s:Button label="Click Me, Click Me!"/>
</s:VGroup>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
Styles are applied only to components that appear in the display
list. Descendant selectors are only applied if the ancestors also
appear in the display list.
Descendant selectors work with all classes that implement the
IStyleClient interface.
A descendant selector applies to a component as long as any parent
class of that component matches the descendant selector. The following
example shows that two Spark Button controls inherit the styles
of the Group descendant selector, because their parents (VGroup
and HGroup) are both subclasses of Group.
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/CSSDescendantSelectorExample2.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:myComps="*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
s|Group s|Button {
color:red;
}
</fx:Style>
<s:VGroup>
<!-- This button is red, because VGroup is a subclass of Group. -->
<s:Button label="Click Me"/>
</s:VGroup>
<s:HGroup>
<!-- This button is also red, because HGroup is also a subclass of Group. -->
<s:Button label="Click Me, Too"/>
</s:HGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
In general, you should avoid using the Group type selector in
CSS. This is because all Spark skins use the SparkSkin class, which
is a subclass of Group. As a result, Spark skins will inherit style
properties from the Group type selectors, which might produce unexpected
results.
Nested descendant selectors that set inheritable style properties
also work for subcomponents. For example, a Label is a subcomponent
of a Button control. It is responsible for rendering the text for
the button’s label text.
The following example shows that the nested descendant selectors
Button Label apply to a Button for inheritable style properties:
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/SubComponentDescendantSelector.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
s|Button s|Label {
backgroundColor:#FFCC33;
}
</fx:Style>
<!-- This button has a fontSize of 16. -->
<s:Button label="Click Me"/>
</s:Application>
The executing SWF file for the previous example is shown below:
Using pseudo selectors
Pseudo selectors let you apply styles to a component when
that component is in a particular state. The following example uses
a pseudo selector to change the appearance of the button when it
is in the up, down, and over states:
Class selectors
take precedence over type selectors. In the following example, the text
for the first Button control (with the class selector) is red, and
the text of the second Button control (with the implicit type selector)
is yellow:
The executing SWF file for the previous example is shown below:
The font size of both buttons is 10. When a class selector overrides
a type selector, it does not override all values, just those that
are explicitly defined.
Type selectors apply to a particular class, as well as its subclasses
and child components. In the following example, the color property
for a VGroup control is blue. This means that the color property
for the Button and Label controls, which are direct children of
the VGroup control, is blue.
The executing SWF file for the previous example is shown below:
If the same style property is applied in multiple type selectors
that apply to a class, the closest type to that class takes precedence.
For example, the MX VBox class is a subclass of Box, which is a
subclass of Container. If there were Box and Container type selectors
rather than a VBox type selector, then the value of the VBox control’s color property
would come from the Box type selector rather than the Container
type selector, as the following example shows:
The executing SWF file for the previous example is shown below:
Not all style properties are inheritable. For more information,
see About style inheritance.
Embedding resources in style sheets
You can use embedded resources in your <fx:Style> blocks.
This is useful for style properties such as backgroundImage, which
you can apply to an embedded resource such as an image file. The
following example embeds an image in CSS:
The executing SWF file for the previous example is shown below:
For more information about using the Embed keyword,
see Embedding assets.
For Spark controls, you edit the skin class to add images and
behaviors for certain states. For more information about skinning
Spark components, see Spark Skinning.
You can use document properties in your CSS with the PropertyReference keyword.
The property must be public, or it must be defined in the same document
as the CSS. For example, you can use a private variable in an imported CSS
file, as long as you imported that CSS file in the same document
in which the variable is declared.
If you change the value of the document property, the component’s
style property is not updated, even if the document property is
bindable. Changing the value of the document property will not update
the control’s appearance because styles are not reapplied unless
you explicitly call the setStyle() method or trigger
a reapplication of the styles in some other way.
The following example defines the mySize variable and uses it
in the CSS:
<?xml version="1.0"?>
<!-- styles/PropertyReferenceExample.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- You can declare a property using this method, too: -->
<!--
<fx:Declarations>
<fx:Number id="mySize">20</fx:Number>
</fx:Declarations>
-->
<fx:Script>
[Bindable]
private var mySize:Number = 20;
</fx:Script>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
s|Button {
fontSize: PropertyReference("mySize");
}
</fx:Style>
<!--Notice that when you click the button, the value of mySize increases,
but the size of the font on the button's label does not. Style properties
must be explicitly set, even if the property is bindable. -->
<s:Button id="myButton" label="{mySize.toString()}" click="mySize+=2"/>
</s:Application>
The executing SWF file for the previous example is shown below:
Using media queries
Flex includes partial support for CSS media queries. In
Flex, media queries let you conditionally apply styles based on
the DPI and OS of the target device. You typically use this feature
if you are developing for mobile or tablet devices that have different
target DPIs. For example, if a tablet has a DPI of 300, then you
can set the font size to one value. If a tablet has a DPI of 200,
then you can set the font size to a different value.
Media queries use the values of the application-dpi and os-platform CSS
properties to determine which styles to apply.
The only supported value for the media_type property
is screen. As a result, you do not need to specify
the media type.
If you do not specify a value for the application-dpi or os-platform properties,
then all are assumed. You can specify one or more resolutions or platforms
by comma-separating their values.
The following example changes the font size and color based on
the value of the applicationDPI property: