HOME - ABOUT

Archive for September, 2007

Handling “z-index” Bugs in IE6

Friday, September 21st, 2007

After some thorough research (i.e. a few Google searches), I hadn’t come up with a fully satisfactory explanation of why IE6 mishandled the z-index attribute. So, here’s a concise survival guide if you intend to use this attribute in IE6.

First, let’s revisit the intended properties of z-index:

  • It applies to positioned elements only.
  • Only when a z-index integer value is specified should a new stacking context be generated.
  • A z-index of “auto” should not generate a new stacking context. It should be the same as its parent.
  • An element with no z-index specified has a default value of auto.

Well, of course IE6 violates the CSS specification and starts handing out z-index values willy-nilly, even when it’s not assigned. Let’s see some examples:

#redbox {
border:1px solid black;
background:red;
width:100px;
height:100px;
position:relative;
top:0px;
left:50px;
z-index:1;
}
#bluebox {
border:1px solid black;
color:white;
background:blue;
width:100px;
height:100px;
position:relative;
top:-50px;
left:100px;
z-index:2;
}
This element has a z-index of 1! So, it should be on BOTTOM.
This element has a z-index of 2! So, it should be on TOP.

So far, so good! Of course, there’s not a lot here to screw up, as it’s all pretty explicit. Now, I will blow things up by adding a parent element to #bluebox:

#parent {
position:relative;
}
This element has a z-index of 1! So, it should be on BOTTOM.
This element has a z-index of 2! So, it should be on TOP.

Well, exactly what wasn’t supposed to happen did. According to CSS specs, nothing should have changed here. Instead, IE6 seems to generate a new stacking context for #bluebox based on its parent, despite the fact that the parent doesn’t even have a z-index specified. Well, what happens if we do specify one?

#parent {
position:relative;
z-index:1;
}
This element has a z-index of 1! So, it should be on BOTTOM.
This element has a z-index of 2! So, it should be on TOP.

Oh, so now we’re okay. But, what if the z-index of the parent element is less than that of #redbox? Let’s make #parent’s z-index 2 and #redbox’s 3. According to CSS, this should establish a local stacking context where the stack level is ‘0′.

This element has a z-index of 3! So, it should be on TOP.
This element’s parent has a z-index of 2! So, it should be on BOTTOM.

Phew; it works. I guess that means that if we set the parent z-index to 4, #bluebox will jump to the top again.

This element has a z-index of 3! So, it should be on BOTTOM.
This element’s parent has a z-index of 4! So, it should be on TOP.

From this, we can deduct that IE6’s main fault is the ill-advised assignment of child z-index values when CSS specifically states that parent elements with no z-index value should not influence the stacking contexts of its children.

So, to be safe, make sure to set a z-index for all your positioned containers to avoid this bug. Or, when possible, simply eliminate the positioning of your parent containers:

#parent {
}
This element has a z-index of 1! So, it should be on BOTTOM.
This element’s z-index is 2. It’s parent is not positioned. It should be on TOP.

jQuery, AJAX and Redundant Event Handlers

Monday, September 10th, 2007

It didn’t take me long to realize that jQuery’s AJAX functions don’t trigger the $(document).ready() event. But then, it wouldn’t really make any sense if they did. Naturally, this event fires just once and naturally, AJAX leaves it alone. Therefore, it becomes necessary to supply event handlers to the AJAX callback functions, even if it means duplicating handlers in the DOM.

In my scenario, I had a styled table using the tablesorter plugin (id #tablesort).

Initial code sample:

$(document).ready(function() {
 $("#tablesort").tablesorter({
 	widgets:['zebra'],
 	sortInitialOrder: 'asc'
      });
 $("#tablesort tr").hover(function(){
 	$(this).addClass("over");
 		 },function(){
 	$(this).removeClass("over");
 });
 $("#tablesort tbody").hover(function() {
 	$(this).css({overflow-y: "auto"});
 }, function() {
 	$(this).css({overflow-y: "hidden"});
 });
});

With the inclusion of the AJAX function, each record in the data table would contain a link to generate further detail in a new table, for which I also wanted to apply the tablesorter styles (another id #tablesort.) This looked something like:

 	$("input.more").click(function() {
		$("#ajax_div").html("Retrieving data...");
 		 $.post("./include/ajax_table.php", {sql: $(this).val() },  function(data){
     				$("#ajax_div").html(data);
   		});
   	});

While this is enough to generate and display a second #tablesort, the new table lacks the same styles that jQuery applied to the first #tablesort on $(document).ready(). So, my first instinct was to simply copy & paste the event handlers into my jQuery callback function, like so:

 		$("input.more").click(function() {
 			$("#ajax_div").html("Retrieving data...");
 		 	$.post("./include/ajax_table.php", {sql: $(this).val() },  function(data){
     					$("#ajax_div").html(data);
 					$("#ajax_div tablesort").tablesorter({
 						widgets:['zebra'],
 						sortInitialOrder: 'asc'
 					     });
 					$("#ajax_div tablesort tr").hover(function(){
 						$(this).addClass("over");
 							 },function(){
 						$(this).removeClass("over");
 					});
 					$("#ajax_div tablesort tbody").hover(function() {
 						$(this).css({overflow-y: "auto"});
 					}, function() {
 						$(this).css({overflow-y: "hidden"});
 					});
			 });
		});

Now, I had what I wanted — two #tablesort tables with identical styles. However, I also had a bunch of redundant and messy code at the top of my page. To fix this, I simply stored a function in an external file to handle the styling of all my #tablesort tables. Utilizing the find() function, this was even easier to do:

function tablesortStyles(jthis) {
	jthis.find("#tablesort").tablesorter({
		widgets:['zebra'],
		sortInitialOrder: 'asc'
	     });
	jthis.find("#tablesort tr").hover(function(){
		$(this).addClass("over");
			 },function(){
		$(this).removeClass("over");
	});
	jthis.find("#tablesort tbody").hover(function() {
		$(this).css({overflow-y: "auto"});
	}, function() {
		$(this).css({overflow-y: "hidden"});
	});

	return true;
}

Now, I only needed to use two lines in my source file to style my tables:

$(document).ready(function() {
		tablesortStyles($(document));

		$("input.more").click(function() {
                   $("#ajax_div").html("Retrieving data...");
			 $.post("./include/ajax_table.php", {sql: $(this).val() },  function(data){
     					$("#ajax_div").html(data);
					tablesortStyles($("#ajax_div"));
   			 });
   		}); 

	});

ASP.Net - Error: Newline in constant

Friday, September 7th, 2007

Here’s a tip from a few years ago. I was working in C# on an ASP.Net application and needed to run some Javascript code from the server side. That’s when I ran into the error.

I was trying to run something similar to the following code…
(more…)