Position, offsetleft, clientleft crossbrowser

Description

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; 
   };
  
})()

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.