Announcing the SWFFix project

SWFFix is a new joint project from myself and Bobby van der Sluis. The project’s goal is to replace SWFObject and UFO with a single method that is (hopefully) more standards compliant and doesn’t rely entirely on Javascript.

We’ve put up a dev blog on the site, and will be asking for help and feedback throughout the development cycle, so head over and watch the blog for updates in the coming weeks.

Bobby also has a great A List Apart article out today that talks about the problems with current Flash embed techniques.

Using progressive enhancement with Flash

There’s a fantastic article on Adobe’s devnet site that Bobby wrote (he’s the guy who wrote SWFObject’s biggest competition, UFO*). All about progressive enhancement with Flash. It includes helping your Flash content get picked up by search engines, supporting people without the Flash player, and a ton of other good info. Go have a read.

* But hey, it’s not really a competition, use whatever works best for you.

On embedding Flash content using Web Standards (yes, again)

Lately there’s been a bit of buzz around embedding plugins while adhering to Web Standardsâ„¢. First this ALA article came out and said “bye bye embed”, then yesterday one of the WaSP nerds posted something about “Valid Flash, video and audio embed (object) markup”.

It’s understandable to want to try and force browsers to display your plugin content in a way that adheres to “Web Standards”. It’s a very popular subject, and it’s been covered a few times before. These two recent articles don’t uncover anything new, other than bringing to light (via the comments on them) that Javascript is the only viable method of embedding Flash (and other plugin based) content on the web today.

Now I’m going to say something here that might seem a little controversial, but I really want to get the point across, so I’m going to use some ‘shock and awe’ tactics:

Using only the object tag to embed your plugin content (especially Flash content) is fucking stupid.

There. I said it.

You may say that I’m a bit biased because I wrote some fancy pants Javascript Flash embed script. Maybe I have a hidden agenda of world domination based on plugin detection. So while I no doubt would like to dominate the world, let me say that my reasons for advocating the use of Javascript are much more mundane.

This post was originally going to be titled “Flash Satay considered harmful,” and since the main topic are these “Web Standards” compliant ways of only using the object tag to embed plugin content, I’ll focus on the issues with doing so:

  • “Click to activate” in IE. The only way to get around this is to use Javacript.
  • No plugin detection. While Ben says ‘meh’ to this, it’s a very important aspect of the user experience. If I have Flash Player 6 installed, and I visit a site that uses Flash 9 content, my player will go ahead and try to play that swf anyway. I could end up seeing half of the content, or broken content, or who knows what. Do you really want to show your users broken content?
  • Issues in older Safari versions: Safari pre 1.2 will completely ignore param tags, which are often used to pass information to the plugin. This means broken content for your users.
  • Support for the object tag varies widely from browser to browser. Do you think that just because you work around all the quirks in the 3 main browsers today, it will still work when the next new browser is released?
  • A bug in Flash Player 9 can cause the browser to crash if you have more than one swf on the page and are using ExternalInterface to communicate with Javacsript. While this isn’t specifically related to how the swf is embedded, SWFObject does include a fix for this issue.
  • Using Flash Satay or other ‘object only’ methods will not stream your Flash movies to the user – this means extra work for you in creating a ‘loader’ swf
  • JAWS will ignore it.

It’s a pretty long list, right? Now if you compare that to the user experience when using SWFObject (or other Javascript based techniques), you can see a noticable difference:

  • The only time a user doesn’t see Flash is if they have Javascript turned off, or they don’t have the required version of the Flash Plugin. This one is a two parter: One, do you think that people really turn off Javascript but leave Flash on? Consider the type of person who turns Javascript off. They are probably the über nerd user who considers anything that isn’t text to be completely evil. They browse the web using Lynx. They probably stay a mile away from the Flash Plugin anyway. The beauty of the way SWFObject works is that even these people get content if you set it up right. Since you put alternate content ‘under’ your swf, they will just see the alternate content. As long as you set it up right (you do, don’t you?) they may never even know they are missing out on Flash content.
  • They don’t have to click your movie once to ‘activate’ it
  • Their browser doesn’t crash just because you had two swfs on the same page that use ExternalInterface
  • They only see Flash content if their browser and plugin support it.

