Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

jQuery 1.4 Opacity and IE Filters


:P
On this page:

Ran into a small problem today with my client side jQuery library after switching to jQuery 1.4. I ran into a problem with a shadow plugin that I use to provide drop shadows for absolute elements – for Mozilla WebKit browsers the –moz-box-shadow and –webkit-box-shadow CSS attributes are used but for IE a manual element is created to provide the shadow that underlays the original element along with a blur filter to provide the fuzziness in the shadow. Some of the key pieces are:

var vis = el.is(":visible");
if (!vis)
    el.show();  // must be visible to get .position

var pos = el.position();
if (typeof shEl.style.filter == "string")
    sh.css("filter", 'progid:DXImageTransform.Microsoft.Blur(makeShadow=true, pixelradius=3, shadowOpacity=' + opt.opacity.toString() + ')');

sh.show()
  .css({ position: "absolute",
      width: el.outerWidth(),
      height: el.outerHeight(),
      opacity: opt.opacity,
      background: opt.color,
      left: pos.left + opt.offset,
      top: pos.top + opt.offset
  });

This has always worked in previous versions of jQuery, but with 1.4 the original filter no longer works. It appears that applying the opacity after the original filter wipes out the original filter. IOW, the opacity filter is not applied incrementally, but absolutely which is a real bummer.

Luckily the workaround is relatively easy by just switching the order in which the opacity and filter are applied. If I apply the blur after the opacity I get my correct behavior back with both opacity:

sh.show()
  .css({ position: "absolute",
      width: el.outerWidth(),
      height: el.outerHeight(),
      opacity: opt.opacity,
      background: opt.color,
      left: pos.left + opt.offset,
      top: pos.top + opt.offset
  });

  if (typeof shEl.style.filter == "string")
      sh.css("filter", 'progid:DXImageTransform.Microsoft.Blur(makeShadow=true, pixelradius=3, shadowOpacity=' + opt.opacity.toString() + ')');

While this works this still causes problems in other areas where opacity is implicitly set in code such as for fade operations or in the case of my shadow component the style/property watcher that keeps the shadow and main object linked. Both of these may set the opacity explicitly and that is still broken as it will effectively kill the blur filter.

This seems like a really strange design decision by the jQuery team, since clearly the jquery css function does the right thing for setting filters. Internally however, the opacity setting doesn’t use .css instead hardcoding the filter which given jQuery’s usual flexibility and smart code seems really inappropriate.

The following is from jQuery.js 1.4:

var style = elem.style || elem, set = value !== undefined;

// IE uses filters for opacity
if ( !jQuery.support.opacity && name === "opacity" ) {
    if ( set ) {
        // IE has trouble with opacity if it does not have layout
        // Force it by setting the zoom level
        style.zoom = 1;

        // Set the alpha filter to set the opacity
        var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
        var filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";
        style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
    }

    return style.filter && style.filter.indexOf("opacity=") >= 0 ?
        (parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":
        "";
}

You can see here that the style is explicitly set in code rather than relying on $.css() to assign the value resulting in the old filter getting wiped out.

jQuery 1.32 looks a little different:

// IE uses filters for opacity
if ( !jQuery.support.opacity && name == "opacity" ) {
    if ( set ) {
        // IE has trouble with opacity if it does not have layout
        // Force it by setting the zoom level
        elem.zoom = 1;

        // Set the alpha filter to set the opacity
        elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
            (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
    }

    return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
        (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
        "";
}

Offhand I’m not sure why the latter works better since it too is assigning the filter. However, when checking with the IE script debugger I can see that there are actually a couple of filter tags assigned when using jQuery 1.32 but only one when I use jQuery 1.4.

Note also that the jQuery 1.3 compatibility plugin for jQUery 1.4 doesn’t address this issue either.

Resources

Posted in jQuery  

The Voices of Reason


 

AdamS
January 25, 2010

# re: jQuery 1.4 Opacity and IE Filters

Nice shadow plugin. I noticed on the makeAbsolute method, your doing:

el.remove.appendTo("body")


The elements that have events attached were being removed (as they should with this method). I changed it to:

el.detach.appendTo("body")


and this worked with no problems.

thorn
January 26, 2010

# re: jQuery 1.4 Opacity and IE Filters

Have you filled in a bug report?

Jamin
January 27, 2010

# re: jQuery 1.4 Opacity and IE Filters

I see you got 1.4.1 in your latest build (which I will check out soon as I have some spare hours) and wondering if that makes a difference in what you're seeing here.

There is another change between JQuery 1.3.2 and 1.4 that impacted our app. And since it's really your toolkit that determines which JQuery we use this all ties together. 1.3.2 prefers the XMLHttp ActiveX object over the XMLHttpRequest method in IE7. 1.4 reverses that and tries XMLHttpRequest first. Many of our clients use IE7 (and a few still use IE6). When we started testing with west wind toolkit 1.12 and subsequently JQuery 1.3.2 a few installations started throwing these ActiveX warnings. I chased it down to Jquery and IE7. In some of these cases IE is embedded inside another app and IE settings cannot be easily changed. Simply using JQuery 1.4(.1) seems to resolve the issue (very nice timing for us). Probably not too many folks that have to deal with this, but just another fun thing I've run into.

PS - We're headed back your way on Feb 25.

ASP.NET jQuery
March 22, 2010

# re: jQuery 1.4 Opacity and IE Filters

Thanks a lot for your research. I've book marked this and will return to it when I eventually move to jQuery 1.4.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024