Flash Satay: Embedding Flash While Supporting Standards

I’ve worked with Flash for several years and have always been slightly dissatisfied with the markup needed to embed a movie in web pages. When I recently published a site in XHTML, my dissatisfaction with the markup grew as I realized that it simply wasn’t valid in this context and was bloating my pages to unacceptable levels. A leaner, standards-compliant method of embedding Flash movies was called for.

Article Continues Below

The Twice-Cooked Method#section2

Flash has always shipped with some method of generating an HTML page to contain Flash movies. Initially, it was a tool called AfterShock. Since the release of Flash 4, authors can export HTML pages with embedded movies from within the Flash authoring environment. This markup produced by Flash is the de facto standard that you’ll find in 99% of sites that use Flash movies.

<object 
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
codebase="http://download.macromedia.com /pub/shockwave/cabs/flash/swflash.cab#versi
width="400" height="300" id="movie" align="">

<embed src="movie.swf" quality="high" width="400"
height="300" name="movie" align="" 
type="application/x-shockwave-flash"
plug inspage="http://www.macromedia.com/go/getflashplayer"> 
</object>

As you can see, it’s a bit of a monster. There are two main tags used to embed the movie, requiring every value to be declared twice. Internet Explorer and its followers primarily use one tag; browsers that consider themselves friends of Netscape use the other. We’ll call this the Twice Cooked method.

<object> is part of the XHTML specification, but is badly implemented here. It is used by IE style browsers to start an instance of the Flash Player and load in the specified movie. The <param> element is its bedfellow, offering any number of parameters to be passed to the player once it is started.

<embed> is not part of the XHTML specification and will prevent your page from validating. It is used by Netscape and similar browsers for displaying Flash movies. Parameters are passed within the element as name/value attribute pairs.

The <embed> Element#section3

The <embed> element was created by Netscape as their method of embedding plug ins and players in web pages. It’s not part of the XHTML specification, and while some browsers other than Netscape support it, it’s not standards-compliant, so it’s out.

Bye bye, <embed> … it’s been swell.

The <object> Element#section4

Without <embed>, we’re left with the <object> element, so it would be prudent to fully understand its capabilities. The great news is that just about every browser in popular use supports <object> in one way or another.

The <object> element has no required attributes, but many are available for use. Below are the more interesting ones, along with edited highlights from the W3C specification.

classid (URI) This attribute may be used to specify the location of an object’s implementation via a URI. It may be used together with or as an alternative to the data attribute (see below), depending on the type of object involved.

codebase (URI) This attribute specifies the base path used to resolve relative URIs specified by the classid, data, and archive attributes. When absent, its default value is the base URI of the current document.

data (URI) This attribute may be used to specify the location of the object’s data, or more generally, a serialized form of an object which can be used to recreate it.

type (content-type) This attribute specifies the content type for the data specified by data.

codetype (content-type) This attribute specifies the content type of data expected when downloading the object specified by classid.

There are other attributes that allow references to archived versions, cause text to display while loading (we can do this is Flash already), and so on, as well as width, height, id, class and other common attributes. The ones listed above, however, are particularly relevant when it comes to embedding Flash movies.

Another useful thing I learned is that an <object> tag can contain child elements which can be used as an alternative if the browser doesn’t have the capability to display the object itself. In fact, this is how the undesirable nested <embed> works in Netscape browsers—but more on that later.

The Process#section5

Armed with a more thorough understanding of the markup, I set about doing some testing in various browsers. My first step was to try the Macromedia markup with the <embed> stripped out, and cleaned up for XHTML:

<object
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
codebase="http://download.macromedia.com /pub/shockwave/cabs/flash/swflash.cab#versi
width="400" height="300">
 
</object>

Unfortunately, this simply doesn’t work outside IE-style browsers. After a little jiggerypokery and some Googling, I discovered that the GUID used in the classid attribute was specific to the browser’s ActiveX configuration. In fact, it was causing Netscape 7 and Mozilla to totally ignore the object. The classid attribute does, however, perform an important function: telling the browser which Player to use. So we can’t simply get rid of it without replacing its functionality with something else.

