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.

92 thoughts on “Proper Flash embedding: FlashObject Best Practices

  1. Pingback: Jason Fox - The Ramblings » Javascript - Automatic flash content replacement

  2. Fantastic additions! This solved the problem I was having in terms of displaying my XHTML region for users without Flash rather than the default text in the jold .js file. However, now for whatever reason my “leftcol” div is screwy.

    http://www.cube-interactive.com/new_site/test/about2.html

    Anyone have any idea why this is getting pushed out of the red “topnav” div it’s supposed to be encased in? Keep in mind I’m a longtime web designer who is now trying to learn to become standards compliant. So if I’m making a rookie mistake or asking a rookie question, please forgive me.

  3. If you have a high concentration of users who will have Javascript disabled or unavailable but still have the Flash player installed, then it might be a good idea to use a Flash movie to detect the Flash player.

    But from my experience these days, plenty of people have javascript enabled and the scripting in FlashObject is very reliable – so far i’ve tested in these browsers: for PC: IE: 5, 5.1, 6 (should work in 4 as well), Firefox, Mozilla, and Opera. On Mac: Firefox, Safari, Opera, Mozilla, Camino. There really aren’t any incompatible browsers, it just depends on whether the user has Javascript enabled or not, and in my experience, most people who have Javascript disabled don’t have the Flash player installed anyway – in which case this method works better than a Flash movie for detection since you don’t need the extra page to redirect them to the upgrade page.

  4. How about flash subversion detection?
    You can hack the moockFPI to allow you to detect the subversion, such as 7.0.19.0 in order to require specific bugrelease players to be present. Any plans to include this to your FlashObject class? Overall though, nice package!

  5. I believe you can’t detect Flash sub-versions using VBScript, which is what this relies on for Internet Explorer Flash player detection. The best (and only way, really) to do proper sub-version detection is to put it inside a Flash movie.

    There’s no reason why you couldn’t use both – use FlashObject to detect the major version and embed the movie, then inside the movie double check the sub-version and either show an upgrade notice, or redirect them to somewhere else.

  6. Hi, very useful stuff, excellent job done!
    I have a problem with sending data through text flashVars though.
    Whatever I do, I can’t get our Latin2 – extended chars displayed,
    using either \u0161 or š syntax.
    I’m using utf-8 encoding and Slovenian language.
    If somebody knows something about this issue, please let me know,
    else keep working great and thanks for sharing it with us.
    With sending XML-data it works perfect

  7. This works great except I get an error on IE4 (Object doesn’t support this property or method). I’m no javascript expert so I just did a little hack which seems to work for me. Maybe someone who is a better programmer can come up with a more elegant solution for dealing with this ie4 problem.

    I made a small change to line 97

    document.getElementById(elementId).innerHTML = this.getHTML();

    with

    var happyTemp=navigator.appVersion.split(“MSIE”);
    var happyVersion=parseFloat(happyTemp[1]);
    var happyBrowserVer=parseInt(happyVersion);
    // weed out ms ie 4… it chokes on this javascript
    if(happyBrowserVer != 4){
    document.getElementById(elementId).innerHTML = this.getHTML();
    }else{
    //alert(‘You are running IE 4… which has problems with the required javascript. Please upgrade!!!’);
    }

  8. Mark,

    No, this is all custom code.

    Eric,

    That’s odd, IE4 supports innerHTML – maybe something else is making it stumble?

  9. Hey there, gooood coding indeed.

    I’m getting a little FOUC style thing in IE6.

    Using the files supplied, I added an @import reference to a stylesheet and this seems to cause the alternate content in the div to flash up for a second before being replaced by the flash.

    Anyone else experiencing this/have any solutions other than avoiding @import?

    Other than that this code is spot on for my needs.

    Ta V Much.

  10. This updated script is MY GOD beautiful. I loved the first version but was trying to have the altTxt variable include a PHP file ( a gif file was suggested ) which contained my alternative html content and couldn’t get it to work. The idea of overwriting the div with the flash content is great. I’m a designer who dabbles in programming, not a programmer, so this kind of thing keeps me from jumping off a tall building. Kudos!

  11. Thanks a lot for sharing your code and continuing to improve it, Geoff. I’ve implemented it (this version and the previous one) on two sites so far, with great results.

    Wanted to point out something in your instructions that I believe you accidentally overlooked. In the embed example in item 1 above, the “Include a link to bypass the detection” href value is ?dodetect=false. That didn’t work for me, so I checked the code and found you meant to say the value should be ?detectflash=false. That did the trick.

    Thanks again!

  12. First, as everyone says, Thanks for sharing your efforts!

    Second, my Flash movie calls back to JavaScript functions in my page via fscommand(). When trying out your code, I noticed that it would fail on certain browsers (specifically, FireFox 1.0.2). If I understand correctly, FireFox requires the Flash object to be “named” – so, I modified the flashHTML string generations from (abbreviated):

    (...) '" id="' + this.id + '" align="' + this.align + '"';

    to

    (...) '" id="' + this.id + '" name="' + this.id + '" align="' + this.align + '"';

    Now, fscommand() calling back to JavaScript works fine.

    Don

  13. I’m just wondering why you recommed using an innerHTML swap over a direct document.write?
    What advantages does this have over just defaulting to using <noscript> tags if javascript is disabled.

  14. Well this way made more sense as far as displaying alternate content goes. If a user doesn’t have the needed Flash player I would have to use document.write to write the alt content, so Google wouldn’t pick that content up, or I would have to duplicate it on the page by putting it in the Javascript and also repeating it in noscript tags.

    This way I only place my alt content once on the page, and google will read it, and if for some reason a user can’t see the Flash content (no Javascript or not a high enough Flash player) then the page still makes perfect sense sematically.

  15. When placing a link to bypass the detection …

    Include a link to bypass the detection if you wish.

    … How would i pass along variables/value pairs allready appended to the url. It seems to me that they are replaced with the ?detectflash=false.
    Sorry if this is a stupid question, but i am one of those ..I’m not a programmer, i’m a designer jadda, jadda, jadda.
    Thank you for a great solution to the ever precent Google cant crawl my flashcontent problem.

  16. You just need to add a little extra Javascript: you can either add a function that adds the extra var to the string, like so:

    function bypassDetect() {
       var sep = (document.location.href.indexOf("?") > -1) ? "&" : "?";
       document.location = document.location.href + sep +"detectflash=false";
    }

    Then, on your bypass link:
    <a href="javascript:void(0)" onclick="bypassDetect()">bypass detection</a>

  17. Hi there,

    Great script :)

    Can I call BASE attribute witht this script?

    BASE set to “.” – All the paths in the Flash Player movie file are relative to the directory in which the movie file is located. Suppose the movie file is located in a directory called movies.

    Thanks Sara

  18. Don,

    Well here’s the deal with the Javascript stuff: all browsers that use the Netscape plugin architechture have really poor support for fscommand, so what I normally do is use some method of detecting whether the user is using IE or something else (either using System.capabilities.ActiveX for Flash 7, or passing in a var after detecting it with Javascript as the page loads for all others) and then using fscommand calls for IE and direct Javascript calls for all others. The only reason I would even use fscommand with IE is to suppress the ‘click’ noise the browser makes when you call a Javascript function.

    But, if for some reason you still want to add the name parameter to the embed tag, you can do it without modifying the flashobject.js file. Just use:

    fo.addParam("name", "mymoviename");

  19. Sorry another question:
    I have this and wondered how I incorporate it:

    <param name="FlashVars" value="&skinName=/inc/clearSkin_2&streamName=/flash/media/nena512K_Stream001&
    autoPlay=false&autoRewind=true" />

    Mnay thanks :)

  20. You just add a var for each of your values:

    fo.addVariable("skinName", "/inc/clearSkin_2");
    fo.addVariable("streamName", "/flash/media/nena512K_Stream001");
    fo.addVariable("autoPlay", "false");
    fo.addVariable("autoRewind", "true");

  21. I have looked at this solution and others and have thought about another possible solution:

    Use javascript to write the flash object into a div.
    Javascript starts a timer.
    Flash sends a GetURL(“javascript:FlashOK()”)
    FlashOK() function tells javascript that everything is ok. Stop the timer.
    If the timer isn’t stopped javascript runs a function to insert alternate content into the div.

    This is just an untried concept but it possibly would be smaller and wouldn’t rely vbscript and the flash movie could return a lot more info about the player version back to js. Also the scripts would be very simple to reuse.

    Anyone got any thoughts on this idea?

  22. There’s a few things wrong with that:

    1) setting a timer and waiting for the Flash movie to call something is dangerous because your Flash movies can be different sizes and users will all have different connection speeds, so sometimes the timer would be longer, sometimes shorter.

    2) It’s better to have the alternate content in the div and have the Flash content placed using Javascript because then google will index your alt content and you’ll get better search engine results if done right.

    3) What’s wrong with relying on vbscript? IE supports it natively just fine, other browsers use Javascript to detect the plugin with no waiting and it’s very reliable.

    4) As far as returning more info to the JS – at that point the Flash movie would already be running so the extra info wouldn’t be of any use.

    5) It doesn’t get much easier to reuse the FlashObject script.

  23. Geoff, thank you! I’ve just finished implementing deep linking on my flash site, url above, using yours and Kevin’s script, works a treat!

    FWIW for anyone doing a similar project, I found using #detectflash=false works better than ?detectflash=false esp if you are adding url vars via Flash afterwards to enable browser bookmarks

    A couple of people have commented that Firefox with the latest Flash player occassionally screws up and gets shown the alt content instead of the swf, even if the required player version is set one or two versions lower than what they have installed. I doubted it, but then have seen the behaviour myself a couple of times – usually fixed by a reload. Which is why I wanted to be sure the bypass detection worked ok with bookmarks etc.

    Thanks again!

    Pete

  24. I know this is off topic, but you all seem much more experienced than I. It has to do with using Flash in email.

    Outlook blocks the ActiveX control that allows the Flash to play on incoming emails. I know that the user can change the settings as a workaround, but has anyone come up with a different way to handle the embedding or linking to the Flash file, so it appears w/out this warning.

    Seeing this Javascript option gave me hope that there’s another way to do the email as well since it uses HTML.

    I apologize if it is off topic.

  25. Pingback: Mark's Technomusings

  26. I just noticed an error in the source files. The link for bypassing the flash detection is: ?dodetect=false
    It should be: ?detectflash=false

    And another thing.
    When using IE the content of the flashcontent div tag is shown for a short while, before it’s replaced by the Flash.

    The solution is pretty simple, but it would be cool if you could include it in the flashobject script:

    <div id="flashcontent">
    	<script type="text/javascript">
    	// <![CDATA[
    	// hide the flashcontent div tag
    	document.getElementById("flashcontent").style.display = "none";
    	// ]]>
    	</script>
    	Content goes here...
    </div>type="text/javascript">
    	// <![CDATA[	
    	var fo = new FlashObject("flash.swf", "flash", "250", "250", 7, "#ffffff");
    	fo.write("flashcontent");
    	// show the flashcontent div tag again
    	document.getElementById("flashcontent").style.display = "block";
    	// ]]>
    

  27. You’re right about the bypass link. Must have been a typo – I actually thought I had fixed that already.

    As for the flash of alternate content, I’ve never seen that happen, so maybe there is something else on the page causing that? Maybe a specific browser setting? You shouldn’t need any extra code in there to make this work perfectly.

  28. I use this:

    <object type="application/x-shockwave-flash" data="flash.swf" width="300" height="100">
      <!--[if IE]><param name="movie" value="flash.swf" />< ![endif]-->
      <param name="quality" value="low" />
      Place your alternate content here and users without the Flash plugin
      or with Javascript turned off will see this.
    </param></></param></></object>
    


    It’s XHTML valid and it works perfectly.

  29. Actually, that method has some problems in Safari (versions less than 1.3) that I talk about a bit in the post (and the original FlashObject post): Safari ignores the param tags, so if you want to use any custom params they will be ignored. Things like flashvars and the different alignment options, and the ‘show menu’ option for example.

    Also, if a user does not have Flash, they will get the ActiveX sercurity popup (or the small ActiveX bar on WinXP SP2, or the puzzile piece in Mozilla/Firefox) So novice users might have no idea what that is or what they have to do in order to install the correct plugin.

    If you use FlashObject, you have full control over the alternate content, and can give your users much more friendly and informative error messages and instructions on how to download the plugin.

  30. I am having a problem with seeing the map div on my page. It loads after the flash object and is absolutely positioned over the Flash. If I just load the Flash normally, everything looks fine. But when I use your Flash embedder, the map does not show. I believe it is on a lyaer beneath the Flash movie. I tried simply setting the map’s z-index to 2, but this does not help.

    Is it because the javascript is running AFTER the page is set up? Is there a way to force the second div to the surface?

    Sorry if this question is a little elementary. I am still learning CSS and javascript.

  31. about safari ignoring param tags in object tags: in my tests i’ve actually found that safari does see the param tags, at least on my mac (safari 1.0.3, flash 7). ie/mac, however, does not.

  32. Great code works a treat its a pleasure to use and I think it is a vast improvement over straight copy n paste from MM code output

  33. Hi,
    I am very happily using your great flash detection method. Thank you for sharing this with the net!

    I generally work in flash using full-screen mode (awesome that you included an example using full-screen in the package!!). But my html “alternative” page needs its scroll bars.
    Question: Does anyone have any idea how to have a full-screen flash site but still have the scrollbars in the html page?

    Maybe like some way to write the styles for the flash movie in at the same time we write into “flashcontent”?

    Any ideas or help would be super!

  34. Bill –
    You could try this in your css:

    body {
    margin: 0;
    overflow: hidden;
    }

    this makes it so it attached the scrollbars only if they are needed. I had that problem on a site I did.
    You can see it in action here:
    http://www.ucard.utah.edu/

    The first page is full screen flash and all the other pages are html and use the same css.

    Good Luck.

  35. Uhm,
    Ok Ryan. Thanks but I dont understand. That site you linked to has no html that I can find. And I disabled my flash player and it doesn’t seem that you are using any Flash detection at all. And also I didnt see a scroll-bar at any time (that was problematic whenever my browser was not filling up my screen btw, @ 1280 * 854 ).

    Here is the problem: We are forced to use the same styles for the body of our flash movie and our html alternative. That’s no good! As soon as I get time Ill figure it out myself. I’m sure it willl be SUPER simple to write over the “styles” just like we write over “flashcontent” but I’m very new to Java Script. Whatever, Ill get it.

  36. Hopefully someone who knows their Java Script better than I can jump in here and give a better solution. But until that happens this seems to be working for me:

    this goes in your HEAD and links two different style sheets to the page but disables the first (the flash styles).

    
    <link rel="stylesheet" href="html/flashStyle.css" disabled id>
    <link rel="stylesheet" href="html/style.css">
    <script language="JavaScript">
    	if (document.getElementsByTagName)
            document.getElementsByTagName('link')[0].disabled = true;
    </script>
    

    Then we go into our lovely external flashobject.js file and add this below line 97:

    
    document.getElementsByTagName('link')[0].disabled = false;
    document.getElementsByTagName('link')[1].disabled = true;
    
    		if (elementId) {
    			document.getElementById(elementId).innerHTML = this.getHTML();
    			////////////////////////
    			document.getElementsByTagName('link')[0].disabled = false;
    			document.getElementsByTagName('link')[1].disabled = true;
    			////////////////////////
    		} else {
    			document.write(this.getHTML());
    		}
    

    Ok so what is important here is that the order of your links to your css files is: First Flash css. Then Html css.

    Basta.

    Ok now somebody jump in here and give us a better solution.

  37. Rasmus,
    I was having the same problem Using IE 5.2 on a Mac. the alternative content was flashing up for a second before the flash movie. I deleted my prferences, and restarted my machine, and all the rest. And I was testing a freshly unziped version of the package. Your fix worked great though! Pretty smart!!! Thanks!

    Awesome solution.

    This is really the best method out there for delivering alternate content, Geoff. I wish you lots of happiness and success!

    Thank you!

  38. Super-Great solution Geoff! However I am not so great, I can’t load a movie into the embedded .swf? I have tried everything. Its so elemetary, and I am beginning to think my files are corrupt. The movie loads the external movie using this.mc.loadmovie(“test.swf”) locally, but online it just sits there and doesnt load test.swf….

  39. That shouldn’t have anything to do with the embed method. But if you want to be sure, try publishing your movie using the “Publish Movie” menu in Flash and then try that out.

  40. Am using the great FlashObject with the CommunityMX extension. Very nice!
    In your Best Practices, you recommend not using the fo.altTxt and bypassTxt; just placing alternative content in the div. That, too works fine. However, is there a way to get the equilivant of fo.version as a variable to be able to use in the div (“You must upgrade to #fo.version#”–I’m using ColdFusion. Obviously, I could hard code it, but would be nice to have the variable.

    One other question: Just wanted to make sure that the false for detectflash is the string “false” and not boolean.

    Thanks for a very valuable tool!

Comments are closed.