Taking all of the above into account, the choice is very clear: Javascript wins hands down. Any questions?

Now that all of that is taken care of, I wanted to address a couple of things:

First, these types of posts are not good for the Web Standards community. Basically what’s happening is highly visible people (even if they aren’t that well known, they still carry the WaSP name, or have articles on well respected online publications like A List Apart) are posting information that is bad for your users. Even worse is that they are doing it in the name of “Web Standards” and not taking into consideration any of the other options outside of pure HTML. This is extremely bad for the Web Standards movement. It makes the standards advocates look like crazed zealots who don’t care about user experience, but only care about adhering to the written rules exactly how they are stated even if it hurts them.

Second, you may be saying “well, if I can’t use the object tag, then what good is it?” and that is a FANTASTIC question. What good is it? Beats me, because the object tag is completely and utterly broken in nearly every web browser out there. Want to do something about it? Maybe you could join WaSP and create a task force to fix how browsers handle plugins?

UPDATE: I added this as a comment below, but wanted to put it in the main post as well: I want to say that as for Flash Satay: It was fantasic for the people who use(d) it, and in it’s time it was great. But now that certain big issues with it have been discovered, and Flash has changed over time, it’s time for it to retire. This is something I’ve been meaning to mention for a while, and it was sort of implied on the SWFObject page. So, since we are on the subject, it’s time to give it up.

UPDATE (8-17-2006): Ben has posted a follow up.

A modern approach to Flash SEO

Search engine optimization is one of the most popular subjects when nerds sit around and talk about Flash. “Does Google index your swf files?” seems to be the most popular question, usually garnering plenty of ‘yes‘ and ‘no’ and ‘maybe’ answers. The real answer to this question, once and for all, is this:

It doesn’t matter.

To understand this answer, you need to understand what Flash is. And to do that, you need to understand modern web development philosophy. First off, you need to embrace web standards. Semantic markup and separating content from style and behavior is the only way you should be building your sites. Many web standardistas have been recommending this method of web development for years, and rightly so. However, this post isn’t the place to go into the whys of this type of development, so I’ll skip that part and just say this about how it’s done: There are three areas of front-end web development: Content, Style, and Behavior. You should always keep these three things separated as much as possible.

That brings up the question: “Where does Flash fit into this three pillar method of web development?” Is it content? Is it behavior? Is it style? While it could be considered all three, most professional Flash developers will remove the content from their Flash movies and load it in using Flash remoting or XML files. That leaves us with style and behavior.

Style is added using CSS. Generally when you add images to your HTML that are purely presentational (no text or required content in them) you should add them in using CSS. In most cases you don’t want Google to index them because people don’t search the web for ‘top left rounded corner gif.” They search for content. Even if Google upgrades their crawler someday to read CSS files and index the images, they probably wouldn’t use the information for more than statistical analysis because of this.

Behavior is generally added using Javascript. Maybe you want a new window to open set to a certain size, or you want to use some fancy Ajax to let users rate something without refreshing the page. This should all be added unobtrusively, and if the browser doesn’t support Javascript, it will hopefully still work. Unfortunately, not everyone considers this, and these days Javascript is becoming more and more of a requirement to use most websites. So you should always provide some sort of alternative for non-Javascript users. When it comes to indexing behavior, Google will for the most part not index your Javascript files. Even if it did, most web users would have no idea what the .js file they are looking at actually does. When using Javascript to change your document, Google will not read the ‘final’ page, but only the raw HTML file. Google does not render Javascript 1.

Now that you know all of this, it’s time to look at how to treat your Flash content. Since we’ve determined we don’t want Google to index our swf files, but we do want it to index the content displayed inside them, what is the best way to go about this?

