This commit is contained in:
Ilya Kantor 2017-02-28 12:54:48 +03:00
parent 4272b7bb13
commit 508969c13f
168 changed files with 340 additions and 10 deletions

View file

@ -0,0 +1,42 @@
# Outer corners
Outer corners are basically what we get from [elem.getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/DOM/element.getBoundingClientRect).
Coordinates of the upper-left corner `answer1` and the bottom-right corner `answer2`:
```js
let coords = elem.getBoundingClientRect();
let answer1 = [coords.left, coords.top];
let answer2 = [coords.right, coords.bottom];
```
# Left-upper inner corner
That differs from the outer corner by the border width. A reliable way to get the distance is `clientLeft/clientTop`:
```js
let answer3 = [coords.left + field.clientLeft, coords.top + field.clientTop];
```
# Right-bottom inner corner
In our case we need to substract the border size from the outer coordinates.
We could use CSS way:
```js
let answer4 = [
coords.right - parseInt(getComputedStyle(field).borderRightWidth),
coords.bottom - parseInt(getComputedStyle(field).borderBottomWidth)
];
```
An alternative way would be to add `clientWidth/clientHeight` to coordinates of the left-upper corner. That's probably even better:
```js
let answer4 = [
coords.left + elem.clientLeft + elem.clientWidth,
coords.top + elem.clientTop + elem.clientHeight
];
```

View file

@ -0,0 +1,27 @@
body {
padding: 20px 0 0 20px;
cursor: pointer;
}
#field {
overflow: hidden;
width: 200px;
height: 150px;
border-top: 10px solid black;
border-right: 10px solid gray;
border-bottom: 10px solid gray;
border-left: 10px solid black;
background-color: #00FF00;
font: 10px/1.2 monospace;
}
.triangle-right {
position: relative;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 20px solid red;
text-indent: -20px;
font: 12px/1 monospace;
}

View file

@ -0,0 +1,59 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
<script>
document.onclick = function(e) { // shows click coordinates
coords.innerHTML = e.clientX + ':' + e.clientY;
};
</script>
</head>
<body>
Click anywhere to get window coordinates.
<br> That's for testing, to check the result you get by JavaScript.
<br>
<div id="coords">(click coordinates show up here)</div>
<div id="field">
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
</div>
<div class="triangle-right" style="left:-20px;top:-176px">1</div>
<div class="triangle-right" style="left:-10px;top:-178px">3</div>
<div class="triangle-right" style="left:190px;top:-40px">4</div>
<div class="triangle-right" style="left:200px;top:-42px">2</div>
<script>
let fieldCoords = field.getBoundingClientRect();
let answer = [
[ // 1
fieldCoords.left,
fieldCoords.top
],
[ // 2
fieldCoords.right,
fieldCoords.bottom
],
[ // 3
fieldCoords.left + field.clientLeft,
fieldCoords.top + field.clientTop
],
[ // 4
fieldCoords.left + field.clientLeft + field.clientWidth,
fieldCoords.top + field.clientTop + field.clientHeight
]
];
alert(answer.join(' '));
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
body {
padding: 20px 0 0 20px;
cursor: pointer;
}
#field {
overflow: hidden;
width: 200px;
height: 150px;
border-top: 10px solid black;
border-right: 10px solid gray;
border-bottom: 10px solid gray;
border-left: 10px solid black;
background-color: #00FF00;
font: 10px/1.2 monospace;
}
.triangle-right {
position: relative;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 20px solid red;
text-indent: -20px;
font: 12px/1 monospace;
}

View file

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
<script>
document.onclick = function(e) { // shows click coordinates
coords.innerHTML = e.clientX + ':' + e.clientY;
};
</script>
</head>
<body>
Click anywhere to get window coordinates.
<br> That's for testing, to check the result you get by JavaScript.
<br>
<div id="coords">(click coordinates show up here)</div>
<div id="field">
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
</div>
<div class="triangle-right" style="left:-20px;top:-176px">1</div>
<div class="triangle-right" style="left:-10px;top:-178px">3</div>
<div class="triangle-right" style="left:190px;top:-40px">4</div>
<div class="triangle-right" style="left:200px;top:-42px">2</div>
<script>
// ...your code...
</script>
</body>
</html>

