Merge branch 'master' into patch-1
This commit is contained in:
commit
482ca750a4
327 changed files with 3983 additions and 2566 deletions
|
@ -2,11 +2,11 @@
|
|||
|
||||
The JavaScript language was initially created for web browsers. Since then it has evolved and become a language with many uses and platforms.
|
||||
|
||||
A platform may be a browser, or a web-server or another *host*, even a coffee machine. Each of them provides platform-specific functionality. The JavaScript specification calls that a *host environment*.
|
||||
A platform may be a browser, or a web-server or another *host*, even a "smart" coffee machine, if it can run JavaScript. Each of them provides platform-specific functionality. The JavaScript specification calls that a *host environment*.
|
||||
|
||||
A host environment provides own objects and functions additional to the language core. Web browsers give a means to control web pages. Node.js provides server-side features, and so on.
|
||||
|
||||
Here's a bird's-eye view of what we have when JavaScript runs in a web-browser:
|
||||
Here's a bird's-eye view of what we have when JavaScript runs in a web browser:
|
||||
|
||||

|
||||
|
||||
|
@ -49,9 +49,7 @@ document.body.style.background = "red";
|
|||
setTimeout(() => document.body.style.background = "", 1000);
|
||||
```
|
||||
|
||||
Here we used `document.body.style`, but there's much, much more. Properties and methods are described in the specification:
|
||||
|
||||
- **DOM Living Standard** at <https://dom.spec.whatwg.org>
|
||||
Here we used `document.body.style`, but there's much, much more. Properties and methods are described in the specification: [DOM Living Standard](https://dom.spec.whatwg.org).
|
||||
|
||||
```smart header="DOM is not only for browsers"
|
||||
The DOM specification explains the structure of a document and provides objects to manipulate it. There are non-browser instruments that use DOM too.
|
||||
|
@ -60,9 +58,9 @@ For instance, server-side scripts that download HTML pages and process them can
|
|||
```
|
||||
|
||||
```smart header="CSSOM for styling"
|
||||
CSS rules and stylesheets are structured in a different way than HTML. There's a separate specification, [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/), that explains how they are represented as objects, and how to read and write them.
|
||||
There's also a separate specification, [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/) for CSS rules and stylesheets, that explains how they are represented as objects, and how to read and write them.
|
||||
|
||||
CSSOM is used together with DOM when we modify style rules for the document. In practice though, CSSOM is rarely required, because usually CSS rules are static. We rarely need to add/remove CSS rules from JavaScript, but that's also possible.
|
||||
CSSOM is used together with DOM when we modify style rules for the document. In practice though, CSSOM is rarely required, because we rarely need to modify CSS rules from JavaScript (usually we just add/remove CSS classes, not modify their CSS rules), but that's also possible.
|
||||
```
|
||||
|
||||
## BOM (Browser Object Model)
|
||||
|
|
|
@ -201,7 +201,7 @@ The parent is available as `parentNode`.
|
|||
|
||||
For example:
|
||||
|
||||
```js
|
||||
```js run
|
||||
// parent of <body> is <html>
|
||||
alert( document.body.parentNode === document.documentElement ); // true
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ Here we look for all `<li>` elements that are last children:
|
|||
This method is indeed powerful, because any CSS selector can be used.
|
||||
|
||||
```smart header="Can use pseudo-classes as well"
|
||||
Pseudo-classes in the CSS selector like `:hover` and `:active` are also supported. For instance, `document.querySelectorAll(':hover')` will return the collection with elements that the pointer is over now (in nesting order: from the outermost `<html>` to the most nested one).
|
||||
Pseudo-classes in the CSS selector like `:hover` and `:active` are also supported. For instance, `document.querySelectorAll(':hover')` will return the collection with elements that the pointer is over now (in nesting order: from the outermost `<html>` to the most nested one).
|
||||
```
|
||||
|
||||
## querySelector [#querySelector]
|
||||
|
@ -178,7 +178,7 @@ So here we cover them mainly for completeness, while you can still find them in
|
|||
|
||||
- `elem.getElementsByTagName(tag)` looks for elements with the given tag and returns the collection of them. The `tag` parameter can also be a star `"*"` for "any tags".
|
||||
- `elem.getElementsByClassName(className)` returns elements that have the given CSS class.
|
||||
- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. very rarely used.
|
||||
- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. Very rarely used.
|
||||
|
||||
For instance:
|
||||
```js
|
||||
|
|
|
@ -20,7 +20,7 @@ The classes are:
|
|||
|
||||
- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class. Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later.
|
||||
- [Node](http://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic ones like `Comment` for comment nodes.
|
||||
- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. A browser supports not only HTML, but also XML and SVG. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`.
|
||||
- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. A browser supports not only HTML, but also XML and SVG. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`.
|
||||
- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) -- is finally the basic class for all HTML elements. It is inherited by concrete HTML elements:
|
||||
- [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `<input>` elements,
|
||||
- [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `<body>` elements,
|
||||
|
@ -36,7 +36,7 @@ It gets properties and methods as a superposition of (listed in inheritance orde
|
|||
- `HTMLInputElement` -- this class provides input-specific properties,
|
||||
- `HTMLElement` -- it provides common HTML element methods (and getters/setters),
|
||||
- `Element` -- provides generic element methods,
|
||||
- `Node` -- provides common DOM node properties,.
|
||||
- `Node` -- provides common DOM node properties,
|
||||
- `EventTarget` -- gives the support for events (to be covered),
|
||||
- ...and finally it inherits from `Object`, so "plain object" methods like `hasOwnProperty` are also available.
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
The solution is short, yet may look a bit tricky, so here I provide it with extensive comments:
|
||||
|
||||
|
||||
```js
|
||||
let sortedRows = Array.from(table.tBodies[0].rows) // (1)
|
||||
.sort((rowA, rowB) => rowA.cells[0].innerHTML > rowB.cells[0].innerHTML ? 1 : -1); // (2)
|
||||
let sortedRows = Array.from(table.tBodies[0].rows) // 1
|
||||
.sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));
|
||||
|
||||
table.tBodies[0].append(...sortedRows); // (3)
|
||||
```
|
||||
|
@ -14,6 +13,6 @@ The step-by-step algorthm:
|
|||
2. Then sort them comparing by the content of the first `<td>` (the name field).
|
||||
3. Now insert nodes in the right order by `.append(...sortedRows)`.
|
||||
|
||||
Please note: we don't have to remove row elements, just "re-insert", they leave the old place automatically.
|
||||
We don't have to remove row elements, just "re-insert", they leave the old place automatically.
|
||||
|
||||
Also note: even if the table HTML doesn't have `<tbody>`, the DOM structure always has it. So we must insert elements as `table.tBodes[0].append(...)`: a simple `table.append(...)` would fail.
|
||||
P.S. In our case, there's an explicit `<tbody>` in the table, but even if HTML table doesn't have `<tbody>`, the DOM structure always has it.
|
||||
|
|
|
@ -1,37 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<table id="table">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Surname</th>
|
||||
<th>Age</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>John</td>
|
||||
<td>Smith</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td>
|
||||
<td>Brown</td>
|
||||
<td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td>
|
||||
<td>Lee</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th><th>Surname</th><th>Age</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>John</td><td>Smith</td><td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td><td>Brown</td><td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td><td>Lee</td><td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>...</td><td>...</td><td>...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
let sortedRows = Array.from(table.rows)
|
||||
.slice(1)
|
||||
.sort((rowA, rowB) => rowA.cells[0].innerHTML > rowB.cells[0].innerHTML ? 1 : -1);
|
||||
<script>
|
||||
let sortedRows = Array.from(table.tBodies[0].rows)
|
||||
.sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));
|
||||
|
||||
table.tBodies[0].append(...sortedRows);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
table.tBodies[0].append(...sortedRows);
|
||||
</script>
|
||||
|
|
|
@ -1,33 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<table id="table">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Surname</th>
|
||||
<th>Age</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>John</td>
|
||||
<td>Smith</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td>
|
||||
<td>Brown</td>
|
||||
<td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td>
|
||||
<td>Lee</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th><th>Surname</th><th>Age</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>John</td><td>Smith</td><td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td><td>Brown</td><td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td><td>Lee</td><td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>...</td><td>...</td><td>...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
// ... your code ...
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
// ... your code ...
|
||||
</script>
|
||||
|
|
|
@ -6,33 +6,29 @@ importance: 5
|
|||
|
||||
There's a table:
|
||||
|
||||
```html run
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Surname</th>
|
||||
<th>Age</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>John</td>
|
||||
<td>Smith</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td>
|
||||
<td>Brown</td>
|
||||
<td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td>
|
||||
<td>Lee</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>...</td>
|
||||
<td>...</td>
|
||||
<td>...</td>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th><th>Surname</th><th>Age</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>John</td><td>Smith</td><td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pete</td><td>Brown</td><td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ann</td><td>Lee</td><td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>...</td><td>...</td><td>...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
There may be more rows in it.
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ We'll create the table as a string: `"<table>...</table>"`, and then assign it t
|
|||
The algorithm:
|
||||
|
||||
1. Create the table header with `<th>` and weekday names.
|
||||
1. Create the date object `d = new Date(year, month-1)`. That's the first day of `month` (taking into account that months in JavaScript start from `0`, not `1`).
|
||||
2. First few cells till the first day of the month `d.getDay()` may be empty. Let's fill them in with `<td></td>`.
|
||||
3. Increase the day in `d`: `d.setDate(d.getDate()+1)`. If `d.getMonth()` is not yet the next month, then add the new cell `<td>` to the calendar. If that's a Sunday, then add a newline <code>"</tr><tr>"</code>.
|
||||
4. If the month has finished, but the table row is not yet full, add empty `<td>` into it, to make it square.
|
||||
2. Create the date object `d = new Date(year, month-1)`. That's the first day of `month` (taking into account that months in JavaScript start from `0`, not `1`).
|
||||
3. First few cells till the first day of the month `d.getDay()` may be empty. Let's fill them in with `<td></td>`.
|
||||
4. Increase the day in `d`: `d.setDate(d.getDate()+1)`. If `d.getMonth()` is not yet the next month, then add the new cell `<td>` to the calendar. If that's a Sunday, then add a newline <code>"</tr><tr>"</code>.
|
||||
5. If the month has finished, but the table row is not yet full, add empty `<td>` into it, to make it square.
|
||||
|
|
|
@ -28,7 +28,7 @@ Here's how it will look:
|
|||
*/!*
|
||||
```
|
||||
|
||||
That was an HTML example. Now let's create the same `div` with JavaScript (assuming that the styles are in the HTML or an external CSS file).
|
||||
That was the HTML example. Now let's create the same `div` with JavaScript (assuming that the styles are in the HTML/CSS already).
|
||||
|
||||
## Creating an element
|
||||
|
||||
|
@ -48,21 +48,28 @@ To create DOM nodes, there are two methods:
|
|||
let textNode = document.createTextNode('Here I am');
|
||||
```
|
||||
|
||||
Most of the time we need to create element nodes, such as the `div` for the message.
|
||||
|
||||
### Creating the message
|
||||
|
||||
In our case the message is a `div` with `alert` class and the HTML in it:
|
||||
Creating the message div takes 3 steps:
|
||||
|
||||
```js
|
||||
// 1. Create <div> element
|
||||
let div = document.createElement('div');
|
||||
|
||||
// 2. Set its class to "alert"
|
||||
div.className = "alert";
|
||||
|
||||
// 3. Fill it with the content
|
||||
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
|
||||
```
|
||||
|
||||
We created the element, but as of now it's only in a variable. We can't see the element on the page, as it's not yet a part of the document.
|
||||
We've created the element. But as of now it's only in a variable named `div`, not in the page yet. So we can't see it.
|
||||
|
||||
## Insertion methods
|
||||
|
||||
To make the `div` show up, we need to insert it somewhere into `document`. For instance, in `document.body`.
|
||||
To make the `div` show up, we need to insert it somewhere into `document`. For instance, into `<body>` element, referenced by `document.body`.
|
||||
|
||||
There's a special method `append` for that: `document.body.append(div)`.
|
||||
|
||||
|
@ -90,14 +97,20 @@ Here's the full code:
|
|||
</script>
|
||||
```
|
||||
|
||||
This set of methods provides more ways to insert:
|
||||
Here we called `append` on `document.body`, but we can call `append` method on any other element, to put another element into it. For instance, we can append something to `<div>` by calling `div.append(anotherElement)`.
|
||||
|
||||
- `node.append(...nodes or strings)` -- append nodes or strings at the end of `node`,
|
||||
- `node.prepend(...nodes or strings)` -- insert nodes or strings at the beginning of `node`,
|
||||
- `node.before(...nodes or strings)` –- insert nodes or strings before `node`,
|
||||
- `node.after(...nodes or strings)` –- insert nodes or strings after `node`,
|
||||
Here are more insertion methods, they specify different places where to insert:
|
||||
|
||||
- `node.append(...nodes or strings)` -- append nodes or strings *at the end* of `node`,
|
||||
- `node.prepend(...nodes or strings)` -- insert nodes or strings *at the beginning* of `node`,
|
||||
- `node.before(...nodes or strings)` –- insert nodes or strings *before* `node`,
|
||||
- `node.after(...nodes or strings)` –- insert nodes or strings *after* `node`,
|
||||
- `node.replaceWith(...nodes or strings)` –- replaces `node` with the given nodes or strings.
|
||||
|
||||
Arguments of these methods are an arbitrary list of DOM nodes to insert, or text strings (that become text nodes automatically).
|
||||
|
||||
Let's see them in action.
|
||||
|
||||
Here's an example of using these methods to add items to a list and the text before/after it:
|
||||
|
||||
```html autorun
|
||||
|
@ -121,7 +134,7 @@ Here's an example of using these methods to add items to a list and the text bef
|
|||
</script>
|
||||
```
|
||||
|
||||
Here's a visual picture what methods do:
|
||||
Here's a visual picture of what the methods do:
|
||||
|
||||

|
||||
|
||||
|
@ -139,7 +152,7 @@ before
|
|||
after
|
||||
```
|
||||
|
||||
These methods can insert multiple lists of nodes and text pieces in a single call.
|
||||
As said, these methods can insert multiple nodes and text pieces in a single call.
|
||||
|
||||
For instance, here a string and an element are inserted:
|
||||
|
||||
|
@ -150,7 +163,7 @@ For instance, here a string and an element are inserted:
|
|||
</script>
|
||||
```
|
||||
|
||||
All text is inserted *as text*.
|
||||
Please note: the text is inserted "as text", not "as HTML", with proper escaping of characters such as `<`, `>`.
|
||||
|
||||
So the final HTML is:
|
||||
|
||||
|
@ -166,7 +179,7 @@ In other words, strings are inserted in a safe way, like `elem.textContent` does
|
|||
|
||||
So, these methods can only be used to insert DOM nodes or text pieces.
|
||||
|
||||
But what if we want to insert HTML "as html", with all tags and stuff working, like `elem.innerHTML`?
|
||||
But what if we'd like to insert an HTML string "as html", with all tags and stuff working, in the same manner as `elem.innerHTML` does it?
|
||||
|
||||
## insertAdjacentHTML/Text/Element
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ For instance:
|
|||
```smart header="Computed and resolved values"
|
||||
There are two concepts in [CSS](https://drafts.csswg.org/cssom/#resolved-values):
|
||||
|
||||
1. A *computed* style value is the value after all CSS rules and CSS inheritance is applied, as the result of the CSS cascade. It can look like `height:1em` or `font-size:125%`.
|
||||
1. A *computed* style value is the value after all CSS rules and CSS inheritance is applied, as the result of the CSS cascade. It can look like `height:1em` or `font-size:125%`.
|
||||
2. A *resolved* style value is the one finally applied to the element. Values like `1em` or `125%` are relative. The browser takes the computed value and makes all units fixed and absolute, for instance: `height:20px` or `font-size:16px`. For geometry properties resolved values may have a floating point, like `width:50.5px`.
|
||||
|
||||
A long time ago `getComputedStyle` was created to get computed values, but it turned out that resolved values are much more convenient, and the standard changed.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
background-color: #00FF00;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
#ball {
|
||||
position: absolute;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
|
||||
<div id="field">
|
||||
<img src="https://js.cx/clipart/ball.svg" id="ball"> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
<img src="https://js.cx/clipart/ball.svg" height="40" width="40" id="ball"> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
</div>
|
||||
|
||||
|
@ -38,4 +38,4 @@
|
|||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -24,17 +24,22 @@ ball.style.left = Math.round(field.clientWidth / 2 - ball.offsetWidth / 2) + 'px
|
|||
ball.style.top = Math.round(field.clientHeight / 2 - ball.offsetHeight / 2) + 'px';
|
||||
```
|
||||
|
||||
**Attention: the pitfall!**
|
||||
Now the ball is finally centered.
|
||||
|
||||
````warn header="Attention: the pitfall!"
|
||||
|
||||
The code won't work reliably while `<img>` has no width/height:
|
||||
|
||||
```html
|
||||
<img src="ball.png" id="ball">
|
||||
```
|
||||
````
|
||||
|
||||
When the browser does not know the width/height of an image (from tag attributes or CSS), then it assumes them to equal `0` until the image finishes loading.
|
||||
|
||||
After the first load browser usually caches the image, and on next loads it will have the size immediately. But on the first load the value of `ball.offsetWidth` is `0`. That leads to wrong coordinates.
|
||||
So the value of `ball.offsetWidth` will be `0` until the image loads. That leads to wrong coordinates in the code above.
|
||||
|
||||
After the first load, the browser usually caches the image, and on reloads it will have the size immediately. But on the first load the value of `ball.offsetWidth` is `0`.
|
||||
|
||||
We should fix that by adding `width/height` to `<img>`:
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
|
||||
<script>
|
||||
// ball.offsetWidth=0 before image loaded!
|
||||
// ball.offsetWidth=0 before image loaded!
|
||||
// to fix: set width
|
||||
ball.style.left = Math.round(field.clientWidth / 2 - ball.offsetWidth / 2) + 'px'
|
||||
ball.style.top = Math.round(field.clientHeight / 2 - ball.offsetHeight / 2) + 'px'
|
||||
|
|
|
@ -10,7 +10,7 @@ Here's how the source document looks:
|
|||
|
||||
What are coordinates of the field center?
|
||||
|
||||
Calculate them and use to place the ball into the center of the field:
|
||||
Calculate them and use to place the ball into the center of the green field:
|
||||
|
||||
[iframe src="solution" height=180]
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ If you click the element below, the code `elem.scrollTop += 10` executes. That m
|
|||
<div onclick="this.scrollTop+=10" style="cursor:pointer;border:1px solid black;width:100px;height:80px;overflow:auto">Click<br>Me<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9</div>
|
||||
```
|
||||
|
||||
Setting `scrollTop` to `0` or `Infinity` will make the element scroll to the very top/bottom respectively.
|
||||
Setting `scrollTop` to `0` or a big value, such as `1e9` will make the element scroll to the very top/bottom respectively.
|
||||
````
|
||||
|
||||
## Don't take width/height from CSS
|
||||
|
|
|
@ -60,11 +60,11 @@ Why so? Better don't ask. These inconsistencies come from ancient times, not a "
|
|||
|
||||
## Get the current scroll [#page-scroll]
|
||||
|
||||
DOM elements have their current scroll state in `elem.scrollLeft/scrollTop`.
|
||||
DOM elements have their current scroll state in their `scrollLeft/scrollTop` properties.
|
||||
|
||||
For document scroll, `document.documentElement.scrollLeft/scrollTop` works in most browsers, except older WebKit-based ones, like Safari (bug [5991](https://bugs.webkit.org/show_bug.cgi?id=5991)), where we should use `document.body` instead of `document.documentElement`.
|
||||
|
||||
Luckily, we don't have to remember these peculiarities at all, because the scroll is available in the special properties `window.pageXOffset/pageYOffset`:
|
||||
Luckily, we don't have to remember these peculiarities at all, because the scroll is available in the special properties, `window.pageXOffset/pageYOffset`:
|
||||
|
||||
```js run
|
||||
alert('Current scroll from the top: ' + window.pageYOffset);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Outer corners
|
||||
|
||||
Outer corners are basically what we get from [elem.getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/DOM/element.getBoundingClientRect).
|
||||
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`:
|
||||
|
||||
|
|
|
@ -88,10 +88,10 @@ As you can see, `left/top` do not equal `x/y` in such case.
|
|||
In practice though, `elem.getBoundingClientRect()` always returns positive width/height, here we mention negative `width/height` only for you to understand why these seemingly duplicate properties are not actually duplicates.
|
||||
```
|
||||
|
||||
```warn header="Internet Explorer and Edge: no support for `x/y`"
|
||||
Internet Explorer and Edge don't support `x/y` properties for historical reasons.
|
||||
```warn header="Internet Explorer: no support for `x/y`"
|
||||
Internet Explorer doesn't support `x/y` properties for historical reasons.
|
||||
|
||||
So we can either make a polywill (add getters in `DomRect.prototype`) or just use `top/left`, as they are always the same as `x/y` for positive `width/height`, in particular in the result of `elem.getBoundingClientRect()`.
|
||||
So we can either make a polyfill (add getters in `DomRect.prototype`) or just use `top/left`, as they are always the same as `x/y` for positive `width/height`, in particular in the result of `elem.getBoundingClientRect()`.
|
||||
```
|
||||
|
||||
```warn header="Coordinates right/bottom are different from CSS position properties"
|
||||
|
@ -216,6 +216,8 @@ function getCoords(elem) {
|
|||
|
||||
return {
|
||||
top: box.top + window.pageYOffset,
|
||||
right: box.right + window.pageXOffset,
|
||||
bottom: box.bottom + window.pageYOffset,
|
||||
left: box.left + window.pageXOffset
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue