ce script permet de récupérer précisément la position d un élément dans le document...
3 fonction disponible :
getOffset(element, from) -> récupere la position a partir du document
getPosition(element, from) -> récupere la position a partir du dernier élément non static( la position relative n'est pas pris en charge bcp tros de beug, sur ie surtout)
getSize (element, from) -> retourne la taille de l'élément
l'argument from peux prendre 4 valeurs:
margin ou border, ou padding, ou content, et définit ou la mesure doit commencer
getOffset et getPosition commene leur mesure par default à border, getSize à content
si l'élément n'est pas visible , alors, les méthodes forceront sont affichage pour récupérer les données.
getOffset et getPosition, renvoient les valeurs sans les scroll
n'utiliser pas de tableau en position absolue, et préciser les bordure avec l'attribut style et non border
voilà si y a des bug , faite moi le savoir
a++
Source / Exemple :
(function(){//on encapusle nos donné grace a une fonction anonyme , pour eviter tros de vriables globale ou de faire un namespace
/*------------------------------------fonction privée-------------------------------------------------*/
//definit les versions du navigateur, peux etre mit en globale
var ua=navigator.userAgent.toLowerCase(),
isIE=/msie/.test(ua),
isIE6=/msie 6/.test(ua),
isIE7=/msie 7/.test(ua),
isIE8=/msie 8/.test(ua),
isWebKit = /webkit/.test(ua),
isGecko = /gecko/.test(ua) && !isWebKit,
isOpera = /presto/.test(ua);
var getStyle = function(/*DOMObject*/element, /*string*/rule){//peux etre definit en globale car très utilise, aucune dépendance...
var camelRule=rule.replace(/\-(\w)/g, function (strMatch, p1){return p1.toUpperCase();}),//supprime les tiré et met en majuscule la lettre suivante
value = element.style[camelRule];
if (!value){
if(document.defaultView && document.defaultView.getComputedStyle){
value = document.defaultView.getComputedStyle(element, "").getPropertyValue(/*fait l inverse de camelRule*/rule.replace(/[A-Z]/g, function(match){return '-'+match.charAt(0).toLowerCase();}));
}else{//specifique ie
value = element.currentStyle[camelRule] ;
}
}
return value == 'auto' ? undefined : value;
};
var toNum = function(el,rule){// convertie une valeur avec des px
return parseInt(getStyle(el,rule) ,10) || 0;
};
var manageBox = function(element, of, op, dim, co){//ajoute ou enleve les élement du modele de boite (bordure padding margin)
for(var i=0,a;(a=op[i]);i++){
of[0]+=toNum(element,a+'-left'+(a=='border'?'-width':''))*co;
of[1]+=toNum(element,a+'-top'+(a=='border'?'-width':''))*co;
if(dim){
of[0]+=toNum(element,a+'-right'+(a=='border'?'-width':''))*co;
of[1]+=toNum(element,a+'-bottom'+(a=='border'?'-width':''))*co;
}
}
};
var displayParent = function(el){//recuepre les parents pas affiché et affiche les, en position absolue (-> plus tard ) et invisible
var p=[];
while((el=el.parentNode) && el!=document.documentElement){
var d=getStyle(el,'display');
if(d=='none')
p.push(el);
}
if(p.length){
for(var i=0,el;(el=p[i]);i++){
el.style.display='';
}
var last=p[p.length-1];
last.__visibility__=getStyle(last,'visibility');
last.style.visibility='hidden';//on devrait passer en absolue le dernier parrent avec un display none, mais bcp de travaille ... faut modifier les valeurs pour correspondre à la position d'orgine , vue que le taux de rafraichissement (~= 20 millisec) est plus élévé que le temp d'execution de la fonction, on peux faire sans
/* last.__position__=getStyle(last,'position');
last.style.position='absolute';*/
}
return p;
};
var unDisplayParent = function(p,of,abs){//retablie l'affichage des parents
if(p.length){
var l=p[p.length-1];
/*if(of && l.__position__=='static'){
if(abs && (!isIE8 && !isOpera)){
of[0] -= toNum(l,'border-left-width');
of[1] -= toNum(l,'border-top-width');
}
if(abs){
of[0] -= l.offsetLeft || 0;
of[1] -= l.offsetTop || 0;
}
}
l.style.position=l.__position__;
l.__position__=null;*/
l.style.visibility=l.__visibility__;
l.__visibility__=null;
for(var i=0,el;(el=p[i]);i++){
el.style.display='none';
}
}
};
var getOffset = function(/*DOMObject*/element, /*bool*/byPos, /*string*/from){
var of=[0,0],//tab de coordonnées à retourner
from = from || 'border',//par default offset de la bordure (sasns les marges) , car la définition des position se fait a partir des bordures
el=element,//réferene a element pour boucler dessus
manageWith,//variable pour ajouter des elements du modele de boite
manageLess,//variable pour enlever des elements du modele de boite
abs,//si l'element est en absolue (utile seulement pour ie6 et 7 geko et webkit, mais déclarer pour tous pourr éviter tros e test conditionnelle)
dp=displayParent(element);//affiche les parents si néccessaire
//definit abs
if(!isIE8 || !isOpera)
abs=_abs=getStyle(element,'position')!='static'?element:false;
//ajoute au tab de coor les offsetparent, + break la boucle si un parent opu l'element en position absolue et byPos définit
while (el){
of[0] += el.offsetLeft || 0;
of[1] += el.offsetTop || 0;
el = el.offsetParent;
if(el && byPos && ((getStyle(el,'position')!='static' && (!el.__position__ || el.__position__!='static')) || abs)){
//ie8 et opera beug
if(isIE8 || isOpera){
of[0] -= toNum(el,'border-left-width');
of[1] -= toNum(el,'border-top-width');
}
break;
}
};
if(!isIE8 && !isOpera){
//si l'element est en absolue et que byPos définit, pas besoin de réctifier les valeurs
if(!byPos || !abs){
var _el=el || document.documentElement,//dernir element parent définit
el=element.parentNode;//on commence au 1er parent
//beug ie , concerne les prop width, height,et overflow
if(isIE)
var h=false;
do{
if(el.tagName=='TR' || el.tagName=='TBODY')//pas de beug sur ses éléments
continue;
if(el.tagName=='TD' || (isWebKit && el.tagName=='TABLE')){
//retranche les bordure si pas en absolue avant
if(!abs ){
of[0] += toNum(el,'border-left-width');
of[1] += toNum(el,'border-top-width');
}
h=false;
continue;
}
if(!byPos && getStyle(el,'position')!='static'){//si l'élément est pas en static, et que l'oin cherche l'offset depuis le body, en ajoute les bordure (beug)
of[0] += toNum(el,'border-left-width');
of[1] += toNum(el,'border-top-width');
abs=el;
}
// ajoute les scroll si pas ie6 qui le fait déja ,
if(!isIE6 && el!=document.body){
of[0] = of[0]-el.scrollLeft || 0;
of[1] = of[1]-el.scrollTop || 0;
}
if(isIE){
//si beug de style ie
if(!abs && (getStyle(el,'height') || getStyle(el,'width') || (isIE7 && getStyle(el,'overflow')!='visible') )){
h=el;
}
// si beug de style et pas en absolue ajoute les bordure
if(!abs && h==el){
of[0] += toNum(el,'border-left-width');
of[1] += toNum(el,'border-top-width');
}
}
}while((el=el.parentNode) && el!=_el);
}
}
//réctifie les valeurs si le dernier parent visible est body
if(!el || el==document.documentElement){
if((!isIE8 && !isOpera) && (!abs || isWebKit || isGecko)){
of[0] += toNum(document.body,'border-left-width')*(isGecko && !abs?2:1);
of[1] += toNum(document.body,'border-top-width')*(isGecko && !abs?2:1);
}
}
//définit les tableau des prop du modele de boite a enlever ou ajouter
switch(from){
case 'content':
manageWith=['padding','border'];
break;
case 'padding':
manageWith=['border'];
break;
case 'margin':
manageLess=['margin'];
break;
}
//enleve ou ajoute les prop du modele de boite
if(manageWith)
manageBox(element, of, manageWith, false, 1);
if(manageLess)
manageBox(element, of, manageLess, false, -1);
//rétatblie le display des parent
unDisplayParent(dp,of,_abs );
return of;
};
/*------------------------------------fonction publique-------------------------------------------------*/
window.getOffset=function(/*DOMObject*/element, /*string*/from){
return getOffset(element,false,from);
};
window.getPosition=function(/*DOMObject*/element, /*string*/from){
return getOffset(element,true,from);
};
window.absolutize = function(/*DOMObject*/element){
//si pas deja en absolue
if (getStyle(element,'position') == 'absolute')
return;
var es=element.style,//racourcit
dp=displayParent(element);//affiche les parents si néccessaire
var of=getPosition(element,'margin'),//position de l'élément
dim=getSize(element);//dimension de l'élément
//rétatblie le display des parent
unDisplayParent(dp,of,true);
es.position = 'absolute';
es.left = of[0] + 'px';
es.top = of[1] + 'px';
es.width =dim[0] + 'px';
es.height = dim[1] + 'px';
};
window.getSize = function(/*DOMObject*/element, /*string*/from){
var dim=[0,0],//tableau de coor à retourné
from = from || 'content',//par default taille du contenue (sasn les padding) , car la définition des taille se fait a partir de là
manageWith,//variable pour ajouter des elements du modele de boite
manageLess,//variable pour enlever des elements du modele de boite
op=from=='content' || from=='padding'?'client':'offset',//operation pour récupérer les dimension, utilise la meilleur fonction native
dp=displayParent(element);//affiche les parents si néccessaire
dim[0] += element[op+'Width'];
dim[1] += element[op+'Height'];
//définit le tableau des prop du modele de boite a enlever ou ajouter
switch(from){
case 'margin':
manageLess=['margin'];
break;
case 'content':
manageWith=['padding'];
break;
}
//enleve ou ajoute les prop du modele de boite
if(manageWith || manageLess)
manageBox(element, dim, manageWith || manageLess, true,manageLess?1:-1);
//rétatblie le display des parent
unDisplayParent(dp);
return dim;
};
})()