Stop flash from covering HTML content

Browse through a few developer forums and you will find lots of people pulling their hair out over flash content covering up their dropdown menus or modal windows.  The problem is especially bad in IE (surprise, surprise). The fix is actually quite simple as long as you can edit the embed code for your flash. The trick is to change the wmode parameter to either “transparent” or “opaque”.  You should do this for both the <embed> and <object> tags like this:

<object width="200" height="300" data="example.swf" type="application/x-shockwave-flash">
    <param name="quality" value="high" />
    <param name="wmode" value="transparent" />
    <param name="src" value="example.swf" />
</object>

The problem is you don’t always have the option of changing the embed code.  What if you’re developing a JavaScript widget and don’t have any control over how the flash is embedded?  The solution is more complicated than you would expect.  It turns out there are a slew of IE bugs around the <object> tag that escalate what should be a simple task into a real headache.  Basically you need to replace each <embed> and <object> tag with a cloned version that has had its wmode parameter fixed. Here’s how you do it:

<script type="text/javascript">

function fix_flash() {
    // loop through every embed tag on the site
    var embeds = document.getElementsByTagName('embed');
    for(i=0; i<embeds.length; i++)  {
        embed = embeds[i];
        var new_embed;
        // everything but Firefox & Konqueror
        if(embed.outerHTML) {
            var html = embed.outerHTML;
            // replace an existing wmode parameter
            if(html.match(/wmode\s*=\s*('|")[a-zA-Z]+('|")/i))
                new_embed = html.replace(/wmode\s*=\s*('|")window('|")/i,"wmode='transparent'");
            // add a new wmode parameter
            else
                new_embed = html.replace(/<embed\s/i,"<embed wmode='transparent' ");
            // replace the old embed object with the fixed version
            embed.insertAdjacentHTML('beforeBegin',new_embed);
            embed.parentNode.removeChild(embed);
        } else {
            // cloneNode is buggy in some versions of Safari & Opera, but works fine in FF
            new_embed = embed.cloneNode(true);
            if(!new_embed.getAttribute('wmode') || new_embed.getAttribute('wmode').toLowerCase()=='window')
                new_embed.setAttribute('wmode','transparent');
            embed.parentNode.replaceChild(new_embed,embed);
        }
    }
    // loop through every object tag on the site
    var objects = document.getElementsByTagName('object');
    for(i=0; i<objects.length; i++) {
        object = objects[i];
        var new_object;
        // object is an IE specific tag so we can use outerHTML here
        if(object.outerHTML) {
            var html = object.outerHTML;
            // replace an existing wmode parameter
            if(html.match(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")[a-zA-Z]+('|")\s*\/?\>/i))
                new_object = html.replace(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")window('|")\s*\/?\>/i,"<param name='wmode' value='transparent' />");
            // add a new wmode parameter
            else
                new_object = html.replace(/<\/object\>/i,"<param name='wmode' value='transparent' />\n</object>");
            // loop through each of the param tags
            var children = object.childNodes;
            for(j=0; j<children.length; j++) {
                if(children[j].getAttribute('name').match(/flashvars/i)) {
                    new_object = new_object.replace(/<param\s+name\s*=\s*('|")flashvars('|")\s+value\s*=\s*('|")[^'"]*('|")\s*\/?\>/i,"<param name='flashvars' value='"+children[j].getAttribute('value')+"' />");
                }
            }
            // replace the old embed object with the fixed versiony
            object.insertAdjacentHTML('beforeBegin',new_object);
            object.parentNode.removeChild(object);
        }
    }
}

</script>

This solution is adapted from code I found on QIndex. Hopefully this version is a little cleaner and easier for people to find.

Note: There is also a jquery version of this code, complements of José Nobile.
  • Pingback: Интересното от 17.08.2009 | DevStorming.com()

  • http://www.nobilesoft.com José Nobile

    I Write a more litte javascript using jQuery, working better, dont use regular expression.

    Key Features:

    Only include the script in any webpage, it change/add the wmode to transparent, to embeds and objects
    Work with or without jQuery included. (if is not jQuery, it is included using Google CDN Service (minimized and Gziped) -> http://ajax.googleapis.com/ajax/libs/jquery/1.3.2
    Compatible with other libraries (ej Mootools) using jQuery.noConflict();
    Work at Firefox 2.0+, Internet Explorer 6+, Safari 3+, Opera 9+, Chrome 1+
    Use Dom Ready, is possible to include the script at head of html.

    The Source is available for download from:

    http://www.nobilesoft.com/Scripts/fix_wmode2trans

    A Minimized version:

    http://www.nobilesoft.com/Scripts/fix_wmode2trans

    The version minimized and Gziped is only 637 Bytes !

    Or the Source:
    <code>
    function LJQ() {
    var sc=document.createElement('script');
    sc.type='text/javascript';
    sc.src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&#039;;
    sc.id = 'script1';
    sc.defer = 'defer';
    document.getElementsByTagName('head')[0].appendChild(sc);
    window.noConflict = true;
    window.fix_wmode2transparent_swf();
    }

    if(typeof (jQuery) == "undefined") {
    if (window.addEventListener) {
    window.addEventListener('load', LJQ, false);
    } else if (window.attachEvent) {
    window.attachEvent('onload', LJQ);
    }
    }
    else { // JQuery is already included
    window.noConflict = false;
    window.setTimeout('window.fix_wmode2transparent_swf()', 200);
    }

    window.fix_wmode2transparent_swf = function () {
    if(typeof (jQuery) == "undefined") {
    window.setTimeout('window.fix_wmode2transparent_swf()', 200);
    return;
    }
    if(window.noConflict)jQuery.noConflict();

    // For Internet Explorer
    jQuery("object").each(function (i) {

    var algo = jQuery(this).context.attributes;
    var str_tag = '<OBJECT ';

    for (var i=0; i < algo.length; i++)
    str_tag += algo[i].name + '="' + algo[i].value + '" ';

    str_tag += '>';

    var flag = false;

    jQuery(this).children().each(function (elem) {
    if (jQuery(this).attr("NAME") == "wmode") {
    flag=true;
    str_tag += '<PARAM NAME="' + jQuery(this).attr("NAME") + '" VALUE="transparent">';
    }
    else
    str_tag += '<PARAM NAME="' + jQuery(this).attr("NAME") + '" VALUE="' + jQuery(this).attr("VALUE") + '">';
    });

    if(!flag)
    str_tag += '<PARAM NAME="wmode" VALUE="transparent">';

    str_tag += '</OBJECT>';

    jQuery(str_tag).insertAfter(this);
    jQuery(this).remove();
    } );

    // For Firefox Browser
    jQuery("embed").attr("wmode",'transparent');
    jQuery("embed").each(function(i) {
    jQuery(this).clone().insertAfter(this);
    jQuery(this).remove();
    });
    }
    </code>

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Nice. I was using this on a javascript widget and didn't have the privilege of using jQuery. Thanks for sharing.

      • http://www.facebook.com/casler Bryan Casler

        I was wondering if there was a benefit to using the jQuery version vs the JS version. I'm currently running a drupal site and I could support either or.

        Side question, if you think I should use the jQuery version. Drupal already has jQuery.js in it, so how can I prevent the jquery version from being downloaded again? Do I just remove the "LJQ" function?

        • http://www.onlineaspect.com Josh Fraser

          Use the jQuery version if you've already taken the hit of loading it in. It already handles checks to see if jQuery is defined before loading it in.

  • http://www.nobilesoft.com José Nobile

    Ok, you can include the script in any webpage or javascript without jQuery already included and the script auto include jQuery and noConclift mode, it may be perfect compatible with you javascript widget :-)

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Sure, I just don't want to add a javascript library on other people's sites when it's not necessary. My widget is 8K. JQuery would add 50k. It's not a good trade-off to add 50k to save 1k. Performance matters a lot to me as people are very sensitive to how much a widget slows their page down. The jQuery solution is great if you've already taken the hit on including the library.

  • http://www.nobilesoft.com José Nobile

    mmm, you comment is good, if you widget is only 8K is better a solution using "native" javascript.

    but, only two observation: Google CDN (Content Delivery Network) put the hosted content at GZiped, how the jQuery library, the version hosted at http://ajax.googleapis.com/ajax/libs/jquery/1.3.2
    is only 19K (Gziped), the time to load the file and process is beetween 120ms and 500ms (0.5 seconds)

    Dont try: if (embed.outerHTML) {

    Firefox had not outerHTML, is safe remove these conditional.

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Yeah, the Google CDN is good. Of course, the biggest advantage is the increased chance of getting a local cache hit. The more people use Google, the better the service becomes for everyone. Eventually those libraries are just going to be built into browsers.

  • fractalbit

    I wish i had discovered this earlier. A drop down menu for navigation was hiding behind a flash. You can imagine how angry the users get when they cannot navigate to your site. Now imagine their anger considering the fact that the flash movie blocking navigation was a… 720×90 advertisment! Unfortunately i did not had direct control of the advertisment. I had to contact the advertisment provider and spend hours on the phone trying to explain them how and why they should set the wmode of the flash file to transparent :(

    Next time this happens to me, i will try your script. Many thanks!

  • http://www.zby.cz/ zby-cz

    Hello, the code above doesnt work, since there are missing some escape sequences in the regexps :) (Meanwhile its possible to use code from this page's embedded JS)

    But this is so great sollution, i was trying to find one really hard. Maybe you can add some keywords to article, these are the phrases I GOOGLEd up:
    jquery hide flash objects, jquery hide flash when overlaying, jquery overlay on top of flash, jquery remove flash, jquery remove FLASH object param embed (the last one led me to your site :D)

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Sorry about that. My code coloring plugin has a bad habit of slaughtering regular expressions. It should be fixed now.

      I've added a bunch of keywords to try and make it easier for people to find in Google, along with a direct link in the post to José's jquery version. It took me a long time to figure out this solution, so I want to save as many people as I can from that pain.

  • Brendan

    Testing this cool commenting feature.

  • http://intensedebate.com/people/joshfraser Josh Fraser

    My comments are a widget that you can get from IntenseDebate.com. I highly recommend it.

  • http://www.intensedebate.com/people/joshfraser Josh Fraser

    My comments are provided via a widget from IntenseDebate.com. I highly recommend it.

  • http://labs.kaliko.com Fredrik

    A simular take to solving the problem using jQuery:
    http://labs.kaliko.com/2009/11/change-wmode-with-

  • http://intensedebate.com/people/joshfraser Josh Fraser

    Beautiful. Thanks for sharing.

  • http://www.briancasel.com Brian

    Tried every code posted here… none seem to be working in IE8.

    I'm trying to fix embedded videos (vimeo and youtube) without manually adding wmode to the embed code.

    Can anyone provide a working demo?

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Is it giving you an error or failing silently? I don't have a computer w/ IE8 handy to check it out myself.

  • http://www.briancasel.com Brian

    Failing silently.

    However, the one that does work across all browsers for me is your original reference link:

    http://www.qindex.info/Q_get.php?g_clss=forum&amp

    • http://intensedebate.com/people/joshfraser Josh Fraser

      Very weird — especially since I borrowed so heavily from that example. I'll grab a PC later and take a look. Thanks for letting me know.

  • http://www.nobilesoft.com José Nobile

    I found the problem, is very rare, el code from vimeo using object + embed for show flash in IE, but in Firefox use object + embed, I dont understand very good, but it see in developers tools in IE and in Firebug in FF.

    The problem in firefox, is when I tried to execute the code for fix in IE, it to do regenerate the object, but without embed, obly params.

    if comment the part for Internet explorer, it working in FF and IE, pero only for vimeo videos embebeds.

    These "object" from code to embeed the swf in video is from type (object HTMLGENERICELEMENT) the normal object (with codebase and classid) is from type (object).

    The solution is detect the HTMLGENERICELEMENT and to end the funciton. I tried this.nodeType, this.nodeName, typeof this, but only a alert(this) show it.

    Now I'm working in this.

  • http://www.nobilesoft.com José Nobile

    Many fixes and patch applied to my code.

    Finally I searched a embed into the objects, if detected, it is cloned, after is changed (or added using setAttribute) wmode param to the clone, the clone is inserted after the original, and the original is deleted, the object parent of the embed was not alter, only the embed.

    El code was updated in http://www.nobilesoft.com/Scripts/fix_wmode2trans

    And a test (Vimeo video and div with position fixed) suggest by Brian is in:
    http://nobilesoft.com/Scripts/brian_test.html

    • Tânia B Nielsen

      You just saved my life and maybe my job. Thank you!

    • http://giuk.org sunsuron

      Hi Jose, I've tried your solution and found out that the line 'this.attributes' will not work on IE7.
      I think it 's IE7 fault and has nothing to do with your implementation. I would like to know the solution if any. Thanks.

      • http://www.nobilesoft.com José Nobile

        I tested in IE 7 and it worked.
        I checked in MSDN, and attributes property exits in all IE versions
        I checked in W3C and is part of DOM level 1

        Do you can give me what error appear in your IE 7?

        http://msdn.microsoft.com/en-us/library/ms537438(

        • http://giuk.org Charles

          Hi Jose, Sorry for the late reply. I've made a sample at http://www.tra.my/dev/
          You can take a look at the JS source codes of the page.
          By right, IE7 will echo some attributes. It doesn't echo in my IE7.

        • Tânia B Nielsen

          Just realized I have the same problem =/
          IE7 seems to think all the values to all the attributes of the object are null
          The flash just disappear
          Don't know what to do

    • Bernardo

      Hy, in Ie8 it's not working well. Any ideas?

  • frank

    nice.. just what i needed.. brilliant..

  • http://twitter.com/julienhidch @julienhidch

    thanks for this script it help me very much,…

    I just have a bug with IE 6 and 7,..

    so I implemented like this

    <!–[if !IE]>–>
    <script type="text/javascript" src="js/fix_wmode2transparent_swf.js"></script>
    <!–<![endif]–>

    it work for my overlay problem over a vimeo video

    Thank you

  • Nino

    Thanks for the great insight. Worked quite well…

  • Shlomo

    You're amazing.
    I spent days trying this in DOM, and was only successful with the embed tag (Firefox, etc) and not the object tags (Internet Explorer). Don't know why. You're way of just replacing the html works even for Internet Explorer.

    Thanks,
    Shlomo

  • nick lankester

    I also have played with all the scripts on this page..
    The code in the post that is from José Nobile (5 posts before this one) works on my page in Firefox but not in IE8…
    No change is registered to the embedded flash movie's wmode parameter…

    anyone got this to work in IE7/8?

    I can post a link to the page I'm working on if anyone wishes to explore why it isn't working.

    cheers

    • http://intensedebate.com/people/joshfraser Josh Fraser

      José Nobile has been quite responsive to bug reports. You may want to include him and see if he has any thoughts as well.

  • Dmitry Medvinsky

    I might be a bit late in here, but in the line 47 there should be

    new_object = new_object.replace…

    instead of

    new_object = html.replace…

    • http://intensedebate.com/people/joshfraser Josh Fraser

      you sure? it's been a while since i wrote this, but looking at it again, it doesn't look like new_object is defined as anything until after that line. i don't think you want to do a replace on an empty object.

      • Dmitry Medvinsky

        Line 47 is the line inside the for loop (for(j=0; j<children.length; j++) this one).

        new_object is definitely defined (sorry the the tautology) in the line 39 or 42, in the if/else block (at least one branch of it gets executed, since there is an else statement). :)

        So the assignment in the line 47 kills all the effort of adding [param name="wmode" value="opaque"] stuff in the object.

        • http://intensedebate.com/people/joshfraser Josh Fraser

          you're right. good catch. i was looking at the wrong line. i'll fix it now.

          • Dmitry Medvinsky

            Btw, thanks for the post. :)

          • http://intensedebate.com/people/joshfraser Josh Fraser

            sure. glad it was helpful. i've updated my post w/ your fix.

  • Lisa

    Thankyou, thankyou, thankyou. Been trying to fix this problem for the best part of the day. Plugged your script in and it works wonderfully.

  • bandcoach

    Strangely, leavingthe close object tag out create a similar problem in ie but not firefox or opera.

    As soon as I added the close object tag, this fixed it; no need for wmode to be set or anything else.

  • http://www.justeinecullen.com henry cullen

    excellent! thanks so much, that was driving me nuts!

  • jrt324

    it does't working in IE 6

  • http://twitter.com/matthewmceachen @matthewmceachen

    Woot! I found your solution an hour ago, and it's now a proud part of AdGrok's GrokBar… Thanks!

    • http://www.onlineaspect.com Josh Fraser

      Awesome! Always love to hear stories from people who use my code. Love what you're doing with AdGrok. We should chat about getting you set up with Torbit too. :)

  • http://bbc.co.uk robserious

    I have a menu that is being killed by an ad so need this fix, however, I don't know if rewriting the HTML may grab another ad ad or re-embed it and bugger up the impression counts etc, before I run with this, anyone had any experience?

  • krishna

    Thank you so much. You saved my day.

  • http://usabilidade.net Filipe Tavares

    With prototypeJS, I'd do:

    if ( Prototype.Browser.IE ) {
    $$('object').each(function(s) {
    if ( s.down('param[name="wmode"]') ) {
    s.down('param[name="wmode"]').writeAttribute('value', 'transparent');
    } else {
    var newObject = s.clone();
    s.childElements().each(function(j) {
    newObject.insert({bottom: j});
    });
    var newParam = new Element('param', { 'name': 'wmode', 'value': 'transparent' });
    newObject.insert({bottom: newParam});
    s.up().replaceChild(newObject, s);
    }
    });
    } else {
    $$('embed').each(function(s) {
    var newEmbed;
    newEmbed = s.clone();
    newEmbed.writeAttribute('wmode','transparent');
    s.up().replaceChild(newEmbed,s);
    });
    }

  • boiii

    Thanks for the excellent blog, saved my butt!!!