I've recently become involved in building a very module based Flex app, where the question of css and css inheritance came up, particularly with respect to how Flex handles run time loading of style sheets when they are loaded within not only the shell application but also the therein loaded modules.
Essentially, there are 3 rules that prevail:
- The most recent style to be loaded always wins.
- Run time overrides compile time styles
- StyleManager is a global Manager
- Style inheritance is granular to the attribute level
- Compile time css will only compile styles found in Application
The most recent style loaded always wins
Say you load a runtime style sheet with the following:
fillColors: #ff0000, #ff0000, #ffffff, #eeeeee; /*red */
Then in a (rather large) module you load another runtime style sheet with this:
fillColors: #006600, #009900, #ffffff, #eeeeee; /*green*/
You'll notice that the first color style is applied right away, to any buttons in the shell application. However, when the second module finishes loading, all Buttons will change from Green to Red, and spacing will be reduced to 1. To make it even more interesting, you could add an additional module of roughly the same size as the first and have it load its own style sheet. Then the end result is pretty much random, whichever module takes the longest to load wins, the shell run time style never to be heard from again.
Run time overrides compile time styles
In your shell application you add the following:
fillColors: #9900ff, #9900ff, #ffffff, #eeeeee;
Once your app loads the run time css, this will be overwritten. Now if you have a huge run time css swf with massive fonts or images embedded in, there's a chance you might even see your original color first and then have it overwritten later. This can cause for some funky effects in your app, in which case you might want to attach an eventListener to StyleEvent.COMPLETE, and hide your interface until that event has triggered using a ViewState or the like.
StyleManager is a global Manager
It that does not distinguish between <Applications> and <Modules>. Say you create a custom style class called .myDogAteMyHomeworkButton for Buttons in your module. You then place a corresponding style entry in your compile time or run time styles for this module. Now someone else happens, just happens to use the same exact style class in their module. Or the shell application developers happens to do so. Well again, the last one loaded wins. Your custom style class is never safe. But then again neither are their's. The best thing you can do is be very very unique in your style class naming conventions, and hope for the best.
Style inheritance is granular to the attribute level
Getting back to our original example, you'll notice the style attribute letterSpacing was defined explicitly in both style sheets. Because inheritance is on the attribute level, if you do not specify an attribute in say your run time style sheet for your application, then that attribute can be set in compile time style tags and it will override the default values. What's the lesson to be learned here? If you want to make sure that your runtime css has the final word, then get detailed and explicitly list every style attribute and its value, even if the default will suffice.
Compile time css will only compile styles found in Application
Ever seen this warning "The type selector 'HDividedBox' was not processed, because the type was not used in the application."? Until the dawn of Modules, this was a message I generally ignored. Made sense to me, if I didn't have an HDividedBox anywhere in my application, why include the style? But what would happen to modules that perhaps do use the HDividedBox control but rely solely on the shell application styles for their look and feel? The application doesn't know at runtime that one or more of its modules will need this style defined, so therefore it just ignores it. End result, your HDividedBox in your module will not be styled properly. The solution? Use run time stylesheets. (and that's how this all began!)