CSSLoader
by Ruben
Today I made the last completion to my CSSLoader class, the class enables you to load CSS files into your flex application during runtime, a functionality Actionscript3.0 lacks. It's actually as easy as this:
var loader:CSSLoader = new CSSLoader(); loader.load("mycssfile.css", "nameToBeGiven", displayObj1, displayObj2);
..where the amount of DisplayObjects (to which the style will be applied automatically after loading has finished) is infinite. The style will also automatically be applied to the given DisplayObjects' their children (if any).
Obviously, the class comes with many more features (methods and events), which are all to be found in the docs.
Go check out the demo, and browse through the source and documentation.
Please leave a comment and tell me what you think..
Oh, and big thanks go out to Maikel for helping my out time after time again..
Comments (also 26 trackbacks, click to show)
Trackbacks:
No thanx!! Keep up the good work!
Does this class load non-css attributes that flex understands, such as selectedUpSkin, etc…?
quote from Eric:
Long answer: Yes it does, basically my class reads key/value pairs from the css-file and applies them through setStyle, so if setStyle() accepts selectedUpSkin (which I’m pretty sure it does) then you can put it in your css-file..
Short answer: Yes.
Nice class. I did have problems when setting URLs for properties like backgroundImage. I changed
protected function parseProperty (property:String):XML {
var pair:Array = property.split(’:');
….
to this:
protected function parseProperty (property:String):XML {
var idx:int = property.indexOf(’:');
var pair:Array = new Array();
pair.push(property.slice(0, idx));
pair.push(property.slice(idx + 1));
Thanks again for putting the class out there.
Thanks alot Scott, it’s currently 6.45 in the morning over here, so I’ll have a look at it when I actually wake up
Scott, among some other tweaks I made the modification you suggested, the new version of CSSLoader is now available for download.
Ruben, Thanks for this. Exactly what I’ve been looking for. Do you have a license for this? Or do you consider this public domain?
Thanks Dan. I’m fine with whatever you’re using it for, as long as you’re not modifying the code without my approval (that includes keeping the headers in tact)..
Hey,
This is awesome. Something I have been thinking to do so. Here is some link love back to you: http://www.myot.ca/blog/2007/06/20/nice-writeups-flex-modules-compile-and-runtime-css-loading-pure-css-at-runtime/
quote from Ruben:
Hahaha, yeah man, viva la revolucion! Thanks for kudos Myo
….wow
Haha, well ehh, thanks..
Hi,
Nice code ,But this is not working for Application tag of flex. [for ex . How to set the backgroung color ..?]
Very nice work Ruben. I added a few lines to my copy of your work to address the mx:Application issue.
// after the 2 lines here in CSSLoader.as
protected function applyStyleToOne (css:String, displayObj:*):void {
var n:String = displayObj.className;
// i added this line (you need to import mx.core.Application obviously
if (n == Application.application.className) n = “Application”;
thanks again
Thanks Matthew! Awesome!
Ruben this class was a lifesaver – after trying for a second to get make something similar I remembered reading that you had something up like this – with the application fix someone mentioned in your comments it worked like a charm.
Cheers
Eric
Thanks Eric! See you around..
thanks for your share!
can post a direct .zip source address? the source tree you provided seems too large, and can not download in a long time.
Hey lwz7512, what’s wrong with clicking the “download source”-link on the source-page? It’s only a few kilobytes.
Hi,
Thanks for your nice work.
A question that I have on the class. How does it deal with skins in the CSS file?
Shon
Hi! Does this work with states? For some reason it will not set styles to new items based in a state. Something I’m missing?
@Shon: Thanks. Any values stated in css-files will be applied as string-values, so I’m pretty sure skins won’t work, sorry..
@Brad: Yes, I’ve heard more people mention this one. I haven’t made an attempt yet to figure out why this doesn’t work.
In the meanwhile you might want to try to use the enterState-Event of the State-class to trigger the CSSLoader class to apply styles to a State its children when it gets selected..
Excellent job!
I’m making a few tweaks to it so that it will automatically change actual CSS terms (ex: font-weight, background-color, etc) into their AS3 counterparts. Then I can tie into CSSEdit to see my tweaks live.
Works great so far with HTML apps, not so much with AIR unless I save the CSS file each time.
I’m making a blog post about it, if you’re interested.
This is great!
Any chance of an open source license?
Thanks
Ian
@Jon: cool! I’m very much interested, let me know when you do make a blogpost
@Ian: if you’re talking about the source itself, you can download it here:
rubenswieringa.com/[...]/CSSLoader/source
This is awesome. Same question about appending an os license to it. I would like to use it in a project but without a license, i just cant.
Nice work
oh greate
but cssloader is not applied for customComponents in flex
Hi and good work. I am curious if you have ever had a problem with using your resource to style the title in a panel. I am struggling to apply any sort of styling to a Panel Title at all, bearing in mind all my attempts at traditional methods DO work?
If you have it working and example would be nice
Cheers,
Simon
Hi , iam using the cssloader.as and cssparser.as classes in my applivation to load style sheets dynamically, in my style sheets iam using programatic skinning for some components i.e., iam refering to that classes in as style sheets iam unable to load that skinning through programming using your classes iam trying to enhance the feature please shower some light on it
Thanks
AnnaDorai
hey guys,
great work, but i can’t make it work
i have something like this:
styleLoader.load(’iftf.css’, ‘default’, this);
styleLoader.applyLastLoadedStyle(menu, true);
it’s in the creationComplete
menu is a UIComponent which contains some of the element which i want to style
like
and in the css
.buttonBar
{
horizontalAlign: left;
verticalAlign: top;
backgroundColor: #ffffff;
backgroundAlpha: 0.5;
}
what’s wrong?
thanks in advance, Viktor
Hi,
Where can I download the .as files. The source link opening just the mxml.
Thanks
I am trying to find the cssloader.as and cssparser.as and i can’t seem to find it.. Need help
sounds amazing css at runtime without compilation , hmm let me check .
I found this article somewhat similar .It describes how to change dynamic stylesheet on runtime . It does not use swf or css at all http://askmeflash.com/article_m.php?p=article&id=6
Hi Ruben!
First, i must say that your class work pretty good in Flex-builder3. But now, maybe we have problem in Flash-builder4. When i create a css, Flash-buider generate and suggestes style-name, but we must code styleName in css to use for your CSSLoader
Maybe you edit CSSParse to compatible with flashbuider
Hi Ruben. Nice Work.
But it is possible to set the property skin.
I trying to load a Symbol of a .swf library over css at runtime.
Like this:
.applyBtn {
skin: Embed(source=”../output/swf/gui/library.swf”, symbol=”IconDelicious”);
}
I tried it with your solution, but i got the whole time the information that my type []@179.. couldnt converted into class.
Do you have any idea, maybe on a other way to solve my problem. I tried a couple of other ways, but nothing with success. I dont wanna use the ugly way to convert the css to a swf to load the embed symbol.
Hey Chii,
The problem is that the
Embed()tag is kind of like an instruction for the mxml-compiler (mxmlc), it’ll make sure that whatever you’re trying to embed will be compiler into either your main swf, or the stylesheet-swf (if you’re using those).The CSSLoader and CSSParser classes use the actual raw css text-files and as such you cannot actually embed your assets in those (since the stylesheets are just text-files). The solution would be to actually host your assets alongside your css- and swf-files, and refer to them by url.
Cool… Has anyone figured out how to get a “global” declaration to work yet? I use something like this in most of my flex style sheets
global
{
color: #4d4d4d;
fontFamily: Arial;
fontSize: 12px;
}
Ok, so I’ve spent some time with this and found that the parser works well enough, but I don’t like the way the loader applies the styles. Why deal with display objects and looking for children when you can just set css style declarations??
Here are modifications I made to use css declarations and ignore the display object stuff…
protected function processResult (url:String, css:String):void {
var index:int = this.styleSheets.styleSheet.(@url==url)[0].childIndex();
var name:String = this.styleSheets.styleSheet[index].@name;
var url:String = this.styleSheets.styleSheet[index].@url;
var parsedCSS:XML = this.parser.parse(css);
if (parsedCSS == null){
return;
}
this.styleSheets.replace(index, parsedCSS);
this.styleSheets.styleSheet[index].@name = name;
this.styleSheets.styleSheet[index].@url = url;
this._lastLoadedName = name;
applyStyles(name);
/*
for (var i:String in this.applyTo[name]){
this.applyStyle(name, this.applyTo[name][i], true);
}
this.applyTo[name] = [];
*/
}
protected function applyStyles( name:String ):void
{
var styles:XMLList = this.styleSheets.styleSheet.(@name==name).style;
for each ( var style:XML in styles)
{
var selectors:XMLList = style.selectors.selector;
var properties:XMLList = style.properties.property
for each ( var selector:XML in selectors )
{
var dec:CSSStyleDeclaration = StyleManager.getStyleDeclaration(selector.@name);
if (!dec)
{
dec = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration(selector.@name, dec, false);
//selectors.push(selector.@name);
}
for each ( var prop:XML in properties )
{
trace( selector.@name + ” : ” + prop.@name )
var val:String = prop.@value;
var styleVal:*;
if (val.indexOf(”,”))
styleVal = val.split(”,”);
else
styleVal = val;
dec.setStyle(prop.@name, styleVal);
}
}
}
}
also, in CSSParser I changed the parseSelector method to just do this…
var n:String = element;
if (n == ‘*’) n = ”;
var node:XML = ;
return node;
Maybe this won’t work for everything, but these changes worked much better for me.
One thing I will probably add is to check if the property is valid before setting it, and if not throw an error.
And sorry if I sounded negative before, the code was very helpful
I had better luck with those modifications, but I don’t know if it will support all types of selectors and values.
Hey Steve, thank you very much for the suggestion, I’ll give it some thought
Ruben:
In your comment on 9/10/09 you mentioned a solution to the problem of using Embeds with your CSSLoader class. In your comment you said the following:
“The CSSLoader and CSSParser classes use the actual raw css text-files and as such you cannot actually embed your assets in those (since the stylesheets are just text-files). The solution would be to actually host your assets alongside your css- and swf-files, and refer to them by url.”
I have attempted to do this with a Panel’s titleBackgroundSkin property, which actually requires an Embed in order to work.
In my style sheet, I refer to a hosted PNG:
titleBackgroundSkin: http://my_server-path/graphics/header.png
where header.png is the graphic I am supposed to fidplsy as the panel’s titlebar background.
I still get the same class coercion failure.
Obviously I do not understand your solution. Could you elucidate on it, preferably with a code example? Thanks.
Hello,
I have a problem. I get the .css file from an url and works fine, but if I get an .css file from the server, this .css don’t work. This is, because the file that works have inline css definition and the other file, has the css standard definition. For example:
Thats works.
.red{
backgroundColor: #000444;
}
And this, don’t work:
.red{
background-color: #000444;
}
Anyone know because this style don’t work???
Thanks and great job!!!
Why not do this: Select your stylesheet CSS – right click it – and select “Compile CSS to SWF”. Then simply load that swf using the StyleManager like below:
StyleManager.loadStyleDeclarations(”stylesheet.swf”);
Works like a charm
@ Prakaz: So you can’t load *.css files at runtime and you must compile your project when you want change your css.
@Ruben
I want do something like that.
in css:
.myBtn
{
upSkin: Embed(source=’firstPage_up.png’);
overSkin: Embed(source=’firstPage_over.png’);
downSkin: Embed(source=’firstPage_down.png’);
disabledSkin: Embed(source=’firstPage_up.png’);
}
Result:
Compiling error
Error #1034: cast error: “Embed(source=’firstPage_up.png’)” can´t cast in Class.
Please help, i dont know what i am doing wrong?
Hey, This is a great class. Thank you for sharing. If I may, I have a question for you. when the CSSLoader.Result event is fired and it hits the onCSSFileLoaded function. I am getting the following error:
Error #1069: Property data not found on com.xennsoft.mediabox.utility.CSSLoader.
I see the css data in the onCCCLoaded function in CSSLoader. But the data is not being passed on to the event listener.