views:

552

answers:

5

I was working on a JavaScript dialog with a transparent background overlay when I ran into a problem on large pages.

If the page was large, the transparent overlay would be a solid colour (i.e. no longer transparent). I did some testing and found this only happened in the overlay was greater than 4096 pixels high (hmmm, suspicious, that's 2^12).

Can anyone verify this issue? Have you seen a work-around?

Here's my test code (I'm using Prototype):

<style>
.overlayA { 
    position:absolute;
    z-index:10;
    width:100%;
    height:4095px;
    top:0px;
    left:0px;
    zoom: 1;
    background-color:#000;
    filter:alpha(opacity=10);
    -moz-opacity:0.1;
    opacity:0.1;
}

.overlayB { 
    position:absolute;
    z-index:10;
    width:100%;
    height:4097px;
    top:0px;
    left:0px;
    zoom: 1;
    background-color:#000;
    filter:alpha(opacity=10);
    -moz-opacity:0.1;
    opacity:0.1;
}
</style>
<div style="width:550px;height:5000px;border:1px solid #808080">
    <a href="javascript:// show overlay A" onclick="Element.show('overlayA')">Display A = 4096h</a>
    <br /><a href="javascript:// show overlay B" onclick="Element.show('overlayB')">Display B = 4097h</a>
</div>
<div id="overlayA" onclick="Element.hide(this)" class="overlayA" style="display:none"></div>
<div id="overlayB" onclick="Element.hide(this)" class="overlayB" style="display:none"></div>
+2  A: 

How about making the overlay the size of the window instead of the size of the page, and moving it up or down on scroll.

wheresrhys
The is a possibility but I am worried about lag, especially on pgup/pgdown. I did find a simpler solution - use multiple overlay DIVs, each taking a fraction of the screen that is less than 4906px high.
Diodeus
+1  A: 

You are operating at the edge already (that's huge...) so I don't know that MS would classify it as a bug or 'fix' it even if it was.

You might need to break it up into smaller overlay DIVs.

Adam Davis
Yeah, I ended up using multiple DIVs and sizing/positioning them based on page size.
Diodeus
A: 

Why wouldn't you postion the overlay fixed?
That way it wouldn't have to be as big as the whole page content.

Simply doing:

 #Overlay{
  position:fixed;
  left:0px;
  top:0px;
  height:100%;
  width:100%;
  rest of declarations
 }

Just make sure it's parent is the document and the document has a width and height of 100%. That way you should be good with a much smaller overlay.

THe posotion:fixed will make sure the overlay is positioned relative to the viewport. Thus its always displayed in the top left corner.

Pim Jager
+7  A: 

Since you have an opacity filter on the CSS I believe you are indirectly using DirectShow under the covers for alpha blending and image composition. DirectShow uses DirectX textures, which have a 4096x4096 pixel limit for DX9, which would explain this erratic behavior.

codekaizen
Very insightful. Now I know why the issue is deeper than HTML/CSS.
Diodeus
Awesome explanation! Thanks!
Adam Davis
Oh, of course. I need to know how DirectX works to use CSS opacity filters. Makes total sense. Thanks IE!
Anutron
Ah, of course, all other browsers are completely free of leaky abstractions! Just how do the magical Firefox, Chrome and Safari do it?
codekaizen
A: 

The position:fixed solution is a spotty solution..It is not well supported in IE.

The best thing is to automatically create and append additional transparent elements (with a max height of 2048px to cover XP DX8 which has this issue as well).

Here's the code I used, assuming you already have a floating div solution.

 if(document.getElementById('document_body').scrollHeight > 2048)
 {
  document.getElementById('float_bg').style.height = "2048px";
  document.getElementById('float_bg').style.zIndex = -1;
  count=1;
  total_height=2048;
  while(total_height < document.getElementById('document_body').scrollHeight)
  {
   clone = document.getElementById('float_bg').cloneNode(true);
   clone.id = 'float_bg_'+count;
   clone.style.zIndex = -1;
   //clone.style.backgroundColor='red';
   clone.style.top = (count*2048)+"px";
   document.getElementById('float_el').insertBefore(clone,document.getElementById('float_bg'));
   count++;    

   this_add = 2048;
   if((total_height + 2048) > document.body.scrollHeight)
   {
    clone.style.height = (document.body.scrollHeight - total_height);
   }
   total_height += this_add;
  }
 }
 else
 {
   document.getElementById('float_bg').style.height = document.body.scrollHeight + "px";
 }