View file

@ -0,0 +1,24 @@
importance: 5
---
# Find window coordinates of the field
In the iframe below you can see a document with the green "field".
Use JavaScript to find window coordinates of corners pointed by with arrows.
There's a small feature implemented in the document for convenience. A click at any place shows coordinates there.
[iframe border=1 height=360 src="source" link edit]
Your code should use DOM to get window coordinates of:
1. Left-upper outer corner (that's simple).
2. Right-bottom outer corner (simple too).
3. Left-upper inner corner (a bit harder).
4. Right-bottom inner corner (there are several ways, choose one).
The coordinates that you calculate should be the same as those returned by the mouse click.
P.S. The code should also work if the element has another size or border, not bound to any fixed values.

View file

@ -0,0 +1,4 @@
In this task we only need to accuracely calculate the coorindates. See the code for details.
Please note: the elements must be in the document to read `offsetHeight` and other properties.
A hidden (`display:none`) or out of the document element has no size.

View file

@ -0,0 +1,28 @@
.note {
position: fixed;
z-index: 1000;
padding: 5px;
border: 1px solid black;
background: white;
text-align: center;
font: italic 14px Georgia;
}
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 0 0 0 100px;
padding: .5em 10px;
quotes: "\201C""\201D""\2018""\2019";
display: inline-block;
white-space: pre;
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: .1em;
margin-right: .25em;
vertical-align: -.4em;
}

View file

@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<blockquote>
Teacher: Why are you late?
Student: There was a man who lost a hundred dollar bill.
Teacher: That's nice. Were you helping him look for it?
Student: No. I was standing on it.
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<script>
/**
* Positions elem relative to anchor as said in position.
*
* @param {Node} anchor Anchor element for positioning
* @param {string} position One of: top/right/bottom
* @param {Node} elem Element to position
*
* Both elements: elem and anchor must be in the document
*/
function positionAt(anchor, position, elem) {
let anchorCoords = anchor.getBoundingClientRect();
switch (position) {
case "top":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top - elem.offsetHeight + "px";
break;
case "right":
elem.style.left = anchorCoords.left + anchor.offsetWidth + "px";
elem.style.top = anchorCoords.top + "px";
break;
case "bottom":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top + anchor.offsetHeight + "px";
break;
}
}
/**
* Shows a note with the given html at the given position
* relative to the anchor element.
*/
function showNote(anchor, position, html) {
let note = document.createElement('div');
note.className = "note";
note.innerHTML = html;
document.body.append(note);
positionAt(anchor, position, note);
}
// test it
let blockquote = document.querySelector('blockquote');
showNote(blockquote, "top", "note above");
showNote(blockquote, "right", "note at the right");
showNote(blockquote, "bottom", "note below");
</script>
</body>
</html>

View file

@ -0,0 +1,28 @@
.note {
position: fixed;
z-index: 1000;
padding: 5px;
border: 1px solid black;
background: white;
text-align: center;
font: italic 14px Georgia;
}
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 0 0 0 100px;
padding: .5em 10px;
quotes: "\201C""\201D""\2018""\2019";
display: inline-block;
white-space: pre;
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: .1em;
margin-right: .25em;
vertical-align: -.4em;
}

View file

@ -0,0 +1,57 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<blockquote>
Teacher: Why are you late?
Student: There was a man who lost a hundred dollar bill.
Teacher: That's nice. Were you helping him look for it?
Student: No. I was standing on it.
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<script>
/**
* Positions elem relative to anchor as said in position.
*
* @param {Node} anchor Anchor element for positioning
* @param {string} position One of: top/right/bottom
* @param {Node} elem Element to position
*
* Both elements: elem and anchor must be in the document
*/
function positionAt(anchor, position, elem) {
// ... your code ...
}
/**
* Shows a note with the given html at the given position
* relative to the anchor element.
*/
function showNote(anchor, position, html) {
// ... your code ...
}
// test it
let blockquote = document.querySelector('blockquote');
showNote(blockquote, "top", "note above");
showNote(blockquote, "right", "note at the right");
showNote(blockquote, "bottom", "note below");
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
importance: 5
---
# Show a note near the element
Create a function `positionAt(anchor, position, elem)` that positions `elem`, depending on `position` either at the top (`"top"`), right (`"right"`) or bottom (`"bottom"`) of the element `anchor`.
Use it to make a function `showNote(anchor, position, html)` that shows an element with the class `"note"` and the text `html` at the given position near the anchor.
Show the notes like here:
[iframe src="solution" height="350" border="1" link]
P.S. The note should have `position:fixed` for this task.

