One of the most powerful features of Flex is the vast amount of design flexibility it contains. This flexibility is largely the result of Adobe's implementation of CSS with Flex. For instance, while recently serving as senior UI developer for a new Adobe AIR™ application, I received a number of design change requests days before officially launching the first public release to 160,000 people worldwide. Although many developers might have considered these last-minute requests an atrocity, I had the changes completed and checked into version control in less than 20 minutes, thanks to the power of Flex and CSS.
I look at the use of CSS with Flex as a form of leverage in UI development. There are certain inevitabilities I've learned to expect and prepare for through my experience in UI development. One such inevitability is that regardless of how much planning you do beforehand, both the design and the functional requirements of the project will change and will change often throughout the development life cycle. It's a rule of the game when developing large-scale applications in a team-based environment, and the best way to play a winning game is to anticipate the moves of all the players involved, and then position yourself accordingly in advance. When you learn how to master this development technique, you're always in the lead, and hitting a moving target becomes a lot easier. For this reason, I enjoy developing with Flex, because Flex features like CSS integration give you the power to do exactly that.
My goal is that by the time you finish reading this article, you too will be able to leverage the powerful capabilities of CSS with Flex and play a winning game as a master Flex UI developer. If you're already an avid user of Flex, then my hope is that you will learn new techniques for utilizing CSS with Flex—particularly with enterprise-level applications.
Most object-oriented design patterns keep the design logic separate from behavioral functionality. Because Adobe ActionScript™ is an object-oriented language, it only makes sense to remain consistent with these object-oriented programming (OOP) conventions. The benefits of doing so include flexibility, keeping maintenance of the application easy as it grows, code reuse, and better performance.
In the world of Web design, CSS is a standard for encapsulating the code that makes up the design of a Web site. Given the power and maturity of CSS, most experienced Web designers strive to implement as much of the design and layout properties of a Web site in CSS as possible. The result is much greater control and flexibility over the look and feel of the site. CSS gained most of its popularity three or four years ago when Web developers began to realize that when the design of a Web site is independent of the site's behavioral functionalities, the design can be easily modified without the risk of breaking or otherwise negatively affecting the site's behavioral code. This is what propelled the rapid growth of templates, skinning, and re-skinning the same code base. For example, I'm an avid user of WordPress for my blog Web site. There are tens of thousands of people who use this same open source code base to power their blog site, and yet many times, you will stumble upon a site built on WordPress and you wouldn't even know it thanks to its impressive separation of code from design through the use of CSS.
First and foremost, for those of you coming from a Web design background, it's
important to understand that Flex CSS does not follow the same conventions as
the W3C CSS spec. The hyphen (-) used to separate
words in the W3C CSS Version 2.0 specification isn't used as part of the code
convention in the Flex implementation. Instead, the Flex implementation of CSS
uses camel case. For example, vertical-center in
the W3C CSS2 spec is equivalent to verticalCenter
in Flex CSS. If you're already programming in a language that uses camel case,
however, this is pretty easy to get used to. The good news is that most of
what's available in the CSS 2.0 specification is also available with the Flex
CSS implementation. Furthermore, the Flex implementation of CSS expands
significantly on the CSS 2.0 W3C standard, offering additional style
properties that are unique to the Flex components.
Maintaining styles: Component versus style properties
Before you begin creating Flex CSS style sheets, I recommend that you first consider how you want your styles implemented. For the sake of simplicity, I show you four basic methods of declaring a style:
- Through a component's class name. You can set a style on a
component by using the component's class name as the style name:
TitleWindow { borderColor: #f7f7f7; borderAlpha: 1; borderThicknessLeft: 0; borderThicknessTop: 0; borderThicknessBottom: 0; borderThicknessRight: 0; cornerRadius: 0; headerHeight: 0; highlightAlphas: 1, 1; headerColors: #f7f7f7, #f7f7f7; footerColors: #f7f7f7, #f7f7f7; backgroundColor: #f7f7f7; dropShadowEnabled: true; } - Through a unique style name. You can declare styles using a unique
style name. Just be sure to put a dot in front of the name and use the
camel case convention:
.altText { fontFamily: TVNordEFCEOP-RegularCon; fontSize: 18; color: #FFFFFF; } - Through a component plus a style name. You can also set a style
name on a component when you need to have multiple designs for the same
component, which is common for applications that have multiple view states.
This method also ensures that only the specified component can have that
particular style assigned to it:
Text.bigYellowText { color:#EFB526; fontSize:36; fontWeight:Bold; } - Through the global selector. The global selector is a
special kind of selector that affects every component within the
application that contains the properties set inside it. For example, I
could set the
cornerRadiusstyle property of all of my display object components that contain acornerRadiusstyle property to a setting of4, like so:global { cornerRadius: 4; }
Although the global selector basically sets a default value of a property,
that value is easily overridden. For instance, if I set the cornerRadius property of the Button component to 0 either inline or
in my CSS file, it will take precedence over the global default setting of
4 that I have also specified; thus, all my Button components will contain a cornerRadius value of 0. Furthermore, I
can override both the global setting of 4
and the Button setting of 0 by creating an additional style:
Button.altCornersButton
{
cornerRadius: 8;
}
|
The method of CSS implementation with Flex you choose must be based on the situation and the environment. It's important to look at the application you're designing from the conceptual 50,000-foot view when considering your options for design implementation. The following methods are the most common for using CSS with Flex.
Setting styles on an instance (inline)
Flex components that extend the Flex UIComponent
base class allow you to set common styles as properties
inline—in other words, within the MXML component declaration
tag (see Listing 1). The layout properties of a display
object are often unique to that object, so it's common to see any one of the
following properties set explicitly on a component: x, y, height,
width, top, right, left, bottom, horizontalCenter,
verticalCenter, horizontalAlign, and verticalAlign.
Listing 1. Setting styles as properties of a component instance with MXML
<mx:Button id="volumeIcon" cornerRadius="0" alpha="0.9" verticalCenter="0" enabled="true" toolTip="Volume Control" click="toggleVolumeControl();" /> |
Listing 1 exhibits a functional example of setting style properties that are
unique to the specific instance of the Button
component with an id value of volumeIcon. Because I know that this is the only button that will
require these particular style values, I have explicitly set the cornerRadius, alpha, and
verticalCenter of this particular button.
As a good rule of thumb when setting style properties on an MXML component
tag, only set the property this way when you know that the particular property
value you're setting is specific to that component. For instance, say your
application requires a container that vertically stacks display objects but
without any gap in between. At the same time, you know that other VBox
containers in the application do need to have some spacing between the display
objects. In this type of situation, you should explicitly set the verticalGap property on that instance of the VBox
component, as shown in Listing 2.
Listing 2. The verticalGap is explicitly set to 0 on this instance of the VBox container component
<mx:VBox id="myVBox" verticalGap="0" x="15" y="15" width="100%" height="100%"> (...) </mx:VBox> |
This method involves embedding styles or assets directly into an MXML file
with the <mx:Style/> tag. For all practical
purposes, there are few instances in which directly embedding style
information into an MXML file makes sense. It's important to recognize that as
the application grows, the design will become increasingly difficult to
maintain if the application contains a lot of embedded CSS. With that in mind,
be conservative with this method, and only use it when necessary. Listing 3 provides an example of an embedded style
declaration that really should be held within an external CSS file for greater
code maintainability.
Listing 3. Embedding styles directly within the MXML application file
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
showFlexChrome="false"
borderStyle="none"
keyUp="{this.onKeyStrokeEvent(event);}">
<mx:Style>
.bGroup {
borderSides:"left,bottom,right";
borderStyle:"solid";
borderColor:#6d6f71;
borderLeftThickness:3;
borderRightThickness:3;
borderBottomThickness:1;
dividerColor:#6d6f71;
dividerThickness:3;
}
</mx:Style>
<mx:Script>
<![CDATA[
(...)
|
However, that's not to say that it will never happen. Listing
4 is a scaled-down component I built for one of my applications that's
based on the Flex AplicationControlBar. In the
design provided, each button in the control bar was actually just a single
word of text and looked more like a link than a button. Additionally, all the
one-word links had a small bullet separator between them. Because I had the
design for the full application already, I knew this bullet separator was
unique to the application's main control bar and did not appear anywhere else.
Most importantly, because the bullet appeared several times within the same
component, it made perfect sense to embed the image as its own private class
within the MXML file so that I could bind to it from each image control I
placed between the links. Otherwise, I would have ended up with multiple
instances of the same image being created, which is nothing more than a waste
of system resources.
Listing 4. Embed an image directly
<?xml version="1.0" encoding="utf-8"?>
<mx:ApplicationControlBar xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Embed(source="assets/bullet_black.png")]
[Bindable]
private var bullet:Class;
]]>
</mx:Script>
<mx:HBox x="10" y="10" id="hbox" horizontalGap="10" width="350">
<mx:LinkButton label="Help" styleName="appBarButton"/>
<mx:Image source="{bullet}" />
<mx:LinkButton label="About" styleName="appBarButton"/>
<mx:Image source="{bullet}" />
<mx:LinkButton label="Minimize" styleName="appBarButton" />
<mx:Image source="{bullet}" />
<mx:LinkButton label="Quit" styleName="appBarButton"/>
</mx:HBox>
</mx:ApplicationControlBar>
|
A Flex or AIR application has a single MXML file at the root of the source
code directory that is based on either the Application class (Flex) or the WindowedApplication class (AIR). This is the default MXML
application file that starts with either the <mx:Application/> or <mx:WindowedApplication/>. The application's style sheet source
should immediately follow the declaration of the application's base class (see
Listing 5).
Listing 5. Declaring style sheets in any other file except your main application MXML file results in errors
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
showFlexChrome="false"
dropShadowEnabled="false"
borderStyle="none"
applicationComplete="{this.appInit(event);}"
>
<mx:Style source="com/passalong/assets/RED_SKIN_MAIN.css"/>
<mx:Script>
<
Dan Orlando is a software architect specializing in rich client-server applications that involve Flex, AIR, and ActionScript on the client. He works with a variety of Web service protocols and server-side languages. Dan is co-founder of Vision Media Group, the makers of Avijax, and also serves as a senior UI developer on the (RED)WIRE team. You can reach Dan at dan@vizmarketing.com.
Comments (Undergoing maintenance)





