19
Sep
2011
On 19, Sep 2011 | No Comments | In Coding, HTML5/CSS3, JavaScript/Ajax, jQuery, Tutorials/Tips
cssHooks – Expanding the Set of CSS Properties
by FINoM
In this article I will tell you about the jQuery.cssHooks object, which jQuery contains by default. The expansion of this object allows you to add new properties or values written in the . css () method, which are not natively supported by certain browsers. Perhaps the availability of many CSS hooks is not new, but for me it was a small opening.
For those who are too lazy to read further, I cite the main idea. Let’s suppose you want to add to jQuery CSS property chuck-norris:
$.cssHooks.chuckNorris = {
get: function(elem) {
//do some manipulations with elem component, and get value
return value;
},
set: function(elem, value) {
//do some manipulations with elem component, set the value
}
}
$(el).css(‘chuck-norris’, Infinity);
//или $(el).css({‘chuck-norris’: Infinity});
alert($(el).css(‘chuck-norris’)); //Infinity
Next I will describe in details the “modification” of background-color property to support the rgba in older versions of IE, and adding a new, non-existent in the specification property of background-alpha for easy installation of transparent background color. In IE, the color transparency will be implemented through the use of filter’s properties, adding the element of the gradient, which consists of two identical colors.
This method has two drawbacks.
Firstly, the gradients don’t work for units with auto width, you will have to apply the hack:
$('div').width('100%');
Secondly, filters operate on the background images. Instead of the expected (first figure) in older versions of IE you get something like this (second figure).


