Inloggen
 
 
 
 
    
PNG-Fix with and without Javascript
Location: BlogsFerry Onderwater - Developer    
Posted by: Ferry Onderwater 5-8-2006 23:00
In this blog-entry I tell you about the problems with PNG in IE (versions prior to 7), the solutions, problems with the solution and ofcourse the way wé got rid of the problems. You will find the javascript solutions, css-solutions and an example to override a property in a VB.NET control so the PNG's will be fixed automatically.
The situation
We are developing a web-based application. Since we are developers and definitely not designers we hired someone to 'do' the user-interface. They came up with a beautiful interface and delivered lots of graphics, most of them PNG. But wait, in IE it looked like sh*t!!!

The first solution
So this was our first encounter with the PNG/IE problem. Fortunately there are lots of websites about this particular problem and javascripts are available to 'correct' the IE behavior. A very good one is http://homepage.ntlworld.com/bobosola/. I found no script which covered all of my problems so I gathered some of them, mixed them up and had our own solition. It covers three places where PNG's are used in the app:

- images,
- background images and
- inputs (type = image, i.e. buttons).

This is the script which we used:

Code:
/*

Correctly handle PNG transparency in Win IE 5.5 & 6.
http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.

Use in with DEFER keyword wrapped in conditional comments:


*/

