Periodically, someone tells me about the magic of PNG, how it's the ideal image format for the web, and that someday we'll all be using it on our sites instead of GIF. People have been saying this for years, and by now most of us have stopped listening. Sadly, flaky browser support has made PNG impractical for almost everything; but now, with a few simple workarounds, we can finally put one of its most compelling features to use.
The Portable Network Graphics, or PNG (pronounced “ping”), image format has been around since 1995, having cropped up during the now long-forgotten GIF scare, when Compuserve and Unisys announced they would begin charging royalties for the use of the GIF image format.
To provide GIF support in their applications, software makers like Adobe and Macromedia must pay royalty fees – fees which are passed down to the end user in the selling cost of the software.
When PNG appeared on the scene, web designers were ready to make the switch to the free, superior format and shun GIF forever. But over time, browsers continually failed to support PNG, and eventually most people started to forget about it. Today, nearly everyone still uses GIF habitually.
Which is a shame, because PNG makes GIF look pretty pathetic: it supports gamma correction, (sometimes) smaller file sizes, loss-less compression, up to 48-bit color, and, best of all, true alpha transparency.
To get why alpha transparency is a big deal, we must first understand one of the most annoying limitations of GIF.
When it comes to transparency, GIF doesn't cut it. Whereas PNG supports alpha transparency, GIF only supports binary transparency, which is a big limitation and has a couple of important implications.
For one, a GIF image can either use no transparent colors at all or have one color that's completely transparent – there are no degrees of transparency.
And if a complex GIF does contain a transparent color, the background color of the web page must match the transparent color, or else the anti-aliased area around the transparent color will be surrounded by ugly haloing and fringing. If you've spent more than five minutes as a web designer, you know what I'm talking about.
The result is that any anti-aliased transparent GIF is inextricably tied to the background color of the web page on which it lives. If you ever decide to change that color, you must also change the GIF.
Miraculously, PNG doesn't behave that way. A PNG can be transparent in varying degrees – in other words, it can be of variable opacity. And a transparent PNG is background-independent: it can live on any background color or image. Say you want your navigation on monkeys-run-amuck.com to be 65% opaque so you can see through it to your orangutan background image. You can do that. A transparent anti-aliased “Gorillas, Chimps, Gibbons, et al” title that can sit on top of any background color or image? You can do that, too.
By now, of course, we'd all be up to our ears in PNGs if browsers supported them reliably. But seven years after the format's inception, you still can't slap a PNG onto a web page like you can a GIF or JPG. It's disgraceful, but not as bad as it sounds.
It turns out that most of the latest versions of the major browsers fully support alpha transparency with PNG – namely, Netscape 6, Opera 6, and recently-released Mozilla 1, all on Windows; and, for the Mac, Internet Explorer 5, Netscape 6, Opera 5, Mozilla 1, OmniWeb 3.1, and ICab 1.9. Incredibly, PNG even works on Opera 6 for Linux, on WebTV, and on Sega Dreamcast.
IE5.5+/Win, bless its heart, will, in fact, display a PNG, but it doesn't natively support alpha transparency. In IE5.5+/Win, the transparent area of your PNG will display at 100% opacity – that is, it won't be transparent at all.
Bugger. So what do we do now?
AlphaImageLoader
FilterIE4+/Win supports a variety of non-standard, largely ridiculous visual filters that you can apply to any image's style. You can, for instance, fade in an image with a gradient wipe, or make it stretch from nothing to full size, or even make it swipe into place circularly, like a scene change in Star Wars.
A non-pointless gem among these is the AlphaImageLoader
filter, which is supported in IE5.5+/Win. When used to display a PNG, it allows for full alpha transparency support. All you have to do is this:
<DIV ID="myDiv" STYLE="position:relative; height:250px; width:250px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader<SPAN class=linewrap>»</SPAN> (src='myimage.png',sizingMethod='scale');"></DIV>
(Line wraps are marked ». –Ed.)
And you're in business. Perfect alpha transparency. This code works great, with only the small drawback that it's not part of any accepted web standard, and no other browser on the planet understands it.
So the trick is to determine the user's browser and serve up the images appropriately: if IE5.5+/Win, then we use AlphaImageLoader
; if a browser with native PNG support, then we display PNGs the normal way; if anything else, then we display alternate GIFs, because we can't be sure that a PNG will display correctly or at all.
Using a slightly tweaked version of Chris Nott's Browser Detect Lite, we set some global variables to this effect that we can use later on.
// if IE5.5+ on Win32, then display PNGs with AlphaImageLoader if ((browser.isIE55 || browser.isIE6up) && browser.isWin32) { var pngAlpha = true; // else, if the browser can display PNGs normally, then do that } else if ((browser.isGecko) |<span class="linewrap">»</span> | (browser.isIE5up && browser.isMac) |<span class="linewrap">»</span> | (browser.isOpera && browser.isWin <span class="linewrap">»</span> && browser.versionMajor >= 6) |<span class="linewrap">»</span> | (browser.isOpera && browser.isUnix <span class="linewrap">»</span> && browser.versionMajor >= 6) |<span class="linewrap">»</span> | (browser.isOpera && browser.isMac <span class="linewrap">»</span> && browser.versionMajor >= 5) |<span class="linewrap">»</span> | (browser.isOmniweb && <span class="linewrap">»</span> browser.versionMinor >= 3.1) |<span class="linewrap">»</span> | (browser.isIcab && <span class="linewrap">»</span> browser.versionMinor >= 1.9) |<span class="linewrap">»</span> | (browser.isWebtv) |<span class="linewrap">»</span> | (browser.isDreamcast)) { var pngNormal = true; }
(Note for the faint of heart: complete source code for all the examples we cover is available at the end of the article.)
The simplest, most reliable way to spit out PNGs is using inline document.writes based on the above detection. So we use a function like this:
function od_displayImage(strId, strPath, intWidth, <span class="linewrap">»</span> intHeight, strClass, strAlt) { if (pngAlpha) { document.write('<div style="height:'+intHeight+'px;<SPAN class=linewrap>»</SPAN> width:'+intWidth+'px;<SPAN class=linewrap>»</SPAN> filter:progid:DXImageTransform.Microsoft.AlphaImageLoader<SPAN class=linewrap>»</SPAN> (src=\''+strPath+'.png\', sizingMethod=\'scale\')" <SPAN class=linewrap>»</SPAN> id="'+strId+'" class="'+strClass+'"></div>'); } else if (pngNormal) { document.write('<img src="'+strPath+'.png" <SPAN class=linewrap>»</SPAN> width="'+intWidth+'"<SPAN class=linewrap>»</SPAN> height="'+intHeight+'" name="'+strId+'" <SPAN class=linewrap>»</SPAN> border="0" class="'+strClass+'" alt="'+strAlt+'" />'); } else { document.write('<img src="'+strPath+'.gif" <SPAN class=linewrap>»</SPAN> width="'+intWidth+'"<SPAN class=linewrap>»</SPAN> height="'+intHeight+'" name="'+strId+'" <SPAN class=linewrap>»</SPAN> border="0" class="'+strClass+'" alt="'+strAlt+'" />'); } }
Now we can call the od_displayImage function from anywhere on the page. Any JavaScript-capable browser will display an image, and, if we want to be really careful, we can accompany each call with a
It's a time-tested method, but what if we want more control over our PNGs?
When I told the programmer in the office next door that I was writing this article, he took one look at my code, glowered at me, and said, “Fool. Where's the abstraction? You need to use objects.”
So now we have a JavaScript object to display PNGs. Here's how we use it:
<html><head> <script language="javascript" src="browserdetect_lite.js" type="text/javascript"> </script> <script language="javascript" src="opacity.js" type="text/javascript"></script> <script type="text/javascript"> var objMyImg = null; function init() { objMyImg = new OpacityObject('myimg','/images/myimage'); objMyImg.setBackground(); } </script> <style type="text/css"> #myimg { background: url('back.png') repeat; position:absolute; left: 10px; top: 10px; width: 200px; height: 200px; } </style> </head> <body onload="init()" background="back.jpg"> <div id="myimg"></div> </body> </html>
That's it. The cool thing about the OpacityObject is that we just pass it a DIV ID and an image path and we're done. Using the appropriate technique, it applies the image as a background of the DIV, and from there we can do whatever we want with it. Fill it with text, move it across the screen, resize it dynamically, whatever – just like any other DIV.
The object works in any CSS 1-capable browser that can dynamically apply a background image to a DIV with JavaScript. It's completely flexible, and we could even use it in place of the above function.
The trade-off is that it doesn't degrade as nicely. Netscape 4.7/Win/Mac and Opera 5/Mac, for instance, won't display an image at all. And it has another significant problem, which is this:
IE5/Mac only supports alpha transparency when the PNG resides in an <img>
tag, not when it's set as the background property of a DIV. So PNGs displayed with the OpacityObject will appear 100% opaque in IE5/Mac. This problem is especially frustrating because IE5/Mac is the only browser which natively supports PNG and behaves this way. We've notified Microsoft about this apparent bug and hope for it to be fixed in an upcoming release.
But for now, these issues are the trade-off for flexibility. Obviously, choose the right tactic based on the particular needs of your project. Between them both, you can do pretty much anything with PNGs – like, for instance...
In this simple example, we see how the same 80% opaque PNG can be displayed on any kind of background: Translucent Image on a Photo.
What a beautiful thing it would be, I'm sure you've thought from time to time, to create translucent anti-aliased images that work on any background. Well, check it out: Anti-Aliased Translucent Navigation with Rollovers.
Mouse over the images, observe the behavior of the rollovers, and click “change background” to see how the images behave on different backgrounds. Then view the source. There are a few things worth noting here:
strExt
이라는 변수를 만듭니다. PNG와 대체 GIF가 파일 확장자를 제외하고 동일한 이름을 사용하는 한, 브라우저는 실제로 사용할 이미지만 미리 로드합니다.
pngLink
이라는 클래스를 만들고 커서 속성을 "포인터"로 설정합니다. 함수를 호출할 때 해당 클래스 이름을 함수에 전달하고 함수는 해당 클래스를 PNG에 적용합니다. 결과적으로 사용자가 이미지 링크 위로 마우스를 가져가면 사용자의 포인터가 커서로 바뀌게 됩니다. 하지만 IE5.5+/Win에서는 실제로는 DIV일 뿐입니다. (이미지 사용 방법에 따라 PNG 클래스에 "display:block"
또는 "display:inline"
을 추가하여 Netscape 6에서 올바르게 표시되도록 할 수도 있습니다. (자세한 내용은 Better Living Through XHTML을 참조하세요. .)
AlphaImageLoader
를 사용하여 PNG를 동적으로 교체하는 것이 가능하지만 IE5.5+/Win에서는 힘든 시간을 보내는 것으로 나타났습니다. 효과적인 롤오버를 하기에는 너무 느리고 너무 느립니다. 더 나은 방법은 PNG가 포함된 DIV에 배경색을 적용하는 것입니다. 색상은 이미지의 투명한 부분을 통해 빛나고 빠르게 적용됩니다. 함수를 호출할 때 표시할 이미지 이름과 HTML 색상을 함께 보냅니다. IE5.5+/Win은 색상을 표시하고 다른 것들은 이미지를 표시합니다.
처음 두 예에서는 전술 1의 Quick-and-Dirty 기능을 사용했습니다. 이제 PNG가 페이지의 다른 코드와 상호 작용하기를 원하므로 이번에는 OpacityObject를 사용하여 표시합니다.
그러나 기억하세요. 이 접근 방식에는 단점이 있습니다(위 참조). 그 중 가장 가슴 아픈 점은 이 예가 IE5/Mac에서 완벽하게 작동하지 않는다는 것입니다. 그것이 고통을 야기한다면, 항상 빠르고 더러운 기능이 있습니다. 그렇지 않으면 계속 읽어보세요.
먼저 DIV를 생성하고 ID를 부여한 후 높이, 너비, 글꼴 모음 등 원하는 스타일 속성을 할당합니다.
그런 다음 OpacityObject를 인스턴스화할 때 해당 DIV의 ID를 전달합니다. 이미지 경로도 전달하면 이제 반투명 배경의 DIV가 생성됩니다. 멋지네요!
다음으로 DIV에 일부 HTML 텍스트를 넣고 여기에 관련되지 않은 또 다른 개체 메서드를 적용합니다(이 개체는 OpacityObject와 아무 관련이 없습니다. 주변에 있는 코드일 수 있습니다). 이제 반투명 DIV를 화면 주위로 이동할 수 있습니다. 휘! 내부에 HTML 텍스트가 포함된 플로팅 반투명 DIV.
OpacityObject를 사용하여 가능한 작업을 간략하게 살펴보겠습니다. 하드코어 CSS/DOM 사용자 여러분, 미쳐가세요.
우리가 다룬 객체, 함수, 예제의 소스 코드를 다운로드하세요. 모든 코드는 포함된 Browser Detect Lite의 조정된 버전에 의존합니다. 가변 불투명도 소스 코드.
이 모든 것이 매우 흥미롭지만 웹 개발자를 흥분하게 만드는 많은 성과와 마찬가지로 오늘날의 브라우저에서 PNG를 작동시키는 것도 이렇게 어렵지는 않습니다. Internet Explorer에서 완전한 PNG 지원을 제공하도록 Microsoft를 설득하기 위해 청원에 서명하는 것을 고려해 보세요. 운이 좋으면 이 기사는 곧 쓸모 없게 될 것입니다.
그동안 이 기사의 토론 포럼에 이 코드 개선을 위한 아이디어를 게시해 주세요. 예를 들어 PNG 홈 사이트에서는 알파 투명성을 지원해야 하지만 아직 확인되지 않은 몇 가지 다른 모호한 브라우저에 대해 이야기합니다. 이러한 주장을 확인할 수 있거나 다른 귀중한 의견이 있는 경우 알려주시면 그에 따라 코드를 업데이트하겠습니다.
AlphaImageLoader
MSDN의 필터 페이지
<img>