Fortunately, the Flash Player is configured to respond to content with a MIME type of application/x-shockwave-flash. This is great, because the type attribute allows us to specify a content type. Therefore, out goes:

classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"

… and in comes:

type="application/x-shockwave-flash"

Codebase#section6

The above change doesn’t get movies playing in Netscape browsers on its own. The next curiosity on the list is the codebase attribute. This contains a path to a copy of the Flash plug in-on Macromedia’s servers. This is actually incorrect usage of the attribute, as any paths within it are supposed to be within the same domain—a security feature.

In many browsers (primarily IE) this attribute performs another function. The path contains a string on the end that specifies which version of the plug-in the server should deliver. If the version declared is later than the version currently installed, the browser will prompt the user to allow it to update. The downside is that this attribute also stops the movie from playing in Netscape and Mozilla when used in this way, so it’s gotta go. We’ll discuss a work-around for this lost functionality later on. With the codebase attribute gone, our markup is beginning to look pleasantly sparse:

<object 
type="application/x-shockwave-flash"
width="400" height="300">
 
</object>

Try this code, and it still won’t load a movie in Netscape. Having gotten this far, I worried that there was literally no way to use valid markup to deliver Flash in Netscape browsers, and every response to this question online told me as much. So I did what I always do and started trying crazy things.

Making Progress#section7

When I tried out the data attribute, I nearly had kittens, as movies suddenly started playing in Netscape and Mozilla. Flipping back to IE revealed that the movies played there too.

<object
type="application/x-shockwave-flash" data="movie.swf" 
width="400" height="300">

</object>

After testing with some largish movies, I noticed something amiss. While every other browser was getting it right, IE/Windows was not streaming—it was waiting for the entire movie to download before playing it. This is fine for small movies, but for anything serious, the lack of streaming is unacceptable. I concluded that valid markup for Flash movies was possible, but only once Microsoft had fixed this problem with IE/Windows.

The Satay Method#section8

A few days later I was discussing this issue with Jeffrey Zeldman, explaining how I’d come close to a solution but hadn’t quite found it. He was interested that I’d managed to come close, having experienced the problem himself on recent projects. This got me thinking, and while driving home that evening the solution hit me.

The only problem with the code I had is that IE/Windows doesn’t stream the movie. It waits for the whole movie to download and then plays it. This is fine for very small movies, as the wait isn’t that noticeable. So, how about creating a very small container movie, which in the first frame loads in the real movie we want to play?

I tested it, and it works. It’s a bit of a hack, but a valid and justifiable hack in my opinion. The greatest thing is that you don’t have to create a separate container movie for each “real” movie—one smart container can work with any Flash movie having the same proportions.

No matter if your movie is made from beef, chicken, or pork, you still need to skewer it and dip it in the sauce to make it work. We call this the Satay Method.

The container movie#section9

I created a new Flash movie and put the following ActionScript on Frame 1 right in the root of the movie:

_root.loadMovie(_root.path,0);

This instructs the Flash Player to load a movie, whose name is in the variable path on the root, into Level 0 of the current movie. All we need to do is make sure that the name of the movie we want to load is held in the variable called path.

Flash makes this part easy. The Flash Player loads any name/value pairs that are passed to a Flash movie on a query string into the root of the movie.  This is useful for many different applications, but in our case it means that we just need to call the movie like this:

c.swf?path=movie.swf

The container movie is c.swf. I’m passing it a variable called path with a value of movie.swf. This means that our ActionScript, when evaluated, would equate to this:

_root.loadMovie("movie.swf",0);

You can modify the behavior of the container movie to do whatever you like—as long as it’s kept small. You can use GET and POST to pass variables through the container if you need to, for example. This method, however, will only work well if the container movie is just a few kilobytes in size.

The markup#section10

