11. juni 2026

Koordinator

For at flytte elementer rundt bør vi være bekendt med koordinaterne.

De fleste JavaScript-metoder bruger en af to koordinatsystemer:

  1. Relativt til vinduet – minder om position:fixed, beregnet fra vinduets top/venstre kant.
    • vi vil betegne disse koordinater som clientX/clientY, årsagen til et sådant navn vil blive klar senere, når vi studerer event-egenskaber.
  2. Relativt til dokumentet – minder om position:absolute i dokumentets rod, beregnet fra dokumentets top/venstre kant.
    • vi vil betegne dem pageX/pageY.

Når siden rulles til begyndelsen, således at top/venstre hjørne af vinduet er præcis dokumentets top/venstre hjørne, er disse koordinater ens. Men efter at dokumentet forskydes, ændres vinduesrelative koordinater for elementer, da elementer bevæger sig hen over vinduet, mens dokumentrelative koordinater forbliver de samme.

På dette billede tager vi et punkt i dokumentet og demonstrerer dets koordinater før scrollen (venstre) og efter den (højre):

Når dokumentet er scrollet:

  • pageY – dokument-relative koordinater forbliver de samme, det beregnes fra dokumentets top (nu scrollet ud).
  • clientY – vinduesrelative koordinater ændrede sig (pilen blev kortere), da det samme punkt kom tættere på vinduets top.

Element koordinater: getBoundingClientRect

Metoden elem.getBoundingClientRect() returnerer vindueskoordinater for et minimalt rektangel, der omgiver elem som et objekt af den indbyggede DOMRect klasse.

Hoved DOMRect-egenskaber:

  • x/y – X/Y-koordinater for rektangelens oprindelse relativt til vinduet,
  • width/height – bredde/højde af rektanglet (kan være negativ).

Derudover findes afledte egenskaber:

  • top/bottom – Y-koordinater for rektangelens top/bund kant,
  • left/right – X-koordinater for rektangelens venstre/højre kant.

Klik på denne knap for at se dens vindueskoordinater:

Hvis du ruller siden og gentager, vil du bemærke, at når knapens vinduesrelative position ændres, ændres dens vindueskoordinater (y/top/bottom, hvis du ruller lodret) også.

Her er billedet af elem.getBoundingClientRect() output:

Som du kan se, beskriver x/y og width/height rektanglet fuldt ud. Afledte egenskaber kan nemt beregnes ud fra dem:

  • left = x
  • top = y
  • right = x + width
  • bottom = y + height

Bemærk venligst:

  • Koordinater kan være decimalfraktioner, såsom 10.5. Det er normalt, internt bruger browseren fraktioner i beregninger. Vi behøver ikke runde dem af, når vi sætter dem til style.left/top.
  • Koordinater kan være negative. For eksempel, hvis siden er scrollet således at elem nu er over vinduet, så er elem.getBoundingClientRect().top negativ.
Hvorfor er afledte egenskaber nødvendige? Hvorfor findes top/left hvis x/y allerede eksisterer?

Matematisk set er et rektangel entydigt defineret med dets startpunkt (x,y) og retningsvektoren (width,height). De ekstra afledte egenskaber er altså for bekvemmelighedens skyld.

Teknisk set er det muligt for width/height at være negative, hvilket muliggør et “retningsbestemt” rektangel, f.eks. til at repræsentere musevalg med korrekt markerede start- og slutpunkter.

Negative værdier for width/height betyder, at rektanglet starter ved sit nederste højre hjørne og derefter “vokser” mod venstre og opad.

Her er et rektangel med negativ width og height (f.eks. width=-200, height=-100):

Som du kan se, er left/top ikke lig med x/y i dette tilfælde.

I praksis returnerer elem.getBoundingClientRect() dog altid positive værdier for width/height. Vi nævner negative width/height kun for at hjælpe dig med at forstå, hvorfor disse tilsyneladende duplikerede egenskaber ikke er faktiske duplikater.

Internet Explorer: ingen understøttelse for x/y

Internet Explorer understøtter af historiske årsager ikke x/y egenskaberne.

Vi kan derfor enten lave en polyfill (tilføje getters i DomRect.prototype) eller blot bruge top/left, da de altid er lig med x/y for positive width/height, især i resultatet af elem.getBoundingClientRect().

Koordinaterne right/bottom er forskellige fra CSS positionsegenskaberne

Der er tydelige ligheder mellem vinduesrelative koordinater og CSS position:fixed.

Men i CSS positionering betyder right-egenskaben afstanden fra højre kant, og bottom-egenskaben betyder afstanden fra bundkanten.

Hvis vi bare ser på billedet ovenfor, kan vi se, at det ikke er sådan i JavaScript. Alle vindueskoordinater tælles fra øverste venstre hjørne, inklusive disse.

elementFromPoint(x, y)