As stated before, if you are building Flash sites professionally, you probably move all your content out of your Flash movie and into an XML file or keep it in a database. This makes it much easier to allow Google to index this content by using progressive enhancement.

Progressive enhancement is a method of web development that goes hand in hand with Web Standards. You start with your HTML (your content), then add CSS (your look and feel), then add in additional behavior (Javascript, Ajax, Flash, any other interactivity that isn’t handled automatically by the browser).

The best way to add Flash progressively is by using Javascript, or more specifically, a script like FlashObject. First you lay out your page as if you aren’t using Flash. If you are using a database for your content, you can spit out that data as HTML where the Flash movie will go on the page (or maybe just a preview of the content, it’s up to you to show Google the content you would like indexed). Then you use FlashObject to replace this content only if the user has Javascript enabled and the required Flash plugin version.

Here’s a small example of what that might look like:

<div id="flashcontent">
    This is replaced by the Flash content if the user has the correct version of the Flash plugin installed.
    Place your HTML content in here and Google will index it just as it would normal HTML content (because it is HTML content!)
    Use HTML, embed images, anything you would normally place on an HTML page is fine.
</div>
<script type="text/javascript">
    // <![CDATA[
    var fo = new FlashObject("flashmovie.swf", "flashmovie", "300", "300", "8", "#FF6600");
    fo.write("flashcontent");
    // ]]>
</script>

This causes Google to skip the Flash swf files and only index the HTML (the content!) you place on the page. You can place links to other pages, images, whatever you want Google to index, and when a viewer with a browser that supports Flash visits your site, they will then see the Flash content. This gives you full control and much greater predictability over what content Google will index. And if your content is pulled from a database that is editor controlled, your pages will update and be re-indexed as the content changes without the need to re-publish all your swf files.

1 Currently Google does not render the Javascript on a page, but there are rumors that they are developing a new crawler based on Firefox (they employ a number of Mozilla foundation members) that will index pages based on how the browser sees them, instead of the raw HTML content. This means HTML hidden by CSS may not be indexed, and pages that are altered by Javascript after they load will be indexed how they appear to the user. However, this is all rumors and until it happens Google will ignore your Javascript content.

Note: In this article I use the ‘Google’ name often, but it can be interchanged with any search engine, as they all work roughly the same way.

Proper Flash embedding: FlashObject Best Practices

UPDATE (7-24-2005): This page refers to an old version of the FlashObject script. For questions or comments, or to download the script, please refer to the permanent home of the FlashObject script.

This post is a continuation of a previous post. Read this for more background information on the FlashObject embed method.

In the months since I posted the FlashObject embed I’ve had a chance to talk to a number of developers and use it in a few high traffic projects. In doing so I’ve picked up some tips and best practices that I’ll be outlining here. I’ve also revamped the FlashObject script so it’s a bit more light weight and fixed a few small bugs.

What’s new?

  1. Alternate content is no longer written to the page by default – You may still use the fo.altText variable to add alternate content to your pages, but it is not recommended. The way to display alternate content in your pages with Flash content would be to place the alternate content on your page, and then specify the ID of the element with your content inside. The FlashObject script then writes your Flash content inside that element, replacing your alternate text/content so the end user with Flash will never see it, but users with no Javascript or without the required Flash version will see the alternate content. Google will also index your alternate content since it is just plain HTML.

    Here is an example of what your embed should look like:

    <div id="flashcontent">
      Place your alternate content here and users without the Flash plugin 
      or with Javascript turned off will see this. 
      Include a link to <a href="?detectflash=false">bypass the detection</a> 
      if you wish.
    </div>
    <script type="text/javascript">
     // <![CDATA[
      var fo = new FlashObject("fo_tester.swf", "fo_tester", "300", "150", 6, "#336699");
      fo.write("flashcontent");
     // ]]>
    </script>

    Because of this change, you should always specify the ID of an element to write your Flash content into. You should also be sure to always include alternate content on the page. If your Flash movie is purely decorational, you can leave the div empty, similar to using empty alt attributes (alt="") on decorational images. Also note that with the new version you need to place your Javascript that writes the Flash content after the element that will contain your Flash content, as in the example above.

  2. Support for pulling variables from the URL string when using anchors – There have been some discussion about Flash state tracking and direct or ‘deep linking.’ Most of the methods rely on parsing variables from the URL when the movie loads, so now you can pull vars out using the built in function getQueryParamValue().

    Example:

    If your URL is:

    flashobjectpage.html#var1=value1&var2=value2

    You can pass those vars into your Flash movie by using the following code:

    var fo = new FlashObject("fo_tester.swf", "fo_tester", "300", "150", 6, "#336699");
    fo.addVariable("var1", getQueryParamValue("var1"));
    fo.addVariable("var2", getQueryParamValue("var2"));
    fo.write("flashcontent");

    The same works for normal URL parameters in URLs such as:

    flashobjectpage.html?var1=value1&var2=value2

