Seems like every time I get a new project that involves styling dynamically generated text in Flash, using custom fonts and with no access to Flex’s @embed trickery, I run into problems. I’m writing this blog entry not just to share a solution with you but also to have a single writeup for my own reference moving forward.
So, here’s the assignment: you’re working with Flash (let’s say CS4) and you have some dynamic textfields that are going to hold text. This text needs to be styled, dynamically at runtime. Font size is going to vary between 10 and 20. You know that some text is going to be set in one font (let’s say Avenir Heavy Oblique) and some will be set in another (let’s say Myriad Semibold Condensed Italic). The client even wants you to manually tweak the letter spacing on certain words. Setting properties on the textfields themselves, then, won’t work. You need to be able to handle custom styling of substrings within the larger set of content. How do you do it?
Now, I believe there are multiple ways to address this problem – TextFormat might help you, but I’ve run into various issues getting that to work, and I haven’t done a whole lot of poking around with TLF. If you have alternate solutions to what I’m about to outline, please post them below in comments. I’m going to explain how to do this using CSS. First we’re going to learn the basics of CSS in AS3, then we’re going to learn how to integrate dynamically embedded fonts. Finally we’ll wrap up with a look at additional things to explore.
CSS in AS3
The way I’ve successfully pulled this off is using Flash’s implementation of Cascading Style Sheets, or CSS. CSS in Flash is implemented using the flash.text.StyleSheet class. It’s not quite as simple as it is in HTML – the concept is basically the same, but the format you have to use is very specific.
1) First, somewhere in your class create an instance of the StyleSheet class:
var ss:StyleSheet = new StyleSheet();
2) In CSS, you use selectors to grab certain elements out of the DOM and then apply a set of attributes to them. In HTML you just have a block of CSS – either at the top of your HTML page or in a separate linked file – that has a long list of selectors and attributes all printed out. In AS3 things are a little bit different – here, every set of attributes is treated as a name/value pair in an instance of the Object class, like this:
var bigAndCondensed:Object = {fontSize:20, letterSpacing:-1}; var smallAndBold:Object = {fontSize:10, letterSpacing:1, fontWeight:"bold"}; var bigAndRed:Object = {fontSize:20, color:"#ff0000"};
And so on.
3) These objects, then, get linked to your stylesheet and matched to a CSS selector using the setStyle method of the StyleSheet class, like so:
ss.setStyle(".bigRed", bigAndRed); ss.setStyle(".smallBold", smallAndBold); ss.setStyle(".bigSkinny", bigAndCondensed);
4) We’re almost ready – our CSS is set up, and we just have to attach it to our Textfield. A final bit of preparation and we’re set:
var tf:TextField = new TextField(); tf.autoSize = TextFieldAutoSize.LEFT; tf.styleSheet = ss; addChild(tf);
5) Now, all we have to do is attach some htmlText to that TextField using the selectors we’re listening for and we’re set. We can say something like this:
tf.htmlText = "The quick <span class='smallBold'>brown</span> fox jumped <span class='bigRed'>over</span> the lazy <span class='bigSkinny'>dog</span>.";
OK, that’s all well and good but my designers are using fancy-ass premium fonts! They’re not even web-safe!
Ok, don’t panic – we’re only halfway done. We still need to figure out how to display some parts of your text in Avenir Heavy Oblique and some in Myriad Semibold Condensed Italic. You’ve tried simply specifying those font names in your CSS object, but you and I both know that’ll never work – you need to embed the fonts themselves, and that can be tricky to do right. Fortunately, I’m here to guide you through it so that you don’t have to spend two weeks beating your head against a desk like I did.
1) First, go into your .fla file. (You are using an .fla, right? I don’t know how to do this in pure AS3, and if you’re using Flex you can just @embed the fonts so why waste time with me here?) Open your library, right click and select “New Font”. First, select the first input and give this font a name that you’ll be using to reference it. For instance, AvenirHeavyOblique. In our example here, we’ll be doing this twice – once for the Avenir font face and once for the Myriad.
In the second input field, select the font family you’d like to use. Finally, make sure you have the correct font face selected in the third input – in our case, “85 Heavy Oblique”. (Your mileage may vary – you may not have these fonts, that’s fine, just pick something that’s not websafe and follow along).
Finally, and this is the most important part, make sure you click the box that says “Export for ActionScript”. Hit OK, do it again for every font face you want to use, and then go on to the next step.
2) Go back to your AS3. The first thing you will want to do is instantiate your two exported fonts in code. That’s going to look something like this:
var avenirHeavyOblique:Font = new AvenirHeavyOblique(); var myriadSemiboldCondensedItalic:Font = new MyriadSemiboldCondensedItalic();
3) Now the tricky part, this is what took me forever to figure out. As you can see from the documentation I linked above (see flash.text.StyleSheet), the AS3 CSS syntax takes fontFamily as an acceptable attribute. This is expecting a string – but you can’t just type “Myriad Semibold Condensed Italic” and expect it to work. Instead, you have to pass it the fontName property of the font object you’ve just instantiated. I’ll go ahead and modify the attribute objects we created earlier:
var bigAndCondensed:Object = {fontFamily:avenirHeavyOblique.fontName, fontSize:20, letterSpacing:-1}; var smallAndBold:Object = {fontFamily:myriadSemiboldCondensedItalic.fontName ,fontSize:10, letterSpacing:1, fontWeight:"bold"}; var bigAndRed:Object = {fontSize:20, color:"#ff0000"};
4) Finally, one more tweak. Go back to your textfield and make sure that the .embedFonts property is set to true:
tf.embedFonts = true;
That confirms that the TextField will use the embedded fonts rather than system fonts. I’m actually a little bit confused on this point, because the fact that we’re using Embedded Fonts with CSS should circumscribe our need for this – but TextFields are designed to accept style inputs in a variety of ways (properties directly set this way, CSS, TextFormat, etc) and so I’ve found that there can be some minor unpredictable overlap. If someone can confirm to me that this works even without embedFonts set to true then I’ll remove it, but last time I did this I had some weird inconsistent behavior and setting that to true seemed to fix it.
Anyway, compile. Ta-da! You now have embedded fonts dynamically added to dynamically generated text in a plain old AS3 dynamic TextField.
Wrap-up
So, moving forward there’s one detail that I’ve barely touched on here and that is CSS Selectors in Flash. AS3′s implementation of CSS is limited to the StyleSheet class, which means that you can only use CSS to control the way your fonts look. You can’t select other objects in your swf and style them, which means that you have a much more limited set of CSS Selectors to work with. Generally speaking you’re fine using CSS Classes, like we did in our examples, and text containers (“p”, “span”, etc). I haven’t tried any sort of pseudo-selectors or anything much more fancy than classes, honestly, but eventually I’d like to come up with a comprehensive list of AS3 CSS Selectors. If anyone has something like that, please leave a note!
The other thing I’m a little bit vague on is the additional set of parameters in CS4′s dialog box for embedding fonts into the library (see step 1 of the Fonts section, above). I haven’t really messed around with conflicting font sizes between the embed and the CSS – I generally just play it safe and make sure they match. I’m not sure how the BitmapText checkbox factors into this stuff, and I generally avoid messing with the Faux Bold/Italic options since that is better handled through the specific font face I’m implementing.
Anyway, I hope that helped! Tune in next time!
{ 3 } Comments
thank you so much! that totally helped save my life … ;)
This article is great and helped me out a lot. Thanks!
Many thanks for this – Googling around, I found a pile of snippets about combining multiple fonts in an HTML text field, many of which rely on font-embedded-in-a-text-field voodoo, but this is the cleanest implementation that I’ve seen.
Post a Comment