Voglio sapere come ottenere la posizione X e Y di elementi HTML come img
e div
in JavaScript rispetto alla finestra del browser.
Voglio sapere come ottenere la posizione X e Y di elementi HTML come img
e div
in JavaScript rispetto alla finestra del browser.
Risposte:
L'approccio corretto è usare element.getBoundingClientRect()
:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Internet Explorer lo supporta da quando è probabile che ti interessi e alla fine è stato standardizzato nelle viste CSSOM . Tutti gli altri browser lo hanno adottato molto tempo fa .
Alcuni browser restituiscono anche proprietà di altezza e larghezza, anche se questo non è standard. Se sei preoccupato per la vecchia compatibilità del browser, controlla le revisioni di questa risposta per un'implementazione degradante ottimizzata.
I valori restituiti da element.getBoundingClientRect()
sono relativi alla finestra. Se ne hai bisogno rispetto ad un altro elemento, sottrai semplicemente un rettangolo dall'altro:
var bodyRect = document.body.getBoundingClientRect(),
elemRect = element.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
alert('Element is ' + offset + ' vertical pixels from <body>');
<body>
, però.
element.getBoundingClientRect().top
non restituisce l'offset superiore corretto nel caso di un position: fixed
elemento in iOS (iPhone 8) se contiene un elemento di input focalizzato e la tastiera virtuale è stata aperta. Ad esempio, se l'offset effettivo dalla parte superiore della finestra è 200 px, lo segnalerebbe come 420 px, dove 220 px è l'altezza della tastiera virtuale. Se imposti gli elementi position: absolute
e li posizioni nella stessa posizione di quelli fissi, otterrai i 200px corretti. Non conosco una soluzione a questo.
Le librerie fanno di tutto per ottenere offset accurati per un elemento.
ecco una semplice funzione che fa il lavoro in ogni circostanza che ho provato.
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left;
Questo ha funzionato per me (modificato dalla risposta più votata):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
Usando questo possiamo chiamare
getOffset(element).left
o
getOffset(element).top
div
cui centro usando css top:50%, left:50%; transform:translate(-50%, -50%);
... eccellente. Accetto con la domanda di @ScottBiggs. Logico è cercare la semplicità.
rect
usando var
, let
o const
. Altrimenti, è definito come window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
restituirà la posizione centrale di un elemento
Se vuoi farlo solo in javascript , ecco alcuni uno liners che utilizzanogetBoundingClientRect()
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
La prima riga restituirà la offsetTop
dicitura Y relativa al documento. La seconda riga restituirà la offsetLeft
dicitura X relativa al documento.
getBoundingClientRect()
è una funzione javascript che restituisce la posizione dell'elemento rispetto alla finestra della finestra.
Gli elementi HTML sulla maggior parte dei browser avranno: -
offsetLeft
offsetTop
Questi specificano la posizione dell'elemento rispetto al suo genitore più vicino che ha layout. È possibile accedere a questo genitore spesso tramite la proprietà offsetParent.
IE e FF3 hanno
clientLeft
clientTop
Queste proprietà sono meno comuni, specificano una posizione degli elementi con l'area client principale (l'area imbottita fa parte dell'area client ma il bordo e il margine no).
Se la pagina include - almeno - qualsiasi "DIV", la funzione fornita da meouw lancia il valore "Y" oltre i limiti di pagina correnti. Per trovare la posizione esatta, è necessario gestire sia offsetParent che parentNode.
Prova il codice indicato di seguito (è verificato per FF2):
var getAbsPosition = function(el){
var el2 = el;
var curtop = 0;
var curleft = 0;
if (document.getElementById || document.all) {
do {
curleft += el.offsetLeft-el.scrollLeft;
curtop += el.offsetTop-el.scrollTop;
el = el.offsetParent;
el2 = el2.parentNode;
while (el2 != el) {
curleft -= el2.scrollLeft;
curtop -= el2.scrollTop;
el2 = el2.parentNode;
}
} while (el.offsetParent);
} else if (document.layers) {
curtop += el.y;
curleft += el.x;
}
return [curtop, curleft];
};
Puoi aggiungere due proprietà per Element.prototype
ottenere la parte superiore / sinistra di qualsiasi elemento.
Object.defineProperty( Element.prototype, 'documentOffsetTop', {
get: function () {
return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
}
} );
Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
get: function () {
return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
}
} );
Questo si chiama così:
var x = document.getElementById( 'myDiv' ).documentOffsetLeft;
Ecco una demo che confronta i risultati con jQuery offset().top
e .left
: http://jsfiddle.net/ThinkingStiff/3G7EZ/
Element.prototype
è generalmente considerata una cattiva idea . Porta a un codice davvero difficile da mantenere. Inoltre, questo codice non tiene conto dello scorrimento.
Per recuperare la posizione relativa alla pagina in modo efficiente e senza utilizzare una funzione ricorsiva: (include anche IE)
var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?
document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;
Che ne dici di qualcosa del genere, passando l'ID dell'elemento e restituirà la parte sinistra o superiore, possiamo anche combinarli:
1) trova a sinistra
function findLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.left + window.scrollX;
} //call it like findLeft('#header');
2) trova la cima
function findTop(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.top + window.scrollY;
} //call it like findTop('#header');
o 3) trova sinistra e in alto insieme
function findTopLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');
Potresti essere meglio servito usando un framework JavaScript, che ha funzioni per restituire tali informazioni (e molto altro!) In modo indipendente dal browser. Eccone alcuni:
Con questi framework, potresti fare qualcosa del genere:
$('id-of-img').top
ottenere la coordinata y-pixel dell'immagine.
jQuery .offset () otterrà le coordinate correnti del primo elemento o imposterà le coordinate di ogni elemento, nel set di elementi corrispondenti, relativamente al documento.
Ho preso la risposta di @ meouw, aggiunto in clientLeft che consente il bordo e quindi creato tre versioni:
getAbsoluteOffsetFromBody - simile a quello di @ meouw, ottiene la posizione assoluta rispetto al corpo o all'elemento html del documento (a seconda della modalità di stranezza)
getAbsoluteOffsetFromGivenElement: restituisce la posizione assoluta relativa all'elemento specificato (relativeEl). Si noti che l'elemento specificato deve contenere l'elemento el, altrimenti si comporterà come getAbsoluteOffsetFromBody. Questo è utile se hai due elementi contenuti in un altro (noto) elemento (facoltativamente diversi nodi nella struttura dei nodi) e vuoi renderli nella stessa posizione.
getAbsoluteOffsetFromRelative: restituisce la posizione assoluta relativa al primo elemento padre con position: relative. Questo è simile a getAbsoluteOffsetFromGivenElement, per lo stesso motivo, ma andrà solo fino al primo elemento corrispondente.
getAbsoluteOffsetFromBody = function( el )
{ // finds the offset of el from the body or html element
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{ // finds the offset of el from relativeEl
var _x = 0;
var _y = 0;
while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
getAbsoluteOffsetFromRelative = function( el )
{ // finds the offset of el from the first parent with position: relative
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
if (el != null)
{
if (getComputedStyle !== 'undefined')
valString = getComputedStyle(el, null).getPropertyValue('position');
else
valString = el.currentStyle['position'];
if (valString === "relative")
el = null;
}
}
return { top: _y, left: _x };
}
Se i problemi persistono, in particolare quelli relativi allo scorrimento, potresti provare a consultare http://www.greywyvern.com/?post=331 - Ho notato almeno un pezzo di codice discutibile in getStyle che dovrebbe andare bene supponendo che i browser si comportino bene , ma non ho ancora testato il resto.
se si utilizza jQuery, il plug-in dimensioni è eccellente e consente di specificare esattamente ciò che si desidera.
per esempio
Posizione relativa, posizione assoluta, posizione assoluta senza imbottitura, con imbottitura ...
Continua, diciamo solo che c'è molto che puoi farci.
Inoltre il vantaggio dell'utilizzo di jQuery è la sua dimensione di file leggera e un facile utilizzo, non tornerai a JavaScript senza di essa in seguito.
Questo è il miglior codice che sono riuscito a creare (funziona anche con iframe, a differenza di offset () di jQuery). Sembra che il webkit abbia un comportamento un po 'diverso.
Basato sul commento di meouw:
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
// chrome/safari
if ($.browser.webkit) {
el = el.parentNode;
} else {
// firefox/IE
el = el.offsetParent;
}
}
return { top: _y, left: _x };
}
Se stai usando jQuery, questa potrebbe essere una soluzione semplice:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Differenza tra piccolo e piccolo
function getPosition( el ) {
var x = 0;
var y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
x += el.offsetLeft - el.scrollLeft;
y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: y, left: x };
}
Guarda un esempio di coordinate: http://javascript.info/tutorial/coordinates
<svg>
elementi, per esempio, non hanno offsetLeft
, offsetTop
e offsetParent
le proprietà.
DIV
o IMG
no SVG
. Visualizza "Guarda un esempio di coordinate"? puoi trovare l'oggetto svg è posizione chiamata getOffsetRect , prova a dipendere dal lavoro dell'oggetto.
L'approccio più pulito che ho trovato è una versione semplificata della tecnica utilizzata da jQuery offset
. Simile ad alcune delle altre risposte con cui inizia getBoundingClientRect
; quindi usa il window
e il documentElement
per regolare la posizione di scorrimento così come cose come il margine sul body
(spesso predefinito).
var rect = el.getBoundingClientRect();
var docEl = document.documentElement;
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
Mentre è molto probabile che questo si perda in fondo a così tante risposte, le migliori soluzioni qui non funzionavano per me.
Per quanto ne so, nessuna delle altre risposte avrebbe aiutato.
Situazione :
in una pagina HTML5 avevo un menu che era un elemento nav all'interno di un'intestazione (non l'intestazione THE ma un'intestazione in un altro elemento).
Volevo che la navigazione rimanesse in alto una volta che l'utente lo scorreva, ma prima di ciò l'intestazione era posizionata in modo assoluto (quindi avrei potuto sovrapporla leggermente qualcos'altro).
Le soluzioni sopra non hanno mai innescato un cambiamento perché .offsetTop non cambierà poiché si trattava di un elemento posizionato in modo assoluto. Inoltre, la proprietà .scrollTop era semplicemente la parte superiore dell'elemento più in alto ... vale a dire 0 e sarebbe sempre 0.
Qualsiasi test che ho eseguito utilizzando questi due (e lo stesso con i risultati getBoundingClientRect) non mi direbbe se la parte superiore della barra di navigazione è mai stata spostata in cima alla pagina visualizzabile (di nuovo, come riportato nella console, sono rimasti semplicemente gli stessi numeri durante lo scorrimento si è verificato).
Soluzione
La soluzione per me stava utilizzando
window.visualViewport.pageTop
Il valore della proprietà pageTop riflette la sezione visualizzabile dello schermo, quindi mi permette di tracciare dove un elemento è in riferimento ai confini dell'area visualizzabile.
Probabilmente non è necessario dirlo, ogni volta che ho a che fare con lo scorrimento, mi aspetto di utilizzare questa soluzione per rispondere programmaticamente al movimento degli elementi sottoposti a scorrimento.
Spero che aiuti qualcun altro.
NOTA IMPORTANTE: questo sembra funzionare su Chrome e Opera attualmente e sicuramente non su Firefox (6-2018) ... fino a quando Firefox non supporta VisualViewport, consiglio di NON utilizzare questo metodo (e spero che lo facciano presto ... fa molto più senso del resto).
AGGIORNAMENTO:
solo una nota relativa a questa soluzione.
Mentre trovo ancora ciò che ho scoperto essere molto prezioso per le situazioni in cui "... rispondono programmaticamente al movimento degli elementi che vengono fatti scorrere". è applicabile. La soluzione migliore per il problema che avevo era usare CSS per impostare posizione: appiccicososull'elemento. Usando sticky puoi avere un elemento rimanere in alto senza usare javascript (NOTA: ci sono volte che questo non funzionerà in modo efficace come cambiare l'elemento in fixed ma per la maggior parte degli usi l'approccio sticky sarà probabilmente superiore)
UPDATE01:
Quindi ho capito che per una pagina diversa avevo un requisito in cui dovevo rilevare la posizione di un elemento in una configurazione a scorrimento leggermente complessa (parallasse più elementi che scorrono come parte di un messaggio). Mi sono reso conto in quello scenario che quanto segue forniva il valore che ho usato per determinare quando fare qualcosa:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if(trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
Spero che questa risposta sia ora molto più utile.
L'ho fatto così, quindi era compatibile con i vecchi browser.
// For really old browser's or incompatible ones
function getOffsetSum(elem) {
var top = 0,
left = 0,
bottom = 0,
right = 0
var width = elem.offsetWidth;
var height = elem.offsetHeight;
while (elem) {
top += elem.offsetTop;
left += elem.offsetLeft;
elem = elem.offsetParent;
}
right = left + width;
bottom = top + height;
return {
top: top,
left: left,
bottom: bottom,
right: right,
}
}
function getOffsetRect(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docElem = document.documentElement;
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var clientTop = docElem.clientTop;
var clientLeft = docElem.clientLeft;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
var bottom = top + (box.bottom - box.top);
var right = left + (box.right - box.left);
return {
top: Math.round(top),
left: Math.round(left),
bottom: Math.round(bottom),
right: Math.round(right),
}
}
function getOffset(elem) {
if (elem) {
if (elem.getBoundingClientRect) {
return getOffsetRect(elem);
} else { // old browser
return getOffsetSum(elem);
}
} else
return null;
}
Maggiori informazioni sulle coordinate in JavaScript qui: http://javascript.info/tutorial/coordinates
Per ottenere l'offset totale di un elemento, è possibile riassumere ricorsivamente tutti gli offset padre:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
con questa funzione di utilità l'offset superiore totale di un elemento dom è:
el.offsetTop + getParentOffsets(el);
/**
*
* @param {HTMLElement} el
* @return {{top: number, left: number}}
*/
function getDocumentOffsetPosition(el) {
var position = {
top: el.offsetTop,
left: el.offsetLeft
};
if (el.offsetParent) {
var parentPosition = getDocumentOffsetPosition(el.offsetParent);
position.top += parentPosition.top;
position.left += parentPosition.left;
}
return position;
}
Grazie a ThinkingStiff per la risposta , questa è solo un'altra versione.
Ho usato con successo la soluzione di Andy E per posizionare un bootstrap 2 modale a seconda del collegamento in una riga della tabella su cui un utente fa clic. La pagina è una pagina di Tapestry 5 e javascript di seguito viene importato nella classe di pagine java.
javascript:
function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
offset = offset + 20;
$('#serviceLineModal').css("top", offset);
}
Il mio codice modale:
<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<t:zone t:id="modalZone" id="modalZone">
<p>You selected service line number: ${serviceLineNumberSelected}</p>
</t:zone>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<!-- <button class="btn btn-primary">Save changes</button> -->
</div>
Il collegamento nel ciclo:
<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">
<td style="white-space:nowrap;" class="add-padding-left-and-right no-border">
<a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber"
t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
onmouseover="setLinkPosition(this);">
<i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
</a>
</td>
E il codice java nella classe di pagina:
void onServiceLineNumberSelected(String number){
checkForNullSession();
serviceLineNumberSelected = number;
addOpenServiceLineDialogCommand();
ajaxResponseRenderer.addRender(modalZone);
}
protected void addOpenServiceLineDialogCommand() {
ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
@Override
public void run(JavaScriptSupport javascriptSupport) {
javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
}
});
}
Spero che questo aiuti qualcuno, questo post ha aiutato.
Dopo molte ricerche e prove questo sembra funzionare
function getPosition(e) {
var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
var x = 0, y = 0;
while (e) {
x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
e = e.offsetParent;
}
return { x: x + window.scrollX, y: y + window.scrollY };
}
Ho pensato di buttare anche questo.
Non sono stato in grado di testarlo nei browser più vecchi, ma funziona con l'ultimo dei primi 3. :)
Element.prototype.getOffsetTop = function() {
return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};
Dal momento che browser diversi rendono il bordo, il riempimento, il margine e così via in modo diverso. Ho scritto una piccola funzione per recuperare le posizioni superiore e sinistra dell'elemento specifico in ogni elemento radice che desideri in una dimensione precisa:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Per recuperare la posizione sinistra è necessario restituire:
return offsetRect.left - rootRect.left;
Ottieni la posizione del div rispetto a sinistra e in alto
var elm = $('#div_id'); //get the div
var posY_top = elm.offset().top; //get the position from top
var posX_left = elm.offset().left; //get the position from left
el.offsetTop
e el.offsetLeft
(l'OP non dice nulla su jQuery ... Non sono sicuro del perché la tua risposta usi neanche jQuery ...)