Just to recap some of the things posted in the previous FlashObject post, here’s some of the thinking behind the FlashObject embed method:

Why Javascript?

Javascript is the best overall solution for a number of reasons, among them:

  1. With Javascript you can detect the presence of the Flash Player on your user’s system and either display the Flash content or leave the existing (X)HTML on the page. This is also a huge advantage when it comes to search engine indexing since the alternate content is on the page and will be indexed as normal content. This also prevents novice users from seeing Internet Explorer’s ActiveX install box, which on Windows systems pre-SP2 is a very scary thing these days with all the Spyware and Malware running around on the internet. On most other browsers, you’ll likely see some empty box where the Flash content should be, sometimes with a broken image or puzzle piece icon which most novice users have no idea what to do with (Should they click on it? Is it part of the site?). If you include well written upgrade/install instructions in your alternate content, all of these problems are avoided.
  2. No Extra configuration files for each Flash movie. Some alternate methods of embedding Flash content in XHTML documents include using extra configuration files or ‘holder’ movies that load in other movies. With this method there is no need for any extra files aside from the single .js file.
  3. Easy to serve different content to different browsers. I worked on a project recently that made extensive use of the wmode=transparent option. Well when you are using IE or Firefox you can use wmode=transparent with the Flash 6 player, but if you are using Apple’s Safari browser, you need Flash player 7 to see the content properly. So in the embeds on the page, we required Safari users to have the Flash 7 player, and everyone else the Flash 6 player. Without Javascript we would have had to force everyone to upgrade to Flash player 7, something we didn’t want to do, even though the Flash 7 player has a pretty high penetration percentage.

Problems with Flash Satay/pure Object tag embedding

The main issue with using any embed method that uses only object tags to embed any plugin on a page is that Safari ignores the param tags. For very basic embeds this isn’t a problem, but when you want to start passing in variables or change the background color of the movie without re-publishing it you start to run into problems.

The one area where using pure object tag embeds shine is in using XHTML pages that are sent with a mime type of application/xhtml+xml. Since the FlashObject script uses innerHTML and sometimes document.write, it is not compatible with pages sent with the application/xhtml+xml mime type. Currently I have no plans to update it to work with these pages, as there are many issues with creating object tags using the DOM because almost every browser engine handles it differently and has little quirks that make it very hard to work around. If you are interested in seeing some of the code it would take to embed Flash in XHTML documents, check out the excellent Javascript that comes along with sIFR 2.0.

Download

Download the source to FlashObject 1.1.1.

Download the source to FlashObject 1.3.

View sample pages using FlashObject 1.2 in different Flash embed situations.

UPDATE (5-5-2005): If anyone is interested, Paul Newman has wrapped this script into a Dreamweaver extension. It costs $15 (or free to CommunityMX subscribers), but if you are a not-so-technical Dreamweaver user I think it would be worth it.

UPDATE (5-17-2005): Made a small change to the embed tag output. I changed the id attribute to a name attribute as Firefox needs it that way in order to use LiveConnect and talk to the plugin via Javascript.