
Для тех, кому лень дальше читать, привожу основную мысль. Допустим, вы хотите в jQuery добавить CSS свойство chuck-norris:
$.cssHooks.chuckNorris = {
get: function(elem) {
//проводим манипуляции с узлом elem, получаем value
return value;
},
set: function(elem, value) {
//проводим манипуляции с узлом elem, устанавливаем value
}
}
$(el).css(‘chuck-norris’, Infinity);
//или $(el).css({‘chuck-norris’: Infinity});
alert($(el).css(‘chuck-norris’)); //Infinity
Далее будет подробно описана «модификация» свойства background-color для поддержки rgba в старых версиях IE и добавление нового, несуществующего в спецификации свойства background-alpha для удобной установки прозрачности фонового цвета. В IE прозрачность цвета будет реализована с помощью использования свойства filter, добавляя элементу градиент, состоящий из двух одинаковых цветов.
Этот способ имеет два недостатка.
Во-первых градиенты не работают для блоков с шириной auto, для этого придется применять хак:
$('div').width('100%');
Во-вторых фильтры действуют на фоновые изображения. Вместо ожидаемого (первый рисунок) в старых версиях осла вы получите такое (второй рисунок).


Для начала нам понадобится функция (parseColor), которая будет парсить цвет в разных форматах и возвращать объект {r,g,b,a}. Учтены следующие варианты:
- Когда на вход поступила пустая строка или transpatent
- Строка формата #aarrggbb (для градиентов в IE)
- Строка формата #rrggbb
- Строка формата #rgb
- Строка формата rgb[a](r, g, b [, a])
Код этого парсера (который будет не к месту из-за размера) и, собственно, идея частично позаимстсоваы отсюда.
Вторым этапом создадим класс Color, принимающий на вход html узел и содержащий ряд функций, которые в дальнейшем понадобятся.
var Color = function(el){
//функция возвращает объект из трех элементов:
//является ли браузер IE8-, есть ли в стилях элемента градиент, включен ли этот градиент
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;
})();
//конвертация объекта с десятичными значениями цвета в объект с шестнадцатиричными
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);
//добавляем '0', если полученное значение состоит из одного символа
hex[i] = hex[i].length == 2 ? hex[i] : '0' + hex[i];
}
return hex;
}
//преобразует объект {r,g,b,a} в строку с заданным форматом
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;
}
}
//конвертирует один формат цвета в другой
var convertColor = function(color, format) {
var colorObj = parseColor(color);
return colorToString(colorObj, format)
}
//добавляет поддержку getComputedStyle для старых браузеров
//ниже будет видно, зачем
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;
}
}
...
Теперь перейдем к самой установке значения цвета. Надеюсь, читателю не составит большого труда понять код, несмотря на его вложенность.
this.setBackgroundColor = function(color) {
var newColor,
newColorObj = parseColor(color);
if(ieDetect.isOldIe) { // Если IE
if(newColorObj.a < 1) { // Если альфа меньше единицы
el.style.backgroundColor = 'transparent';
newColor = colorToString(newColorObj, '#8');
if(ieDetect.hasGradient) { // Если есть фильтр градиент
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 { // Если нету фильтра градиент
el.style.filter +=
"progid:DXImageTransform.Microsoft.gradient(enabled='true', startColorstr=" +
newColor + ", endColorstr=" + newColor + ")";
}
} else { // Если альфа равна единице
newColor = colorToString(newColorObj, '#6');
if(ieDetect.hasGradient) { // Если есть фильтр градиент
el.filters.item("DXImageTransform.Microsoft.gradient").enabled = false;
el.style.backgroundColor = newColor;
} else { // Если нету фильтра градиент
el.style.backgroundColor = newColor;
}
}
} else { // Если не IE
if(newColorObj.a < 1) { // Если альфа меньше единицы
newColor = colorToString(newColorObj, 'rgba');
el.style.backgroundColor = newColor;
} else { // Если альфа равна единице
newColor = colorToString(newColorObj, '#6');
el.style.backgroundColor = newColor;
}
}
}
Следующая часть кода отвечает за получение значения цвета. Здесь уже намного проще.
this.getBackgroundColor = function() {
var color;
if(ieDetect.isGradientEnabled) { // Если IE и включен градиент
color = el.filters.item("DXImageTransform.Microsoft.gradient").startColorstr;
return convertColor(color, 'rgba');
} else {
//хак взят отсюда: http://snipplr.com/view/13523/getcomputedstyle-for-ie/
//вместо этого мы могли бы использовать $(el).css('background-color');
//но это свойство мы переназначаем, и возникает бесконечная рекурсия
color = el.style.BackgroundColor ||
window.getComputedStyle(el,null).getPropertyValue('background-color');
return color;
}
}
Теперь основная часть. Добавляем хук backgroundColor.
$.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);
}
}
Добавляем хук backgroundAlpha
$.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);
//если значением стиля является число, то jQuery приписывает 'px'; фиксим
colorObj.a = String(value).replace('px', '');
color.setBackgroundColor('rgba('+
colorObj.r+','+colorObj.g+','+colorObj.b+','+colorObj.a+')');
}
}
Всё сделано, теперь можно использовать.
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);
Как мы видим, для объектов с названиями в стиле «camel case» jQuery автоматически добавляет поддержку «дефисного» стиля.
Вывод
Если вы хотите добавить поддержку некоторого свойства, которое не поддерживается (или частично поддерживается) теми или иными браузерами, то стоит забыть о том, что это можно сделать созданием плагина и, вместо этого, использовать $.cssHooks.
Ссылки:
Итоговый вариант: finom.ho.ua/bgalpha
Код хуков из статьи: finom.ho.ua/bgalpha/background-rgba.csshook.jquery.js
cssHooks в альтернативной документации: jqapi.com/#p=jQuery.cssHooks