Kaldet document.elementFromPoint(x, y) returnerer det mest indlejrede element i vindueskoordinaterne (x, y).

Syntaksen er:

let elem = document.elementFromPoint(x, y);

For eksempel fremhæver og viser koden nedenfor tagget for det element, der nu er i midten af vinduet:

let centerX = document.documentElement.clientWidth / 2;
let centerY = document.documentElement.clientHeight / 2;

let elem = document.elementFromPoint(centerX, centerY);

elem.style.background = "red";
alert(elem.tagName);

Da det bruger vindueskoordinater, kan elementet være forskelligt afhængigt af den aktuelle scrolleposition.

For koordinater uden for vinduet returnerer elementFromPoint null

Metoden document.elementFromPoint(x,y) virker kun, hvis (x,y) er inden for det synlige område.

Hvis en af koordinaterne er negativ eller overstiger vinduets bredde/højde, returneres null.

Her er en typisk fejl, der kan opstå, hvis vi ikke kontrollerer for dette:

let elem = document.elementFromPoint(x, y);
// hvis koordinaterne tilfældigvis er uden for vinduet, så er elem = null
elem.style.background = ''; // Fejl!

Brug til “fast” positionering

Langt de fleste gange har vi brug for koordinater for at placere noget.

For at vise noget nær et element kan vi bruge getBoundingClientRect til at få dets koordinater, og derefter CSS position sammen med left/top (eller right/bottom).

For eksempel viser funktionen createMessageUnder(elem, html) nedenfor beskeden under elem:

let elem = document.getElementById("coords-show-mark");

function createMessageUnder(elem, html) {
  // Opret et besked element
  let message = document.createElement('div');
  // Nok bedre at bruge en css klasse for stilen her
  message.style.cssText = "position:fixed; color: red";

  // Tildel koordinater, husk "px"!
  let coords = elem.getBoundingClientRect();

  message.style.left = coords.left + "px";
  message.style.top = coords.bottom + "px";

  message.innerHTML = html;

  return message;
}

// Anvendelse:
// tilføj den i 5 sekunder i dokumentet
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);

Prøv at trykke på knappen for at se den køre:

Koden kan ændres til at vise beskeden til venstre, højre, nedenunder, anvende CSS animationer til at “fade den ind” og så videre. Det er nemt, da vi har alle koordinater og størrelser af elementet.

Bemærk dog den vigtige detalje: når siden scroller væk, flyder beskeden væk fra knappen.

Årsagen er åbenlys: besked elementet er afhængigt af position:fixed, så det forbliver på det samme sted i vinduet, mens siden scroller væk.

For at ændre det, skal vi bruge dokumentbaserede koordinater og position:absolute.

Dokument-relative koordinater

Dokument-relative koordinater starter fra dokumentets øverste venstre hjørne, ikke vinduet.

I CSS svarer vindueskoordinater til position:fixed, mens dokumentkoordinater ligner position:absolute placeret øverst i dokumentet.

Vi kan bruge position:absolute og top/left til at placere noget et bestemt sted i dokumentet, så det forbliver der under en side scroll. Men vi har brug for de rigtige koordinater først.

Der er ingen standard metode til at få elementets dokumentkoordinater. Men det er ret nemt at skrive sig frem til dem.

De to koordinatsystemer er forbundet med formlen:

  • pageY = clientY + højden af det ud-scrollede del af dokumentet.
  • pageX = clientX + bredden af det ud-scrollede del af dokumentet.

Funktionen getCoords(elem) tager vindueskoordinaterne fra elem.getBoundingClientRect() og lægger det nuværende scroll til dem:

// Funktion til at hente dokumentkoordinaterne for et element
function getCoords(elem) {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + window.pageYOffset,
    right: box.right + window.pageXOffset,
    bottom: box.bottom + window.pageYOffset,
    left: box.left + window.pageXOffset
  };
}

Hvis vi i eksemplet ovenfor brugte position:absolute, så ville beskeden forblive nær elementet under scroll.

Den ændrede createMessageUnder funktion:

function createMessageUnder(elem, html) {
  let message = document.createElement('div');
  message.style.cssText = "position:absolute; color: red";

  let coords = getCoords(elem);

  message.style.left = coords.left + "px";
  message.style.top = coords.bottom + "px";

  message.innerHTML = html;

  return message;
}

Opsamling

Ethvert punkt på siden har koordinater:

  1. Relativt til vinduet – elem.getBoundingClientRect().
  2. Relativt til dokumentet – elem.getBoundingClientRect() plus det nuværende scroll af siden.

Vindueskoordinater er gode at bruge med position:fixed, og dokumentkoordinater virker godt med position:absolute.

Begge koordinatsystemer har deres fordele og ulemper; der er tidspunkter, hvor vi har brug for den ene eller den anden, ligesom med CSS position absolute og fixed.

Opgaver

vigtighed: 5