This leaves us with just the markup to finalize. We’ve dropped a lot of attributes, added some sparkling new ones, and tidied it all up:

<object type="application/x-shockwave-flash"
data="c.swf?path=movie.swf" 
width="400" height="300">

</object>

So there it is—meaner, leaner, and altogether better for the environment. But what about that functionality we lost when axing the codebase attribute?

Compensating#section11

The main problem with getting rid of the codebase attribute was that in IE and similar browsers it caused the user to be prompted to update their Flash plug-in if it was out of date. This is really useful, as it’s likely the only way that most ordinary web users get their players updated.

The workaround is simple: just include one sacrificial movie at the front of your site with the codebase attribute left in. This needs to be a movie with no purpose within the site—just a 1k empty blob of nothingness that causes the user to be prompted if they have an old version of the plug in. Not the cleanest approach, but a practical one. It shouldn’t lose you any friends.

Alternative Content#section12

Remember that behavior of the <object> tag I was talking about earlier, where the browser will try to parse a child element if it can’t work with the object itself? It’s very cool.

If you were to look at the source code of the home page at Macromedia.com, you’d see that they serve up an alternative image if the user can’t view Flash movies. They are detecting the Flash Player with JavaScript, and then using JavaScript to dynamically write out HTML based on the detection. Ugly, ugly, ugly. Here’s how I’d do it:

<object type="application/x-shockwave-flash
data="c.swf?path=movie.swf" 
width="400" height="300">

<img src="noflash.gif" 
width="200" height="100" alt="" />
</object>

If the browser doesn’t know how to play objects with a MIME type of application/x-shockwave-flash, it will simply go for the next child element and give that a try. I’m guessing that a simple image element should be okay for most people. Failing that, you can simply use text.

Work in progress#section13

I’ve written this article with the knowledge that it’s simply one man’s findings and thus a work in progress. Consider it like a scientific theory: what I state today is only proven until it’s disproved.