if (document.body.filters && fixPng() == "True")
{
    // First we do the images ('img')
    for(var i=0; i    {
      var img = document.images[i]
      var imgName = img.src.toUpperCase()
      if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
      {
         var imgID = (img.id) ? "id='" + img.id + "' " : ""
         var imgClass = (img.className) ? "class='" + img.className + "' " : ""
         var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
         var imgStyle = "display:inline-block;" + img.style.cssText
         if (img.align == "left") imgStyle = "float:left;" + imgStyle
         if (img.align == "right") imgStyle = "float:right;" + imgStyle
         if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
         var strNewHTML = "         + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
         + "(src=\'" + img.src + "\', sizingMethod='image');\">
"
         img.outerHTML = strNewHTML
         i = i-1
      }
    }

    // Next do the background-images
    for (i=0; i        var bg = document.all[i].currentStyle.backgroundImage;
        if (bg){
            if (bg.match(/\.png/i) != null){
                var mypng = bg.substring(5,bg.length-2);
                document.all[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+mypng+"', sizingMethod='scale')";
                document.all[i].style.backgroundImage = "url('/images/1pixel.gif')";
            }
        }
    }

    // Finally do the input with type = image
    elements = document.getElementsByTagName("input");
    for (i = 0; i < elements.length; i++) {
        var input = elements[i];
        if (input.getAttribute("type") != "image") continue;
        if (input.getAttribute("src").toLowerCase().search(/\.png$/) < 0)
          continue;
        input.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + input.src  + "', sizingMethod='image')";
        input.src = "images/spacer.gif";
    }
}

function fixPng()
{
    var nameEQ = "FixPng=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++)
    {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return "True";
}

You can see the original source of the first part of script (images) mentioned and the way to use it. The background-images was taken from another example on the net and the input was our own creation (ofcourse based on the two pieces of code we downloaded).

Problems (again)
The first problem with this solution was the speed, it made the load of a page sooooo slooooooow. So very soon we created the possibility in the application to disable the pngfix. This explains the last piece of code in the script (fixPng). We simply used a cookie to store whether we want to use the fix or not.
Ofcourse this wasn't a very good solution. Yes, it was very fast, but the looks where, well, a bit disappointing (understatement).

Then we discovered a second problem. Tooltips were not shown where the were defined for sure. When disableing the pngfix, voila, there they were Smile

Then a third problem arrised. We make use of an online HTML-editor to maintain some content. And we make havily use of javascript to add functionality. In this case javascript is used to set a 'dirty' state to the page. So when data is entered or changed in the editor and the user wants to navigate to another page or close the browser they get a warning 'There is unsaved data, are you sure you want to leave the page'. The pngfix was for some reason responsible for inaccurate results of this functionality.

Some of these problems could be solved, I'm sure. But I choose to try to get rid of the javascript by including a 'PNG-Fix' in the source-code so a part of it would be resolved server-side.

The next solution
I ended up with three different solutions. They are very sufficient for us but I don't have the illusion they are complete. However, maybe they help you or can be one of the sources of information for developing your own solution.

GIF
The images I simply replaced by GIF's. They are not as pretty but in our case it was pretty enough. Let's say the gain of speed was very very much higher than the loss of 'prettyness'.

CSS
But we make use of 'tabs'. Tabs have different colors and there we felt the PNG were needed. They are used as background-images and make very much use of css.
So instead of:

Code:
.FirstPaneLeftTop {background-image: url(graphics/tab_grey_lefttop.png);}

we used:

Code:
.FirstPaneLeftTop {background-image: url(graphics/spacer.gif);filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='graphics/tab_grey_lefttop.png', sizingMethod='scale');}

The only thing left to do is to make sure when IE7 is used the png will be shown without any filter.

Buttons
In our app we make very much use of imagebuttons. We created our own wImageButton which inherits from ImageButton. And this wImageButton is used on its own but also as part of lots of other controls.
What needed to be done for the images on this button was to add the filter with the PNG to the style of the button and to replace the imageurl with a url to spacer.gif.
So the solution was to walk through the code and make all those changes.
But wait, can't this be done in an easier way so I don't have to change code in lots of places but just once?

Ofcourse this is possible!
The one thing allways in common is we set the ImageURL property of the (w)ImageButton to the PNG. So what needs to be done is to check the filename when this property is set. When ít's a PNG, change the ImageURL to the spacer.gif and add the 'filter' key to the style with as value the AlphaImageLoader filter with the original PNG-name.
How does this look in VB.NET?

Code:
Public Class wImageButton
      Inherits ImageButton

      Private df As New DataFunctions

      Public Overrides Property ImageUrl() As String
          Get
              Return MyBase.ImageUrl
          End Get
          Set(ByVal value As String)
                  ' Create a 'shortcut' to the Browser-information
                  With HttpContext.Current.Request.Browser
                          ' Change only when it is a PNG and when that is true the browser is IE with a version prior to 7
                    If value.ToUpper.IndexOf(".PNG") > -1 AndAlso .Browser = "IE" And .MajorVersion < 7 Then
                            'Change the URL
                        MyBase.ImageUrl = "/images/spacer.gif"
                        'And add the filter to the style
                        MyBase.Style.Add("filter", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + value + "', sizingMethod='image');")
                    Else
                            'Maintain the original given URL
                        MyBase.ImageUrl = value
                    End If
                End With
          End Set
      End Property

End Class

From now on, when the ImageURL of a (in our case) wImageButton is set everything will work out ok. If it's a GIF? Perfect, it will be shown unchanged. Are we working with Firefox? Good, our GIF's ánd PNG's will be shown unchanged. Is it a PNG ánd are we working with IE6? From now on perfect as well! GIF's are shown unchanged and PNG's will be shown automatically correct!

Conclusion
We managed to create a workable solution for the PNG problem. The speedproblem is 'solved'. There is no JavaScript which will loop three times through all elements on my page and change the DOM when needed. So there is a gain in actual speed (no loops) ánd we get the page presented correctly rendered at once and not a rendered page which is changed clientside (which is a process the user is very much able to see since colors change and the positioning of controls change!). The latter is also a big psychological speed gain!

The tooltip problem can only be solved (at least as far as I discovered) by NOT using the filter. And that means changing to GIF on places the tooltip is wanted.

The javascript errors are gone. Since we don't need the pngfix-script anymore there was no reason to look for the cause of the error in other scripts when using pngfix.

I hope you can use this information in your own application! If you have any remarks, additions, corrections or compliments Wink, feel free!

Happy programming!

Ferry
Copyright ©2006 Ferry Onderwater
Permalink |  Trackback
  
 
Weblogs
    
Archief
    
Zoeken
    
 
 
 
 
Copyright 2006-2009 by Arcencus
Privacy Statement | Terms Of Use