I iframen nedenfor kan du se et dokument med det grønne “felt”.

Brug JavaScript til at finde vindueskoordinaterne for hjørnerne, der peges på med pilene.

Der er en lille funktion implementeret i dokumentet for nemheds skyld. Et klik ethvert sted viser koordinaterne der.

Din kode skal bruge DOM til at finde vindueskoordinaterne for:

  1. Øverste venstre, ydre hjørne (det er simpelt).
  2. Nederste højre, ydre hjørne (også simpelt).
  3. Øverste venstre, indre hjørne (lidt sværere).
  4. Nederste højre, indre hjørne (der er flere måder, vælg en).

De koordinater du beregner, skal være de samme som dem, der returneres af museklikket.

P.S. Koden skal også virke, hvis elementet har en anden størrelse eller kant, der ikke er bundet til nogen faste værdier.

Åbn en sandbox til opgaven.

Ydre hjørner

Ydre hjørner er det, vi får fra elem.getBoundingClientRect().

Koordinaterne for det øverste venstre hjørne answer1 og det nederste højre hjørne answer2:

let coords = elem.getBoundingClientRect();

let answer1 = [coords.left, coords.top];
let answer2 = [coords.right, coords.bottom];

Indre øverste venstre hjørne

Det adskiller sig fra det ydre hjørne ved bredden af kanten. En pålidelig måde at få afstanden er clientLeft/clientTop:

let answer3 = [coords.left + field.clientLeft, coords.top + field.clientTop];

Nederste højre indre hjørne

I dette tilfælde skal vi trække bredden af kanten fra de ydre koordinater.

Vi kunne bruge CSS-måden:

let answer4 = [
  coords.right - parseInt(getComputedStyle(field).borderRightWidth),
  coords.bottom - parseInt(getComputedStyle(field).borderBottomWidth)
];

En alternativ måde ville være at tilføje clientWidth/clientHeight til koordinaterne for det øverste venstre hjørne.

let answer4 = [
  coords.left + elem.clientLeft + elem.clientWidth,
  coords.top + elem.clientTop + elem.clientHeight
];

Åbn løsningen i en sandbox.

vigtighed: 5

Lav en funktion positionAt(anchor, position, elem), som placerer elem, afhængig af position, i nærheden af anchor elementet.

position skal være en streng med en af 3 værdier:

  • "top" – position elem lige over anchor
  • "right" – position elem lige ved siden af anchor til højre
  • "bottom" – position elem lige under anchor

Det bruges inde i funktionen showNote(anchor, position, html), som leveres i opgavens kildekode, som opretter en “note”-element med den givne html og viser den på den givne position nær anchor.

Her er en demonstration af notes:

Åbn en sandbox til opgaven.

I denne opgave handler det mest om at udregne koordinaterne korrekt. Se kildekoden for detaljer.

Bemærk: elementerne skal være i dokumentet for at kunne læse offsetHeight og andre egenskaber. Et skjult (display:none) eller uden for dokumentet element har ingen størrelse.

Åbn løsningen i en sandbox.

vigtighed: 5

Ret løsningen fra den forrige opgave sådan at noten anvender position:absolute i stedet for position:fixed.

Dette vil forhindre at den bevæger sig væk fra elementet, når siden scroller.

Tag udgangspunkt i løsningen fra den forrige opgave.

For at teste rulningen kan du tilføje denne stil til body-tag’et: <body style="height: 2000px">

Løsningen er egentlig ret simpel:

  • Brug position:absolute i CSS i stedet for position:fixed for .note.
  • Brug funktionen getCoords() fra kapitel Koordinator til at få dokument-relative koordinater.

Åbn løsningen i en sandbox.

vigtighed: 5

Udvid den forrige opgave, Vis en note tæt på elementet (absolut): lær funktionen positionAt(anchor, position, elem) at indsætte elem indenfor anchor.

Nye værdier for position:

  • top-out, right-out, bottom-out – virker på same måde som før, de indsætter elem over/højre om/under anchor.
  • top-in, right-in, bottom-in – indsæt elem indenfor anchor: sæt den fast på den øvre/højre/nedre kant.

For eksempel:

// viser noten over blockquote
positionAt(blockquote, "top-out", note);

// viser noten indenfor blockquote, øverst
positionAt(blockquote, "top-in", note);

Resultat:

Brug kildekoden fra opgaven Vis en note tæt på elementet (absolut).

Tutorial-oversigt

Kommentarer

læs dette før du kommenterer…
  • Hvis du har forslag til forbedringer - så opret venligst et GitHub-issue eller en pull request i stedet for at kommentere.
  • Hvis du ikke forstår noget i artiklen - så uddyb venligst.
  • For at indsætte få ord kode, brug <code>-taggen, for flere linjer - omslut dem i <pre>-tag, for mere end 10 linjer - brug en sandbox (plnkr, jsbin, codepen…)