Flash + Fonts: Dynamically Loaded Fonts + Embedding + CSS + HTML == Hell
I swear about every year I end up reexploring the dark internals to flash's murky font seas, lose a day to a weekend everytime.
Basically the embedded fonts + html is a fairly complicated beast, that in order to work has to be called in a very specific order to work.
Here's a new twist. As I've covered in previous articles the ability to load fonts dynamically is very cool, but what of those textfields on stage used as placeholders? How do they join in the font fun? THEY DON'T. It doesn't appear possible to have them styled as CSS+HTML+Embedded, even if you set it to new text with CSS the text inside just dissapears. However you can create a new TextField that does support those values at the exact same place, and swap them like:
-
-
//////////// Takes a clip on stage and replaces it with an 'identical' one ////////////////////////////////////////
-
public static function swapClip(txt : TextField) : TextField {
-
trace("swapClip2..............." + txt.name);
-
var par : DisplayObjectContainer = txt.parent;
-
-
var tf : TextField = new TextField();
-
var ss : StyleSheet = new StyleSheet();
-
var tff : TextFormat = txt.defaultTextFormat;
-
-
var p : Object = new Object();
-
p.fontSize = tff.size;
-
-
p.fontFamily = tff.font;
-
//"Myriad Pro";
-
p.color = tff.color;
-
p.size = tff.size;
-
ss.setStyle("p", p);
-
//
-
tff.font = tff.font;
-
//"Myriad Pro";
-
tf.defaultTextFormat = tff;
-
// new TextFormat("Myriad Pro", 16, 0);
-
tf.styleSheet = ss;
-
-
-
tf.width = txt.width;
-
tf.height = txt.height;
-
tf.x = txt.x;
-
tf.y = txt.y;
-
// tf.border = true;
-
-
tf.embedFonts = true;
-
tf.antiAliasType = AntiAliasType.ADVANCED;
-
tf.selectable = true;
-
tf.multiline = true;
-
tf.wordWrap = true;
-
tf.condenseWhite = false;
-
-
// tf.rotation = 15;
-
// txt.visible = false;
-
trace("swapClip htmlText " + txt.htmlText);
-
var html : String = "<p>" + txt.text + "</p>";
-
tf.htmlText = html;
-
tf.name = txt.name + "";
-
-
// par
-
par.addChildAt(tf, par.getChildIndex(txt));
-
par.removeChild(txt);
-
return tf;
-
}
-
Weirdly you have to give it both TextFormat and styleSheet to get the similar formatting as the clip on stage, clearly Flash's internal renderer has significant internal state and both TextFormat or StyleSheet overlapp controlling different aspects of it.
XHTML + E4X + Namespaces
Namespaces in flash are cool and...pretty pesky.
- for unknown reasons, querying a E4X's queries in the same block apparently have to be individually namespaced. Neither putting the default namespace in the class or function worked.
- anything that tries to get at the xml while it's being passed around has to have a copy of the namespace. This isn't particularly efficient when you are serializing between objects and XHTML.
Steven Sachs has a good tutorial on some of the issues faced when working with XHTML and Flash. In particular the namespace. However after losing about 2hrs I've come up with an alternate solution...just stripping the namespace out as it's introducing more code chaos than the namespace would have solved.
In the next rev of kidthing.com's website we are going to XHTML for SEO and CMS, deeplinking etc reasons. In addition we are consuming Wordpress, initially as RSS and eventually as fully skinning the main pages in Wordpress. Since Flash's support for HTML is limited we run things through a 'cleaner' that replaces quotes, superscript, some bullets with the appropriately embedded characters. It was easy to add the following to strip it out on the complete load of the XHTML
res = res.split('xmlns="http://www.w3.org/1999/xhtml"').join('');
I switched over from String manipulation to XML manipulation to get at selective DIV's that get mapped to textfields in the flash templates (Flash is like CSS on steroids) E4X here really shines.
Flash + SEO tricks with SWFObject, and SWFObject2
Progressive enhancement is a highly recommended technique for integrating flash into html pages in an SEO compatible manner. As recommended by google, adobe, and others. How it works is at the base is a plain html page that define the site structure using conventional links, which when javascript and flash are present autoupgrades/overwrites the boring html with your stunning flash file.
One thing that should be aware of is that unless there is some text in the html div that gets ovewritten, nothing will be indexed by the any search engine, as yet none are rendering javascript rendered html pages. ..meaning you'll be invisible on google ( perhaps that's what' you want if you're in stealthmode). Even if your index.swf was indexed, if your breakdown is one swf per section, the odds of those getting indexed are remote at best. To demonstrate.
In a recent project, we were in a rush to get everything up so just left it with an html + swfObject to embed the swf file and for everyone else a warning graphic saying "javascript + flash required" (meaning almost no text other than the meta tags). We assumed/required user's needing flash for the content, and we didn't have budget for a rich html site (client requires high end design). Amusingly, despite the unique name., after a few months, the main website the CEO and President's LinkedIn pages scored higher in rank than the main website, presumably getting more hits.
So in a recent push of a new landing page, we upgraded to the nice SWFObject 2.0 but were still in a crunch so couldn't get an html site up underneath yet. But what we did have time to do is create a DIV containing a mirror of the text so that the search bots had something to chew on, and used CSS/Javascript to hide the div so normal users couldn't see it. Within a week, that new page is at the top of google, surpassing the President's pages, with the hidden div text showing up in the link summary below it, so it demonstrate how important powerful having the html text beneath the flash is!
Here's how it works, you have a html div beneath the flash site that contains the info that you want. Including links to other html pages.
-
-
-
<div id="contentToReplaceDiv">
-
-
<div id="main">
-
<h1>Flash SEO tricks</h1>
-
<p>Improve your search engine ranking quickly</p>
-
<p>easy changes</p>
-
<p>best of both worlds, high experience flash for your users, richly targeted text for the search bots</p>
-
<div>
-
<ul>
-
<li><a href="http://www.troyworks.com">http://www.troyworks.com</a></li>
-
<li><a href="http://www.troyworks.com/blog">http://www.troyworks.com/blog/</a></li>
-
-
</ul>
-
</div>
In the CSS you just hide the div
-
-
div#contentToReplaceDiv
-
{
-
margin: 0px 20px 0px 20px;
-
display: none;
-
}
Then just follow the normal SWFObject instructions to embed a swf
A working verison can be seen here:
DRM, MetaData and swfs.
DRM in flash can be tricky, how is it you identify and pass id's to a swf duplicated a thousand times to know where it goes?
1) A temp approach is using server generated FlashVars in AS3, good for session ID's
http://blogs.adobe.com/pdehaan/2006/07/using_flashvars_with_actionscr.html
2) First not visible to actionscript is the metadata tag, preferrably writing it on th fly:
http://tutorials.lastashero.com/2005/10/using_swf_metadata_in_flash_8.html (via the IDE)
The metadata can easily be retrieved by some search engine swf plugins, it's actually what it was designed for.
There is a $30 dollar utility to batch do this to your swfs:
http://www.polarswf.com/
3) Accessible to actionscript is rewriting of variables in the swf This is useful when root vars aren't an option, and or license keys (e.g. encrypted tokens) need to be embedded into the swf.
http://neurofuzzy.net/index.php?p=25
Both 2 and 3 can be accomplished via AS3 and ByteArray. Though I haven't tried it yet.
SEO with Flash
Iconara has a great post on SEO with Flash/Flex centric sites.
Sadly in many rush-rush design centric projects, web considerations are late in the development cycle, such as user experience during preloading (this has affected about 80% of the projects I've been apart of), and SEO. Tacking these features on after the fact is prohibitively expensive.
Part of the problem, is intrinsic to the high pressure, creative first, engineering second, testing/deployement only if time permits..of those who develop flash content, being first tier largely designers concerned with experience (pixels, movement, colors), they will embed fonts, or photoshop them to get the right Typography. so even if they could be straight pages easily indexable, and bots could open up the swf to see inside (which they can do, see them, after it's been ran through a dozen photoshop filters, collaged with a dozen , and spraypainted while it will look spectacular...you might as well be giving the bot a captchas.
Even engineering probably is more concerned about how to get it to work during development, than introducing another asset to load, and attaching links dynamically, as it's one more thing to go wrong and have to be tested. Though if considered early, a loadVars or an XML file for key value pairs, isn't particularly hard to load/parse, Danny has a simple utility to help for precisely http://www.communitymx.com/abstract.cfm?cid=C45CA,
Google can and does index swfs, but it's rare that the links are actually relelvant. Frequentlly when building data driven Flash, if there are a 100 products and links to follow e.g. www.amazon.com/buyme?product.id=2, the link will be normalized into ' www.amazon.com/buyme?product.id' and '2'., with a string replace e.g.
function onClick (){
linkURL = SITE +"/" + SECTION +"?" + product.id;
}
When past projects have faced this, we used XML as the data and do client detection via a jsp/asp/etc +XLST and render HTML or Flash as appropriate.