View file

@ -0,0 +1,4 @@
The solution is actually pretty simple:
- Use `position:absolute` in CSS instead of `position:fixed` for `.note`.
- Usee the function [getCoords()](info:coordinates#getCoords) from the chapter <info:coordinates> to get document-relative coordinates.

View file

@ -0,0 +1,28 @@
.note {
position: absolute;
z-index: 1000;
padding: 5px;
border: 1px solid black;
background: white;
text-align: center;
font: italic 14px Georgia;
}
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 0 0 0 100px;
padding: .5em 10px;
quotes: "\201C""\201D""\2018""\2019";
display: inline-block;
white-space: pre;
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: .1em;
margin-right: .25em;
vertical-align: -.4em;
}

View file

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
</head>
<body style="height: 2000px">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<blockquote>
Teacher: Why are you late?
Student: There was a man who lost a hundred dollar bill.
Teacher: That's nice. Were you helping him look for it?
Student: No. I was standing on it.
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<script>
function getCoords(elem) {
let box = elem.getBoundingClientRect();
return {
top: box.top + pageYOffset,
left: box.left + pageXOffset
};
}
function positionAt(anchor, position, elem) {
let anchorCoords = getCoords(anchor);
switch (position) {
case "top":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top - elem.offsetHeight + "px";
break;
case "right":
elem.style.left = anchorCoords.left + anchor.offsetWidth + "px";
elem.style.top = anchorCoords.top + "px";
break;
case "bottom":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top + anchor.offsetHeight + "px";
break;
}
}
function showNote(anchor, position, html) {
let note = document.createElement('div');
note.className = "note";
note.innerHTML = html;
document.body.append(note);
positionAt(anchor, position, note);
}
// test it
let blockquote = document.querySelector('blockquote');
showNote(blockquote, "top", "note above");
showNote(blockquote, "right", "note at the right");
showNote(blockquote, "bottom", "note below");
</script>
</body>
</html>

View file

@ -0,0 +1,11 @@
importance: 5
---
# Show a note near the element (absolute)
Modify the solution of the [previous task](info:task/position-at) so that the note uses `position:absolute` instead of `position:fixed`.
That will prevent its "runaway" from the element when the page scrolls.
Take the solution of that task as a starting point. To test the scroll, add the style `<body style="height: 2000px">`.

View file

@ -0,0 +1,29 @@
.note {
position: absolute;
z-index: 1000;
padding: 5px;
border: 1px solid black;
background: white;
text-align: center;
font: italic 14px Georgia;
opacity: .8;
}
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 0 0 0 100px;
padding: .5em 10px;
quotes: "\201C""\201D""\2018""\2019";
display: inline-block;
white-space: pre;
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: .1em;
margin-right: .25em;
vertical-align: -.4em;
}

View file

@ -0,0 +1,94 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
</head>
<body style="height: 2000px">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<blockquote>
Teacher: Why are you late?
Student: There was a man who lost a hundred dollar bill.
Teacher: That's nice. Were you helping him look for it?
Student: No. I was standing on it.
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit sint atque dolorum fuga ad incidunt voluptatum error fugiat animi amet! Odio temporibus nulla id unde quaerat dignissimos enim nisi rem provident molestias sit tempore omnis recusandae
esse sequi officia sapiente.</p>
<script>
function getCoords(elem) {
let box = elem.getBoundingClientRect();
return {
top: box.top + pageYOffset,
left: box.left + pageXOffset
};
}
function showNote(anchor, position, html) {
var note = document.createElement('div');
note.className = "note";
note.innerHTML = html;
document.body.append(note);
positionAt(anchor, position, note);
}
function positionAt(anchor, position, elem) {
let anchorCoords = getCoords(anchor);
switch (position) {
case "top-out":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top - elem.offsetHeight + "px";
break;
case "right-out":
elem.style.left = anchorCoords.left + anchor.offsetWidth + "px";
elem.style.top = anchorCoords.top + "px";
break;
case "bottom-out":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top + anchor.offsetHeight + "px";
break;
case "top-in":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top + "px";
break;
case "right-in":
elem.style.width = '150px';
elem.style.left = anchorCoords.left + anchor.offsetWidth - elem.offsetWidth + "px";
elem.style.top = anchorCoords.top + "px";
break;
case "bottom-in":
elem.style.left = anchorCoords.left + "px";
elem.style.top = anchorCoords.top + anchor.offsetHeight - elem.offsetHeight + "px";
break;
}
}
let blockquote = document.querySelector('blockquote');
showNote(blockquote, "top-in", "note top-in");
showNote(blockquote, "top-out", "note top-out");
showNote(blockquote, "right-out", "note right-out");
showNote(blockquote, "bottom-in", "note bottom-in");
</script>
</body>
</html>

View file

@ -0,0 +1,28 @@
importance: 5
---
# Position the note inside (absolute)
Extend the previous task <info:task/position-at-absolute>: teach the function `positionAt(anchor, position, elem)` to insert `elem` inside the `anchor`.
New values for `position`:
- `top-out`, `right-out`, `bottom-out` -- work the same as before, they insert the `elem` over/right/under `anchor`.
- `top-in`, `right-in`, `bottom-in` -- insert `elem` inside the `anchor`: stick it to the upper/right/bottom edge.
For instance:
```js
// shows the note above blockquote
positionAt(blockquote, "top-out", note);
// shows the note inside blockquote, at the top
positionAt(blockquote, "top-in", note);
```
The result:
[iframe src="solution" height="310" border="1" link]
As the source code, take the solution of the task <info:task/position-at-absolute>.

View file

@ -0,0 +1,208 @@
# Coordinates
To move elements around we should be familiar with coordinates.
Most JavaScript methods deal with one of two coordinate systems:
1. Relative to the window top/left.
2. Relative to the document top/left.
It's important to understand the difference and which type is where.
[cut]
## Window coordinates: getBoundingClientRect
Window coordinates start at the left-upper corner of the window.
The method `elem.getBoundingClientRect()` returns window coordinates for `elem` as an object with properties:
- `top` -- Y-coordinate for the top element edge,
- `left` -- X-coordinate for the left element edge,
- `right` -- X-coordinate for the right element edge,
- `bottom` -- Y-coordinate for the bottom element edge.
Like this:
![](coords.png)
Window coordinates do not take the scrolled out part of the document into account, they are calculated from the "window itself".
In other words, when we scroll the page, the element goes up or down and *its window coordinates change*. That's kind of important.
```online
Click the button to see its window coordinates:
<input id="brTest" type="button" value="Show button.getBoundingClientRect() for this button" onclick='showRect(this)'/>
<script>
function showRect(elem) {
let r = elem.getBoundingClientRect();
alert("{top:"+r.top+", left:"+r.left+", right:"+r.right+", bottom:"+ r.bottom + "}");
}
</script>
If you scroll the page, the button position changes, and window coordinates as well.
```
Also:
- Coordinates may be decimal fractions. That's normal, internally browser uses them for calculations. We don't have to round them when setting to `style.position.left/top` etc.
- Coordinates may be negative. For instance, if the page is scrolled down and its top edge is above the window then `elem.getBoundingClientRect().top` is negative.
- Some browsers also add to the result `getBoundingClientRect` properties `width` and `height`. We could also get the same by the substraction: `height=bottom-top`, `width=right-left`.
```warn header="Coordinates right/bottom are different from CSS properties"
If we compare window coordinates vs CSS positioning, then they are closest to `position:fixed` -- the position relative to the viewport.
But in CSS the `right` property means the distance from the right edge, and the `bottom` -- from the bottom edge.
If we just look at the picture below, we can see that in JavaScript it is not so. All window coordinates are counted from the upper-left corner, including these ones.
```
## elementFromPoint(x, y) [#elementFromPoint]
The call to `document.elementFromPoint(x, y)` returns the most nested element at window coordinates `(x, y)`.
The syntax is:
```js
let elem = document.elementFromPoint(x, y);
```
For instance, the code below highlights and outputs the tag of the element that is now in the middle of the window:
```js run
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);
```
As it uses window coordinates, the element may be different depending on the current scroll position.
````warn header="For out-of-window coordinates the `elementFromPoint` returns `null`"
The method `document.elementFromPoint(x,y)` only works if `(x,y)` are inside the visible area.
If any of the coordinates is negative or exceeds the window width/height, then it returns `null`.
In most cases such behavior is not a problem, but we should keep that in mind.
Here's a typical error that may occur if we don't check for it:
```js
let elem = document.elementFromPoint(x, y);
// if the coordinates happen to be out of the window, then elem = null
*!*
elem.style.background = ''; // Error!
*/!*
```
````
## Usage for position:fixed
Most of time we need coordinates to position something. In CSS to position an element relative to the viewport we use `position:fixed` together with the coorinates, usually `left/top`.
For instance, the function `createMessageUnder(elem, html)` below shows the message under `elem`:
```js
let elem = document.getElementById("coords-show-mark");
function createMessageUnder(elem, html) {
// create message element
let message = document.createElement('div');
// better to use a css class for the style here
message.style.cssText = "position:fixed; color: red";
*!*
// assign coordinates, don't forget "px"!
let coords = elem.getBoundingClientRect();
message.style.left = coords.left + "px";
message.style.top = coords.bottom + "px";
*/!*
message.innerHTML = html;
return message;
}
// Usage:
// add it for 5 seconds in the document
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);
```
```online
Click the button to run it:
<button id="coords-show-mark">Button with id="coords-show-mark", the message will appear under it</button>
```
The code can be modified to show the message at the left, right, below, apply CSS animations to "fade it in" and so on.
**But note the important detail: when the page is scrolled, the message flows away from the button.**
The reason is obvious: the message element uses `position: fixed`, so it remains at the same place while the page scrolls away.
To change that, we need to use document-based coordinates. We'll cover them in the next chapter.
## Document coordinates
Document-relative coordinates start from the left-upper corner of the document, not the window.
In CSS, window coordinates correspond to `position:fixed`, while document coordinates are similar to `position:absolute` (out of other positioned elements, of course).
We need document coordinates to stick something at a certain place of the document, so that it remains there during a page scroll.
For clarity we'll call window coordinates `(clientX,clientY)` and document coordinates `(pageX,pageY)`.
When the page is not scrolled, then window coordinate and document coordinates are actually the same. Their zero points match too:
![](document-window-coordinates-zero.png)
And if we scroll it, then `(clientX,clientY)` change, because they are relative to the window, but `(pageX,pageY)` remain the same.
Here's the same page after the vertical scroll.
- `clientY` becomes `0`, because the element is now on window top.
- `clientX` doesn't change, we didn't scroll horizontally.
- `pageX` and `pageY` remain the same, because they are relative to the *document*.
![](document-window-coordinates-scroll.png)
## Getting document coordinates [#getCoords]
There's no standard method to get document coordinates. But it's easy to write it.
The two coordinate systems are connected by the formula:
- `pageY = clientY + current vertical scroll`.
- `pageX = clientX + current horizontal scroll`.
Our function `getCoords(elem)` will take window coordinates from `elem.getBoundingClientRect()` and add the current scroll to them.
```js
function getCoords(elem) {
let box = elem.getBoundingClientRect();
return {
top: box.top + pageYOffset,
left: box.left + pageXOffset
};
}
```
## Summary
Any point on the page has coordinates:
1. Relative to the window -- `elem.getBoundingClientRect()`.
2. Relative to the document -- `elem.getBoundingClientRect()` plus the current scroll.
Window coordinates are great to use with `position:fixed`, and document coordinates do well with `position:absolute`.
Both coordinate systems have their "pro" and "contra", there are times we need one or the other one, just like CSS `position`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

View file

@ -0,0 +1,27 @@
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('coords-show-mark').onclick = function() {
let elem = document.getElementById("coords-show-mark");
function createMessageUnder(elem, text) {
let coords = elem.getBoundingClientRect();
let message = document.createElement('div');
message.style.cssText = "position:fixed; color: red";
message.style.left = coords.left + "px";
message.style.top = coords.bottom + "px";
message.innerHTML = text;
return message;
}
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);
}
});
</script>