First, we need a (parseColor) function, which will parse the color in different formats and return the object {r, g, b, a}. The following options are considered:
• When an empty string or transpatent entered the input
• The string in # aarrggbb format (for gradients in IE)
• The string in #rrggbb format
• The string in #rgb format
• The string in rgb[a](r, g, b [, a]) format
On the second stage we will create a class Color, which takes an html element, and contains a number of functions that are needed in the future.
var Color = function(el){
//function returns an object of the three elements:
//whether the browser is IE8-, if there is a gradient in the styles, whether this gradient is enabled
var ieDetect = (function(){
var ua = navigator.userAgent;
var result = {}
result.isOldIe = ~ua.indexOf('MSIE 6') || ~ua.indexOf('MSIE 7') || ~ua.indexOf('MSIE 8');
result.hasGradient = result.isOldIe &&
~el.style.filter.toLowerCase().indexOf('gradient');
result.isGradientEnabled = result.hasGradient &&
!!el.filters.item("DXImageTransform.Microsoft.gradient").enabled;
return result;
})();
//conversion of the object with decimal color values into the object with hexadecimal
var colorToHex = function (objColor) {
var hex = {};
for (var i in objColor) {
hex[i] = objColor[i];
if (i==='a') {
hex.a = Math.round(hex.a*255);
}
hex[i] = hex[i].toString(16);
//add '0 'if the resulting value is of a single character
hex[i] = hex[i].length == 2 ? hex[i] : '0' + hex[i];
}
return hex;
}
//converts the object {r, g, b, a} in a string with the specified format
var colorToString = function(objColor, format) {
var hexColor = colorToHex(objColor);
switch(format) {
case 'rgb': return 'rgb(' + objColor.r + ',' + objColor.g + ',' + objColor.b + ')';
case 'rgba': return 'rgba(' + objColor.r + ',' + objColor.g + ',' +
objColor.b +',' + objColor.a + ')';
case '#6': return '#' + hexColor.r + hexColor.g + hexColor.b;
case '#8': return '#' + hexColor.a + hexColor.r + hexColor.g + hexColor.b;
}
}
//Converts one color format to another
var convertColor = function(color, format) {
var colorObj = parseColor(color);
return colorToString(colorObj, format)
}
//adds getComputedStyle support for older browsers
//below you'll see for what purpose
if (!window.getComputedStyle) {
window.getComputedStyle = function(el, pseudo) {
this.el = el;
this.getPropertyValue = function(prop) {
var re = /(\-([a-z]){1})/g;
if (re.test(prop)) {
prop = prop.replace(re, function () {
return arguments[2].toUpperCase();
});
}
return el.currentStyle[prop] ? el.currentStyle[prop] : null;
}
return this;
}
}
...
Now we’ll move to the installation of the color value. I hope it won’t be so difficult for our readers to understand the code, despite its nesting.
this.setBackgroundColor = function(color) {
var newColor,
newColorObj = parseColor(color);
if(ieDetect.isOldIe) { // If IE
if(newColorObj.a < 1) { // If alpha is less than 1
el.style.backgroundColor = 'transparent';
newColor = colorToString(newColorObj, '#8');
if(ieDetect.hasGradient) { // If there is a gradient filter
el.filters.item("DXImageTransform.Microsoft.gradient").enabled = true;
el.filters.item("DXImageTransform.Microsoft.gradient").startColorstr = newColor;
el.filters.item("DXImageTransform.Microsoft.gradient").endColorstr = newColor;
} else { // If there is no gradient filter
el.style.filter +=
"progid:DXImageTransform.Microsoft.gradient(enabled='true', startColorstr=" +
newColor + ", endColorstr=" + newColor + ")";
}
} else { // If alpha equals 1
newColor = colorToString(newColorObj, '#6');
if(ieDetect.hasGradient) { // If there is a gradient filter
el.filters.item("DXImageTransform.Microsoft.gradient").enabled = false;
el.style.backgroundColor = newColor;
} else { // If there is no gradient filter
el.style.backgroundColor = newColor;
}
}
} else { // if it’s not IE
if(newColorObj.a < 1) { // If alpha is less than 1
newColor = colorToString(newColorObj, 'rgba');
el.style.backgroundColor = newColor;
} else { // If alpha equals 1
newColor = colorToString(newColorObj, '#6');
el.style.backgroundColor = newColor;
}
}
}
The next part of the code is responsible for getting the color values. It’s a lot easier.
this.getBackgroundColor = function() {
var color;
if(ieDetect.isGradientEnabled) { // If it is IE and the gradient is enabled
color = el.filters.item("DXImageTransform.Microsoft.gradient").startColorstr;
return convertColor(color, 'rgba');
} else {
//the hack was taken from here: http://snipplr.com/view/13523/getcomputedstyle-for-ie/
//instead we could use $(el).css('background-color');
//but we reassign this property, and there appears an infinite recursion
color = el.style.BackgroundColor ||
window.getComputedStyle(el,null).getPropertyValue('background-color');
return color;
}
}
Now the main part. We add a backgroundColor hook.
$.cssHooks.backgroundColor = {
get: function(elem) {
var color = new Color(elem);
return color.getBackgroundColor();
},
set: function( elem, value ) {
var color = new Color(elem);
color.setBackgroundColor(value);
}
}
Add a backgroundAlpha hook
$.cssHooks.backgroundAlpha = {
get: function(elem) {
var color = new Color(elem);
var colorStr = color.getBackgroundColor();
var colorObj = parseColor(colorStr);
return colorObj.a;
},
set: function(elem, value) {
var color = new Color(elem);
var colorStr = color.getBackgroundColor();
var colorObj = parseColor(colorStr);
//if the value of the style is a number, then jQuery attributes 'px'; fix
colorObj.a = String(value).replace('px', '');
color.setBackgroundColor('rgba('+
colorObj.r+','+colorObj.g+','+colorObj.b+','+colorObj.a+')');
}
}
All is done, now you can use it.
p{background-color: #991111; ...}
div{background: url(...) ...}
<div> <p>...</p> <p>...</p> </div>
$('p').width('100%');
$('p:eq(0)').css({'background-color':'rgba(0,111,221,0.9)'});
$('p:eq(1)').css('background-alpha', 0.5);
As we can see, for objects with names in the «camel case» style jQuery automatically adds support for “hyphen” style.
Conclusion
If you want to add support for a property that is not supported (or partially supported) by various browsers, you should forget about what you can do with the plug-in creation and use $. CssHooks instead.
Links:
The final version: finom.ho.ua/bgalpha/
cssHooks in alternative documentation: jqapi.com/#p=jQuery.cssHooks






