Ce script a pour but de connaître la couleur de fond effective d'un élément du DOM. Par effective j'entends la couleur que nous voyant.
| Figure 1: Quel est la couleur de fond de ce paragrahe? |
|---|
Mon paragraphe de test. On répondrait imédiatement que ce paragraphe a pour couleur de fond le blanc, or ce n'est pas réellement exacte du point de vue du javascript. En effet une requête sur l'objet donnerait null ou undefined. alert('paragraphe.bgColor'); //donne null
alert('paragraphe.style.backgroundColor'); //donne null ou 'none' |
Ce paragraphe n'a en réalité pas de couleur de fond. Le blanc visible n'étant rien d'autre que la couleur de fond de l'élément parent, ou peut-être du parent du parent si ce dernier n'a lui même pas de couleur de spécifiée.
J'ai donc conçu ce script afin d'obtenir la couleur de fond 'visible' de ce paragraphe. Vous pouvez retrouvez ce script sur le site Codes-Sources est découvrir les remarques de la communauté web à son sujet. Par ailleur n'hésitez pas à faire par de vos propres suggestions.
| Figure 2: Spécification de ma fonction getVisibleBackgroundColor(obj) |
|---|
Fonction: getVisibleBackgroundColor(obj) Argument: obj - rfrence d'un objet du DOM Valeur de retour: couleur de fond 'visible' de obj |
| Figure3: Speudo-code de la fonction getVisibleBAckgroundColor(obj) |
|---|
SI obj.style.backgroundColor est une couleur ALORS RENVOI(obj.style.backgroundColor) FIN SI SI une régle dans une feuille de style définit la couleur de fond de obj ALORS RENVOI(La couleur spcifie dans la dernire rgle concernant obj) FIN SI SI obj.bgColor est une couleur ALORS RENVOI(obj.bgColor) FIN SI SI obj n'a plus de parent ALORS RENVOI(couleur de fond par défaut) FIN SI RENVOI(getVisibleBackgroundColor(obj.parent)) |
Dans ce speudo-code la deuxième condition cherche à savoir si une règle dans une feuille de style CSS définit la couleur de fond de l'objet étudié. Pour cela nous ferons appel à une seconde fonction getBackgroundColorFromStylesheetFor(obj).
| Figure4: Spécification de la fonction getBackgroundColorFromStylesheetFor(obj) |
|---|
Fonction: getBackgroundColorFromStylesheetFor(obj) Argument: obj - référence d'un objet du DOM Valeur de retour: dernire couleur de fond spficie dans l'ensemble des rgles css trouves applicable l'objet obj! |
| Figure 5: Speudo-code de la fonction getBackgroundColorFromStylesheetFor(obj) |
|---|
@REPONSE=NULL POUR TOUTES les feuilles de styles trouve VARIABLE X POUR TOUTES pour toutes les rgles css de X VARIABLE Y SI Y est de la forme #id et id=obj.id ALORS @REPONSE=Y.style.backgroundColor On passe Y suivant OU SI Y est de la forme .className et classname=obj.className ALORS @REPONSE=Y.style.backgroundColor On passe Y suivant OU SI Y est de la forme tag et tag=obj.tagName ALORS @REPONSE=Y.style.backgroundColor On passe Y suivant FINSI FIN BOUCLE FIN BOUCLE ALORS RENVOI(obj.style.backgroundColor) FIN SI SI une régle dans une feuille de style définit la couleur de fond de obj ALORS RENVOI(La couleur spécifiée dans la dernière règle concernant obj) FIN SI SI obj.bgColor est une couleur ALORS RENVOI(obj.bgColor) FIN SI SI obj n'a plus de parent ALORS RENVOI(couleur de fond par défaut) FIN SI ALORS RENVOI(getVisibleBackgroundColor(obj.parent)) |
Reste plus qu'a traduire ce speudo-code en javascript en abordant les notions suivantes :
| Figure 6: Code source |
|---|
var defaultBodyBAckground='#FFFFFF';
function getVisibleBackgroundColor(obj)
{
if(obj==null) { return defaultBodyBAckground; }
if(obj.style && obj.style.backgroundColor!='' && obj.style.backgroundColor!='none')
{ return obj.style.backgroundColor; }
var bgColorByStylesheet=getBackgroundColorFromStyleSheetFor(obj);
if(bgColorByStylesheet!=null) { return bgColorByStylesheet; }
if(obj.bgColor && obj.bgColor!='') { return obj.bgColor; }
return getVisibleBackgroundColor(obj.parentNode);
}
function getBackgroundColorFromStyleSheetFor(obj)
{
var returnColor=null;
for(i=0 ; i<document.styleSheets.length ; i++)
{
var ss=document.styleSheets[i];
var length=0;
if(ss.cssRules) { length=ss.cssRules.length; }
else { length=ss.rules.length; }
for(j=0 ; j<length ; j++)
{
var cssr=null;
if(ss.cssRules) { cssr=ss.cssRules[j]; }
else { cssr=ss.rules[j]; }
var selector=cssr.selectorText;
switch(selector.charAt(0))
{
case '#' :
if(obj.id!=null
&& obj.id!=''
&& obj.id.toUpperCase()==selector.substr(1).toUpperCase())
{
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; }
}
break;
case '.' :
if(obj.className!=null
&& obj.className!=''
&& obj.className.toUpperCase()==selector.substr(1).toUpperCase())
{
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; }
}
break;
default :
if(obj.tagName.toUpperCase()==selector.toUpperCase())
{
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; }
}
break;
}
}
}
return returnColor;
} |
var defaultBodyBAckground='#FFFFFF'; |
Il s'agit de la valeur du fond de la page. Elle est retournée par la fonction lorsque qu'aucune spécification de couleur de fond n'a pû être trouvée pour l'élément voulu (ainsi que l'ensemble de ses parents).
function getVisibleBackgroundColor(obj)
{
if(obj==null) { return defaultBodyBAckground; }
|
On test si obj est bien une référence valide. Sans quoi nous retournons imédiatement la couleur de fond par défaut définit juste au-dessus. Il s'agit de la condition d'arrêt de la récursivité puisque si au pire nous parcourons l'ensemble des parents d'un élément nous terminerons par l'élément <html> dont sont parent sera inexistant. C'est donc ainsi que s'arrêtera les appels récursifs.
if(obj.style && obj.style.backgroundColor!='' && obj.style.backgroundColor!='none') |
On test si la couleur de fond de l'élément obj a été définit en css 'inline'. C'est à dire avec une syntaxe de la forme <tag style="background-color:#FF55cc; ..."...>...</tag>. J'effectue ici plusieurs test de validité de cette propriété. Car elle pourrait très bien être définit mais avec une valeur none.
{ return obj.style.backgroundColor; } |
Si la couleur est bien spécifiée en css 'inline' alors on la retourne (l'éxecution de la fonction se termine ici).
var bgColorByStylesheet=getBackgroundColorFromStyleSheetFor(obj); |
On déclare une variable bgColorByStylesheet qui sera initialisé par un appel à notre seconde fonction définie plus bas.
if(bgColorByStylesheet!=null) { return bgColorByStylesheet; } |
Si notre variable fraîchement initialisée n'est pas null, c'est qu'une couleur de fond a été spécifié pour notre élément via une règle css d'une des feuilles de style. On retourne cette couleur (fin de l'éxécution de notre fonction).
if(obj.bgColor && obj.bgColor!='') { return obj.bgColor; } |
On test enfin si une couleur de fond a été spécifié via l'attribut bgColor. Comme cette attribu n'est pas applicable à toute les balises nous effectuons tout d'abord un test sur obj.bgColor.
Javascript contrairement à d'autre language n'évalue pas l'ensemble des membres d'un test conditionnel avant d'effectuer effectivement le test. Ce qui entraîne dans ce cas précis que si obj.Color est faux (false) et que ce test est suivi de la concaténation de condition et (&&). Il est inutile de poursuivre. Donc obj.Color!='' ne sera même pas évalué et ne provoquera aucune erreur même si l'attribut ne peut existé pour l'objet courrament scruté.
En résumé notre test résume le comportement souhaité pouvant s'écrire if(obj.bgColor) { if(obj.bgColor!='') { ...
return getVisibleBackgroundColor(obj.parentNode); } |
Si aucune valeur n'a été retourné jusqu'ici cela veux dire qu'aucune couleur de fond n'a été spécifiée pour notre élément obj. Nous renvoyons donc la valeur de la couleur de fond de son élément parent dans le DOM en rappelant simplement la fonction avec comme argument obj.parentNode.
function getBackgroundColorFromStyleSheetFor(obj)
{ |
Déclaration de notre seconde fonction dont le but est de parcourir l'ensemble des règles CSS définit dans toute les feuilles de style attachées ou déclarées dans le document .
var returnColor=null; |
On initilise notre variable de retour à null.Cette variable prendra succesivement les valeur de couleur de fond déclarées dans les feuilles de styles s'applicant à l'objet obj passé en argument à la fonction.
Ainsi si une règle surcharge une règle précédente la valeur de notre variable de retour sera également surchargé.
for(i=0 ; i<document.styleSheets.length ; i++)
{ |
L'objet document.styleSheets est la collection de l'ensemble des feuilles de style du document. Il prend en compte indifférement les feuilles de style liées (<link...>...) et les feuilles de style déclarées au sein du document (<style...>...).
Cette collection est sependant ordonnée ce qui nous permet d'assuré l'intégrité dans l'ordre de surchargement des règles CSS découverte.
var ss=document.styleSheets[i]; |
On déclare simplement un objet ss (comme Style Sheet) afin de simplifier l'écriture du code suivant (pour les adpetes de la syntaxe with(document.styleSheet[i]). Cet objet et réasigné au fur et à mesure de notre boucle sur la collection de feuilles de styles.
var length=0;
if(ss.cssRules) { length=ss.cssRules.length; }
else { length=ss.rules.length; } |
Nous préparons maintenant la boucle sur les règles de la feuille de style ss. Il s'avère que IE et Mozilla n'utilise pas la même déclaration pour cette collection de règle. D'où cette initialisation du nombre de règles avec ce test.
for(j=0 ; j<length ; j++)
{ |
Début de la boucle sur l'ensemble des règles CSS de la feuille de style courante ss.
var cssr=null;
if(ss.cssRules) { cssr=ss.cssRules[j]; }
else { cssr=ss.rules[j]; } |
On initialise à chaque itération de la boucle un objet cssr (comme css rule/règle) en tenant compte de la différence de déclaration entre IE et Mozilla.
var selector=cssr.selectorText;
switch(selector.charAt(0))
{ |
On va maintenant cherché à étudier quelle type de règle CSS il s'agit à savoir :
case '#' : |
Les règles commencant par le caractère # concerne les règles 'sapplicant un un élément du DOM possédant un id spécifique.
if(obj.id!=null
&& obj.id!=''
&& obj.id.toUpperCase()==selector.substr(1).toUpperCase())
{ |
On regarde donc si notre élément obj possède un id coïcident avec notre règle.
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; } |
Si notre règle s'applique à notre élement alors on regarde si cette règle spécifie une couleur de fond. Si c'est le cas on met à jour la valeur de retour.
} break; |
On redonne la main à la boucle sur les règles.
case '.' : |
On s'atèle maintenant au règle de la forme .cssClaseName.
if(obj.className!=null
&& obj.className!=''
&& obj.className.toUpperCase()==selector.substr(1).toUpperCase())
{ |
Comme tout à l'heure on test si notre élément peut être affecté par cette règle. Notons au passage l'une des rares entorses syntaxique du language javascript à savoir obj.className. En effet la logique voudrait que l'on récupère le nom de la classe d'un élément du DOM via la propriété class puisque c'est ainsi qu'on la déclare (<tag class="cssClassName"...>...). Mais comme class est un mot réservé du language javascript il faut utilisé obj.className au lieu de obj.class qui provoquerait une erreur à l'éxécution de la page.
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; } |
Comme plus au on regarde si une couleur de fond est spécifiée et si c'est le cas on surcharge notre valeur de retour.
} break; |
On redonne la main à la boucle sur les règles.
default : if(obj.tagName.toUpperCase()==selector.toUpperCase()) |
Le dernier cas ou type de règle que nous traiterons ici concerne les règles CSS s'appliquant à un type précis de balise html (exemple P, H1, H2, etc...).
Notons au passage l'usage de la propriété tagName qui nous donne la type de balise html de notre élément. Par précaution nous forcons le passage en majuscule des deux membres de notre test d'égalité.
{
if(cssr.style.backgroundColor!=null
&& cssr.style.backgroundColor!='none'
&& cssr.style.backgroundColor!='')
{ returnColor=cssr.style.backgroundColor; } |
Si notre règle s'applique à notre élément alors on surcharge notre valeur de retour si celle-ci spécifie bien une couleur de fond.
} break; } |
On redonne la main à la boucle sur les règles.
} |
Fin de la boucle sur les règles css de la feuille de style courante.
} |
Fin de la boucle sur les feuilles de style.
return returnColor; |
On retourne notre variable prévue a cette effet. Celle si contient la couleur de fond spécifiée par la dernière règle CSS applicable à notre élément obj. Elle contient null si aucune règle ne définisait une couleur de fond pour obj.
} |
Et voilà tout est en place pour déterminer avec exactitude la couleur de fond d'un élément du DOM.
Voici un mini démonstration interactive vous permettant de connaitre la couleur de fond d'un élément du DOM à partir de son id.
Voici la source et l'exemple en téléchargement
Ce script présenter tel quel ne paye pas de mine. En effet pas de mouvement dans tous les sens, pas de couleurs qui change de partout... bref on pourrait terminer en disant qu'il est nul. En fait je tenterai au travers d'autres scripts de vous montrer la puissance de celui-ci. Alors un peut de patience pour voir des applications plus que concrète de ce script.
Ce script a été testé et validé sous IE6 et Firefox en envirronement Windows XP.