If you’ve ever found yourself debugging multiple elements stacked with z-index, and wish you could visualize their boundaries and stack positions without trying to remember numbers, this one is for you.
The picture on the right pretty much sums it up. “Visualize Stack” as I call it applies different shades of a color to elements based on their z-index value, relative to the z-index of other elements. This is particularly useful for developers who are stacking multiple elements on top of each other and would like to visually see their layering. For the time being, this plugin only works on browsers that support CSS3 hsl() coloring. Sorry, IE.
- View an example
- Get the code and follow this project on GitHub
- Get the bookmarklet
Usage
Call the visualizeStack() method on a jQuery object. The plugin will internally filter and only apply logic to the elements with a positive or negative numerical z-index. Example:
$(function(){ // the logic will only apply to div and p elements in this example. // use $("*") for all elements. $("div, p").visualizeStack({ // CSS rules to apply. the percent sign (%) is replaced with // the appropriate color shade. properties: { background: "%", border: "1px solid black" }, // the base color of the gradients. Enter one of the following // colors, or a hue number for hsl(). accepted color names: // red, purple, blue, turquoise, green, orange, and yellow. color: "red", // a hex color to apply to very lightly/darkly shaded elements. // the "color" property of these // elements will be set to this value. pass an empty string // to disable. lightTextColor: "#fff", darkTextColor: "#000" }); });
The Bookmarket
If you’re like me, you’re probably too lazy to come to this website, download the JS file, include it, and write the selector/plugin call just to debug some simple CSS stack issues. By the time you’ve done all that it’s likely you could have figured the problem out on your own. Therefore, I packaged this code up in a little bookmarklet so you can instantly apply plugin.
A couple caveats first: 1) you must already have jQuery included in the website, and 2) it isn’t configurable unless you change the bookmarklet code yourself. All elements are selected (using $(“*”)) and the default options are automatically applied (the background property changes to shades of red).
To use, drag this link into your bookmarks toolbar: Visualize Stack
I suggest giving this thing a run on Digg.com; it’s pretty interesting to see what they have going over there for z-index’d elements.
About hsl() Coloring
This plugin dynamically generates a shade of a color with CSS3′s hsl(h,s,l), or hue, saturation, and lightness syntax. One of the many advantages of hsl() over rgb() for this type of application is that you can begin with a hue color – say 90 for red – and essentially guess a different shade of that color by tweaking the lightness. As such, providing an API where you can either pass in a number of a starting hue, or the name of a color, was trivial. The color name and associated hue number map looks like this:
$.fn.visualizeStack.colors = { red: 360, purple: 300, blue: 240, turquoise: 180, green: 120, orange: 35, yellow: 60 };
Unfortunately, support for hsl() is limited to Firefox 3, Google Chrome, Opera 9+, and Safari 3+. IE doesn’t get to play yet, but I believe we’ll be seeing it in IE 9. Also, if you’re into hsl(), check out hsla() on the CSS3 color spec which adds support for alpha transparency as well.
Walking Through The Code
The code for this is not terribly complicated. First, we’ll create a plugin called “visualizeStack” and add it the the $.fn namespace so that it can be called on a jQuery object of elements. We’ll allow an options parameter to be passed in, and then override the default options with the passed in options. This defaults object will be defined later towards the end of the file.
(function($){ $.fn.visualizeStack = function(options){ options = $.extend({}, $.fn.visualizeStack.defaults, options);
The next section involves filtering out only elements that have a numerical z-index, and saving a reference to each element it’s z-index value in an sorted array. I’ve commented heavily here, so hopefully it explains itself:
// We only want to keep elements that have a legitimate z-index. // If this plugin is called like $("div").visualizeStack(), for // example, not all divs in that selection could have a set z-index. // // Because the default z-index property value is "auto" we can // safely assume a z-index was set if the value is numeric var elems = this.filter(function(){ return /^-?\d+$/.test( $(this).css("z-index") ); }) // Take those filtered elements and return an array of objects. The // "element" key will be a DOM element, and the "stack" key // will be the z-index. // // Ultimately we want to create an array sorted in order of // z-indexes, from lowest to hightest. But, we also need // to remember which element had which z-index; an array of just // z-indexes or just elements does not help us. .map(function(){ return { element:this, stack:parseFloat($(this).css("z-index")) }; }) // Turn this mapped jQuery object into a pure-javascript array of // object literals. If we didn't call get(), we would still be working // with a jQuery object of object literals. .get() // Finally, sort the array ascending based on the "stack" property // of the object. Returning hierarchal numbers in sort() determines where // to place the array item. .sort(function(a,b){ return a.stack === b.stack ? 0 : (a.stack < b.stack ? -1 : 1); });
At this point we’re going to bail out of the script if there aren’t any elements to work with, which could happen one of two ways: 1) either the call to filter() returned an empty set because there weren’t any elements with a numerical z-index, or 2) when this plugin was created using $(expr).visualizeStack() syntax, the $(expr) call did not return any elements.
It is important to return “this” (the jQuery object of matching DOM elements) here to preserve chainability.
// nothing found? bail. if(!this.length || !elems.length){ return this; }
Set a few variables we’ll use later for calculating the lightness hsl() value:
var // the last "lightness" number will be recorded here. We'll start with 90. lastColor = 90, // the last z-index level will be recorded here. Start with the first // z-index in our elems array, or the lowest z-index. lastStack = elems[0]['stack'], // To define the gradient spectrum color, users can either pass in a // name of a color (like red) OR a starting hue color. If the user // passed in a name, lookup it's hue value in $.fn.visualStack.colors. // otherwise, use the number. I'm making an assumption users will read // the docs and don't try to enter the name of an unsupported color. startHue = /\w/.test(options.color) ? $.fn.visualizeStack.colors[options.color] : options.color;
Next, we need to figure out how many unique z-indexes exist so we can correctly calculate a shade of color (or lightness), which is later determined by dividing the number of unique z-indexes by 100, then subtracting the quotient by the last color hue number. We cannot rely on the total number of elements because 8 out of 10 could have the same z-index level. The shades of colors would not be applied evenly across the spectrum.
To see what I’m talking about, this is an example of the shades of red calculated when we use the total number of elements:

If we use the unique number of z-indexes, the shades of red cover a wider spectrum:

To calculate this number we’ll use a self-executing anonymous function to loop through the elems array, and add each element’s z-index to a new array called uniques unless it has already been added. The length of uniques is then returned and set to the variable uniqueStacks.
// figure out how many unique z-index there are var uniqueStacks = (function(){ // where we'll store the unique z-indexes var uniques = []; $.each(elems, function(i,obj){ if($.inArray(obj.stack, uniques) === -1){ uniques.push(obj.stack); } }); return uniques.length; })();
Next comes the heart of the plugin. With each element, we need to determine the lightness value to use based its z-index, and apply the CSS properties defined in the option’s “properties” key.
// loop through the array of objects $.each(elems, function(i, obj){ // jQuerify our element var $element = $(obj.element), // determine the lightness value. if this z-index // is the same as the last z-index, use the last lightness // value. otherwise, create a new, darker shade color = lastColor = (obj.stack === lastStack) ? lastColor : lastColor-(100/uniqueStacks); // loop through the CSS properties to add $.each(options.properties, function(prop, val){ // replace the percent sign in the property value with the // hsl() color. "background-color: %" will become // "background-color: hsl(h, s, l)" $element.css(prop, val.replace("%", "hsl("+startHue+",100%,"+color+"%)") ); // change the text color property when the shade becomes // too light or too dark to read if(options.lightTextColor.length && lastColor < = 50){ $element.css("color", options.lightTextColor); } else if(options.darkTextColor.length && lastColor >= 50){ $element.css("color", options.darkTextColor); } }); // remember what the last z-index value was lastStack = obj.stack; });
We’re almost done! The final steps are to return “this” so that this plugin can be chained, create a lookup table of color hue’s, define this plugin’s default options, and close off the wrapping closure.
return this; // close $.fn.visualizeStack }; // remember how you can pass in a color name as the "color" // property? these are the supported colors and their hue // equivalents for CSS3's hsl() $.fn.visualizeStack.colors = { red: 360, purple: 300, blue: 240, turquoise: 180, green: 120, orange: 35, yellow: 60 }; // plugin defaults $.fn.visualizeStack.defaults = { color: "red", properties: { "background": "%" }, lightTextColor: "" }; // close the wrapping closure, passing in the jQuery object // so $ can be used inside this plugin without conflict })(jQuery);
That’s all there is to it.
Tags: bookmarklet, favlet, jQuery









This seems like it could be VERY useful!! Thanks for posting!!