265 Reader Comments

  1. The following CSS has worked for me using the XHTML 1.0 Transitional DOCTYPE, to display a flash file at 100% width and height (ie. it stretches to fit the full browser window) – note the inclusion of EMBED which is the Gecko (Mozilla/Firebird/Netscape…) bit:

    body, OBJECT, EMBED {
    padding: 0;
    margin: 0;
    width: 100%;
    height: 100%;
    position: absolute;
    }

  2. Re: coda
    Well, actually we are forgetting about the embed element, as it is not part of the XHTML
    specification and will prevent your page from validating. Only the object tag/element is being used. See the W3C validator service: http://validator.w3.org

    There is no need to use embed as a selector. Also, the {absolute: position} as part of
    an object selector, kills the display in NS 6.0, 6.01, and 6.1….and height: 100%;
    over-scales in NS 4.8 or less. See previous posts for more details on these issues:
    http://www.alistapart.com/discuss/flashsatay/25/

    I can understand if you say to hell with NS 4.8 or less, but NS 6.x is still fairly new and in use by many. Also if you don’t care about NS 4.8 or less, then I would expect that you would be detecting for those older browsers and posting a notice page with a browser upgrade link. The average user doesn’t know how or where to upgrade their browser unless we direct them.

  3. I only realised after my post that there were 25 previous pages of dicussion. 😉 It’s good to know about those issues, thanks for that.

  4. There is a point I do not see here. I try to use the Satay method but I have big trouble when trying to use .
    First it doesnt work at all on Opera (but it seems Opera doesnt recognize this properties) and on Explorer and Mozilla, my animation have strange behavior. Do anyone know if using the transparent properties is compatible with the standards?
    Thanks!

  5. Reason why web standards are important to me:
    – At my company we develop web applications for Wireless/Handheld devices. Adhearing to web standards is the only way a company can write a simple/efficient browser for these smaller devices. If the HTML doesn’t validate, most of the time it won’t even run.

    – HTML Validation helps me debug my generated content with my php/perl pages. It will help tell me where/if i forgot to add a closing tag, or if my loops are bad.

    I’ve been using a Javascript hack to get my Flash stuff to validate in the past. Taken from here:
    http://www.davidsonbicycles.com/html/home.shtml

  6. Re: jOrd
    Well, the author of davidsonbicycles.com is simply wrapping

    (Of course, now the future threat of Eolas/IE may force me to change how this code is delivered to the page.)

    And when I need my Flash object to be 100% width and height, then I use this CSS selection in addition to the Javay:

    But in all fairness, perhaps the author of davidsonbicycles created the site long before this research was available. So, credit may be in order for cleverness. In the past, I have been bad at maintaining web standards in some of my site designs. I too have sinned.

    It's also good that you are dead-set on maintaining web standards. Web developers/designers with such enthusiasm are few and far between. It's important that we continue to trade ideas and encourage each other in this important issue of XHTML compliance, because if we don't push it, then no one else will.

  7. So many times I read articles about Flash, HTML, etc.. and I get confused, quickly (that is of course, unless I had had about 3 Starbucks Doubleshots)…

    It was simple, easy to understand, and flowed well for me – and now.. to try it!

  8. Interesting reading. I tried it on a site I am developing, using flash for navigation. We have 5 categories, each with a color theme controlled by css, and matched in the flash navigation: Within the flash movie I change the color of a rectangle serving as a background, and text color, depending on the arguments passed to the flash movie via the URL. When I added these arguments to the definition of “path” they seem to have been lost by the time the movie plays. I’m still somewhat of a newbie to all of this, so if I missed something, please enlighten me. [Using the non-compliant code, the process worked fine.]

    my code now reads:

  9. I’m currently working with a number of Flash movies that interact with Javascript for various reasons.

    When I try using this method it seems that the Flash player in Mozilla browsers is unable to pick up on either the name or id attribute of the object tag (it typically uses the name attribute of embed).

    Does anyone know of a way to use just the object tag but still have FSCommand work properly in Moz?

  10. I’m sorry if this question has been mentioned before. I have looked through and I cannot find a solution in the forum. The flash satay method works excellent in Mozilla and IE, but it will not work on Firebird 0.7 for me (flash simply does not appear). I do not use percentages for the height. The code is below:

    It is not the standby and it is not the transparency parameter. This can be seen at http://www.xdemi.com/music/main.php

    Any solutions?

  11. This really works and while no container has been used for Flash, the page validates for XHTML. It works in Mozilla, Internet Explorer 6.0, 5.5, 5.01 and other browsers, too.

    Nadácia Milana Šimečku
  12. Re: dusoft
    “This really works and while no container has been used for Flash, the page validates for XHTML.” Well dusoft, not exactly. Sure your code validates, but it does not work in all situations. First off, when I.E. encounters the data element it will not stream. Just pump your banner.swf up to 1 MB and view it with a dial-up to see what I mean. I.E. will give you a white box and wait for the file to completely download before playing it. Second, your code will not work in a full Flash situation. If you change your width/height to 100% you will quickly see a blank screen in newer Netscape/Firebird browsers. You have to remedy that with the appropriate CSS:

    Until Eolas hits, I am using the Javay method over the Satay method to resolve these and more issues. For a more detailed explanation, see previous posts:
    http://www.alistapart.com/discuss/flashsatay/26/

    Your method works good for a small Flash file and because you are not using percents, but it will not work for other situations beyond that. Also buy cutting out the codebase you are giving up an easy way to upgrade older Flash players for your I.E. visitors. And without a codebase, some web devers will try to use entry pages. Entry pages like, “You must have Flash player X to view this site..”, are a big waste. Most people don’t even know what a Flash player is, let alone what version they have. Hell, even I forget what Flash version I have sometimes. Flash player detection through JavaScript or with a Flash movie itself may be needed. Server-side detection is not yet reliable in all browsers.
    Flash detection should always remain invisible to the visitor.

    But a lot of what I’m saying has already been covered in previous posts, though.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career