diff --git a/14_dom.md b/14_dom.md index 0b058553..837d630c 100644 --- a/14_dom.md +++ b/14_dom.md @@ -1,10 +1,8 @@ -# The Document Object Model +# 文档对象模型 -{{quote {author: "Friedrich Nietzsche", title: "Beyond Good and Evil", chapter: true} +{{quote {author: "弗德里克·尼采", title: "善恶的彼岸", chapter: true} -Too bad! Same old story! Once you've finished building your house you -notice you've accidentally learned something that you really should -have known—before you started. +糟糕透了!又是老掉牙的那一套!盖完自家房子之后,发现不经意间学到的一点东西,其实是 —— 在动工之前就应该知晓的。 quote}} @@ -12,209 +10,124 @@ quote}} {{index drawing, parsing}} -When you open a web page in your browser, the browser retrieves the -page's ((HTML)) text and parses it, much like the way our parser from -[Chapter ?](language#parsing) parsed programs. The browser builds up a -model of the document's ((structure)) and uses this model to draw the -page on the screen. - +当你在浏览器中打开一个网页时,浏览器会获取该网页的 ((HTML)) 文本并对其进行解析,就像 [第十二章](language#parsing) 提到的解析器解析程序那样。浏览器会构建一个文档的 ((结构)) 的模型,并用该模型在屏幕上渲染出页面。 {{index "live data structure"}} -This representation of the ((document)) is one of the toys that a -JavaScript program has available in its ((sandbox)). It is a ((data -structure)) that you can read or modify. It acts as a _live_ data -structure: when it's modified, the page on the screen is updated to -reflect the changes. +这种对((文档))的表示是 JavaScript 程序在其 ((沙盒)) 中已有的工具之一。它是你可以读取或更改的 ((数据结构)),而且该数据结构是 _动态_ 的:当它被修改时,屏幕上的页面会被更新,将变化反映出来。 -## Document structure +## 文档结构 {{index [HTML, structure]}} -You can imagine an HTML document as a nested set of ((box))es. -Tags such as `
` and `` enclose other ((tag))s, which in -turn contain other tags or ((text)). Here's the example document from -the [previous chapter](browser): +你可以将 HTML 文档想像成一些嵌套的((盒子))。诸如 `` 和 `` 之类的标签会将其他 ((标签)) 包围起来,而被包起来的标签内部还可以包含其他标签或 ((文本))。以下是 [上一章](browser) 出现过的示例文档: ```{lang: "text/html", sandbox: "homepage"} -Hello, I am Marijn and this is my home page.
-I also wrote a book! Read it - here.
+你好,我是 Marijn,这是我的主页哦。
+我还写了一本书!来 + 这里阅读吧!
``` -This page has the following structure: +该页面的结构如下所示: {{figure {url: "img/html-boxes.svg", alt: "HTML document as nested boxes", width: "7cm"}}} {{indexsee "Document Object Model", DOM}} -The data structure the browser uses to represent the document follows -this shape. For each box, there is an object, which we can -interact with to find out things such as what HTML tag it represents -and which boxes and text it contains. This representation is called -the _Document Object Model_, or ((DOM)) for short. +浏览器用于表示文档的数据结构有这样的形状。每一个盒子对应一个对象,我们可以和这些对象交互并找出它们所表示的 HTML 标签以及其包含的盒子和文本。这种表示方法被称之为 _文档对象模型(Document Object Model)_,或简称 ((DOM))。 {{index "documentElement property", "head property", "body property", "html (HTML tag)", "body (HTML tag)", "head (HTML tag)"}} -The global binding `document` gives us access to these objects. Its -`documentElement` property refers to the object representing the -`` tag. Since every HTML document has a head and a body, it also -has `head` and `body` properties, pointing at those elements. +名为 `document` 的全局绑定让我们得以访问这些对象。这个绑定的 `documentElement` 属性引用了表示 `` 标签的对象。由于每份 HTML 文档都有一个头部和主体,该对象也有 `head` 和 `body` 属性,分别指向这些元素。 -## Trees +## 树 {{index [nesting, "of objects"]}} -Think back to the ((syntax tree))s from [Chapter ?](language#parsing) -for a moment. Their structures are strikingly similar to the structure -of a browser's document. Each _((node))_ may refer to other nodes, -_children_, which in turn may have their own children. This shape is -typical of nested structures where elements can contain subelements -that are similar to themselves. +让我们回顾一下 [第十二章](language#parsing) 中的((句法树))。句法树的结构与浏览器文档的结构非常相似,每个 _((节点))_ 可以引用其他作为其 _children_ 的节点,而这些节点也可能有它们自己的子节点。这是在嵌套结构中很典型的树形状,元素可以包含与自身相似的子元素。 {{index "documentElement property", [DOM, tree]}} -We call a data structure a _((tree))_ when it has a branching -structure, has no ((cycle))s (a node may not contain itself, directly -or indirectly), and has a single, well-defined _((root))_. In the case -of the DOM, `document.documentElement` serves as the root. +如果一种数据结构有分杈结构、没有((环路))(一个节点不能直接或间接地包含它本身),且有一个单一的、定义明确的 ((根节点)),那么我们将其称之为树。就 DOM 而言,`document.documentElement` 就是它的根节点。 {{index sorting, ["data structure", "tree"], "syntax tree"}} -Trees come up a lot in computer science. In addition to representing -recursive structures such as HTML documents or programs, they are -often used to maintain sorted ((set))s of data because elements can -usually be found or inserted more efficiently in a tree than in a flat -array. +树在计算机科学中相当常见。树不仅被用于表示诸如 HTML 文档和程序之类的递归结构,它们还常被用于维护数据的有序((集合)),因为在树中查找和插入元素通常比在平铺的数组中更有效率。 {{index "leaf node", "Egg language"}} -A typical tree has different kinds of ((node))s. The syntax tree for -[the Egg language](language) had identifiers, values, and application -nodes. Application nodes may have children, whereas identifiers and -values are _leaves_, or nodes without children. +典型的树结构中有不同种类的 ((节点))。[Egg 语言](language) 的句法树拥有标识器节点、值节点、应用节点。应用节点可能含有子节点,而标识器节点和值节点是 _叶_,即没有子节点的节点。 {{index "body property", [HTML, structure]}} -The same goes for the DOM. Nodes for _((element))s_, which represent -HTML tags, determine the structure of the document. These can have -((child node))s. An example of such a node is `document.body`. Some of -these children can be ((leaf node))s, such as pieces of ((text)) or -((comment)) nodes. +在 DOM 中也是如此。用于表示 HTML 标签的 _((元素))_ 节点决定了文档的结构。它们可以拥有((子节点))。这类节点中的一个例子是 `document.body`。该元素节点的一些子节点可以是 ((叶节点)),比如说((文本))段落或((注释))节点。 {{index "text node", element, "ELEMENT_NODE code", "COMMENT_NODE code", "TEXT_NODE code", "nodeType property"}} -Each DOM node object has a `nodeType` property, which contains a code -(number) that identifies the type of node. Elements have code 1, which -is also defined as the constant property `Node.ELEMENT_NODE`. Text -nodes, representing a section of text in the document, get code 3 -(`Node.TEXT_NODE`). Comments have code 8 -(`Node.COMMENT_NODE`). +每个 DOM 节点对象都有一个名为 `nodeType` 的属性,该属性包含了标识节点类型的(数字)号码。元素节点的类型号码为 1,该号码也被定义为常量属性 `Node.ELEMENT_NODE`。文本节点用于表示文档中的一部分文本,它们的号码为 3(`Node.TEXT_NODE`)。注释的号码为 8(`Node.COMMENT_NODE`)。 -Another way to visualize our document ((tree)) is as follows: +我们可以用下列视觉的方法来呈现文档((树)): {{figure {url: "img/html-tree.svg", alt: "HTML document as a tree",width: "8cm"}}} -The leaves are text nodes, and the arrows indicate parent-child -relationships between nodes. +叶子表示文本节点,而箭头指明了节点之间的父子关系。 {{id standard}} -## The standard +## 标准 {{index "programming language", [interface, design], [DOM, interface]}} -Using cryptic numeric codes to represent node types is not a very -JavaScript-like thing to do. Later in this chapter, we'll see that -other parts of the DOM interface also feel cumbersome and alien. -The reason for this is that the DOM wasn't designed for just -JavaScript. Rather, it tries to be a language-neutral interface -that can be used in other systems as well—not just for HTML but also -for ((XML)), which is a generic ((data format)) with an HTML-like -syntax. +使用号码来表示节点类型在 JavaScript 中并不常见。在这章节的稍后内容中,我们会看到 DOM 接口其他不常见的部分。造成这种局面的原因在于 DOM 并不是专为 JavaScript 而设计的。相反地,它想要成为也能被其他系统使用的语言中立的接口 —— 并不只适用于 HTML, 也适用于 ((XML)),XML 是句法类似 HTML 的泛型((数据格式))。 {{index consistency, integration}} -This is unfortunate. Standards are often useful. But in this case, the -advantage (cross-language consistency) isn't all that compelling. -Having an interface that is properly integrated with the language you -are using will save you more time than having a familiar interface -across languages. +这样的局面有点尴尬,因为标准通常是有益的。但是在 DOM 这里,它的优势(跨语言一致性)并不是非常打动人。相较于为多种语言提供相似的接口,拥有一个与你正在使用的语言集成完善的接口会为你节省更多的时间。 {{index "array-like object", "NodeList type"}} -As an example of this poor integration, consider the `childNodes` -property that element nodes in the DOM have. This property holds an -array-like object, with a `length` property and properties labeled by -numbers to access the child nodes. But it is an instance of the -`NodeList` type, not a real array, so it does not have methods such as -`slice` and `map`. +举一个体现这种糟糕集成的例子,就拿 DOM 中元素节点所拥有的 `childNodes` 属性来说,这个属性含有一个类数组对象、 `length` 属性,还有可访问子节点的数字标签属性。然而,它是一个 `NodeList` 类型的实例,并不是真的数组,所以没有诸如 `slice` 或 `map` 这样的方法。 {{index [interface, design], [DOM, construction], "side effect"}} -Then there are issues that are simply poor design. For example, there -is no way to create a new node and immediately add children or -((attribute))s to it. Instead, you have to first create it and then add -the children and attributes one by one, using side effects. Code that -interacts heavily with the DOM tends to get long, repetitive, and -ugly. +然后,有的问题单纯是出于糟糕的设计。比如说,我们无法在创建新节点的同时马上为其添加子节点或((属性))。相反地,你必须先创建节点,然后使用副作用往里面逐个添加子节点和属性。大量与 DOM 进行交互的代码通常会变得很长、重复而且不美观。 {{index library}} -But these flaws aren't fatal. Since JavaScript allows us to create our -own ((abstraction))s, it is possible to design improved ways to -express the operations you are performing. Many libraries intended for -browser programming come with such tools. +但这些问题并不致命。由于 JavaScript 允许我们创建自己的((抽象)),我们可以设计出表示对 DOM 操作的更好的方式。许多适用于浏览器编程的库都含有这样的工具。 -## Moving through the tree +## 顺树而行 {{index pointer}} -DOM nodes contain a wealth of ((link))s to other nearby nodes. The -following diagram illustrates these: +DOM 节点含有好多通往其他邻近节点的((链接))。如下列图案所示: {{figure {url: "img/html-links.svg", alt: "Links between DOM nodes",width: "6cm"}}} {{index "child node", "parentNode property", "childNodes property"}} -Although the diagram shows only one link of each type, every node has -a `parentNode` property that points to the node it is part of, if any. -Likewise, every element node (node type 1) has a `childNodes` property -that points to an ((array-like object)) holding its children. +虽然在图案中每种链接只显示了一次,每个节点其实都有一个 `parentNode` 属性,指向当前节点所属的父节点(如果有的话)。与之类似的是,每一个(节点类型号码为 1 的)元素节点都有名为 `childNodes` 的属性,该属性指向一个含有其子节点的((类数组的对象))。 {{index "firstChild property", "lastChild property", "previousSibling property", "nextSibling property"}} -In theory, you could move anywhere in the tree using just these parent -and child links. But JavaScript also gives you access to a number of -additional convenience links. The `firstChild` and `lastChild` -properties point to the first and last child elements or have the -value `null` for nodes without children. Similarly, `previousSibling` -and `nextSibling` point to adjacent nodes, which are nodes with the -same parent that appear immediately before or after the node itself. -For a first child, `previousSibling` will be null, and for a last -child, `nextSibling` will be null. +从理论上来说,你可以单单使用这些父链接和子链接移动到树的任何部位。然而 JavaScript 为此提供了一些额外的易用链接。名为 `firstChild` 和 `lastChild` 的属性分别指向首个子节点和最后一个子节点,在没有子节点的情况下值为 `null`。同样,名为 `previousSibling` 和 `nextSibling` 的属性分别指向一个节点的前后相邻节点,即拥有相同父节点的前一个节点和后一个节点。对于第一个子节点来说,`previousSibling` 的值是 `null`。对于最后一个子节点来说,`nextSibling` 的值是 `null`。 {{index "children property", "text node", element}} -There's also the `children` property, which is like `childNodes` but -contains only element (type 1) children, not other types of -child nodes. This can be useful when you aren't interested in text -nodes. +文档对象模型中也存在 `children` 属性,该属性与 `childNodes` 相像,但是只包含元素(类型号码为1)子节点,不含其他类型的子节点。当你不需要搜寻文本节点的时候,该属性可能很有用。 {{index "talksAbout function", recursion, [nesting, "of objects"]}} -When dealing with a nested data structure like this one, recursive -functions are often useful. The following function scans a document -for ((text node))s containing a given string and returns `true` when -it has found one: +通常在处理像这样的嵌套数据结构时,递归函数会很有用。下列函数在文档中扫描含有指定字符串的((文本节点)),并且在找到的时候返回 `true`: {{id talksAbout}} @@ -238,36 +151,21 @@ console.log(talksAbout(document.body, "book")); {{index "childNodes property", "array-like object", "Array.from function"}} -Because `childNodes` is not a real array, we cannot loop over it with -`for`/`of` and have to run over the index range using a regular `for` -loop or use `Array.from`. +由于 `childNodes` 并不是真正的数组,我们不能以 `for` 或者 `of` 遍历它,而是需要用常规的 `for` 循环或 `Array.from` 来遍历索引范围。 {{index "nodeValue property"}} -The `nodeValue` property of a text node holds the string of text that -it represents. +文本节点的 `nodeValue` 属性存有它所表示的文本的字符串。 -## Finding elements +## 查找元素 {{index [DOM, querying], "body property", "hard-coding", [whitespace, "in HTML"]}} -Navigating these ((link))s among parents, children, and siblings is -often useful. But if we want to find a specific node in the document, -reaching it by starting at `document.body` and following a fixed path -of properties is a bad idea. Doing so bakes assumptions into our -program about the precise structure of the document—a structure you -might want to change later. Another complicating factor is that text -nodes are created even for the whitespace between nodes. The -example document's `` tag does not have just three children (`` elements) but actually has seven: those three, plus the -spaces before, after, and between them. + 在父节点、子节点以及相邻节点的((链接))中游走通常是实用的。然而,当我们想要在文档中找寻一个特定的节点的时候,以 `document.body` 为起点根据属性沿着固定的路线找寻实非良策。因为这么做的前提是假设我们已经知道了文档的准确结构 —— 文档的结构随后可能发生改变。另一个使之复杂化的因素在于,DOM 会为不同节点之间的空白字符也创建文本节点。之前的示例文档可不单有三个子节点(一个 `
` 元素)而已, 而是有七个子节点:这三个子节点,以及它们前后及元素之间的空格。 {{index "search problem", "href attribute", "getElementsByTagName method"}} -So if we want to get the `href` attribute of the link in that -document, we don't want to say something like "Get the second child of -the sixth child of the document body". It'd be better if we could say -"Get the first link in the document". And we can. +因此,如果我们想要获取该文档中链接的 `href` 属性,我们并不想说 “获取文档主体元素的第六个子节点的第二个子节点”。更好的方法是直接说 “获取文档中的第一个链接”,而我们确实可以这样做。 ```{sandbox: "homepage"} let link = document.body.getElementsByTagName("a")[0]; @@ -276,15 +174,11 @@ console.log(link.href); {{index "child node"}} -All element nodes have a `getElementsByTagName` method, which collects -all elements with the given tag name that are descendants (direct or -indirect children) of that node and returns them as an ((array-like -object)). +所有的元素节点都有名为 `getElementsByTagName` 的方法,该方法从所有的子嗣节点(直接或间接的子节点)收集含有给定标签名的节点,并且将这些收集到的节点以 ((类数组的对象)) 形式返回。 {{index "id attribute", "getElementById method"}} -To find a specific _single_ node, you can give it an `id` attribute -and use `document.getElementById` instead. +要想找寻一个特定的 _单一_ 节点,你也可以赋予该节点 `id` 属性,然后使用 `document.getElementById` 方法。 ```{lang: "text/html"}
My ostrich Gertrude:
@@ -298,22 +192,13 @@ and use `document.getElementById` instead. {{index "getElementsByClassName method", "class attribute"}} -A third, similar method is `getElementsByClassName`, which, like -`getElementsByTagName`, searches through the contents of an element -node and retrieves all elements that have the given string in their -`class` attribute. +第三个类似的方法是 `getElementsByClassName`,就像 `getElementsByTagName` 那样,该方法搜索一个元素节点的内容,并获取所有在其 `class` 属性中含有给定字符串的元素。 -## Changing the document +## 更改文档 {{index "side effect", "removeChild method", "appendChild method", "insertBefore method", [DOM, construction], [DOM, modification]}} -Almost everything about the DOM data structure can be changed. The -shape of the document tree can be modified by changing parent-child -relationships. Nodes have a `remove` method to remove them from their -current parent node. To add a child node to an element node, we can -use `appendChild`, which puts it at the end of the list of children, -or `insertBefore`, which inserts the node given as the first argument -before the node given as the second argument. +几乎 DOM 数据结构的各个元素都可以被更改。文档树的形状可以随着父子关系的更动而发生变化。各节点有名为 `remove` 的方法将它们从当前的父节点中移除。我们可以用 `appendChild` 为元素节点添加子节点,该方法将新的子节点置于子节点列表的末尾。而另有一个名为 `insertBefore` 的方法将作为第一个参数的子节点插入于作为第二个参数的节点之前。 ```{lang: "text/html"}One
@@ -326,34 +211,21 @@ before the node given as the second argument. ``` -A node can exist in the document in only one place. Thus, inserting -paragraph _Three_ in front of paragraph _One_ will first remove it -from the end of the document and then insert it at the front, -resulting in _Three_/_One_/_Two_. All operations that insert a node -somewhere will, as a ((side effect)), cause it to be removed from its -current position (if it has one). +一个节点在文档中只能存在于一个位置,因此,若将 _段落 3_ 插入到 _段落 1_ 的前面,首先会将其从文档末尾移除,然后再进行前插,最后结果为 _段落 3_/_段落 1_/_段落 2_。所有插入节点的操作都会有这样的 ((副作用)),即将其从当前位置移除(如果当前有位置的话)。 {{index "insertBefore method", "replaceChild method"}} -The `replaceChild` method is used to replace a child node with another -one. It takes as arguments two nodes: a new node and the node to be -replaced. The replaced node must be a child of the element the method -is called on. Note that both `replaceChild` and `insertBefore` expect -the _new_ node as their first argument. +名为 `replaceChild` 的方法用于将子节点替换为另一个节点,该方法接受两个参数:新节点以及被替换的节点。被替换的节点必须是该方法调用的元素的子节点之一。需要注意的是,`replaceChild` 方法和 `insertBefore` 方法都将 _新_ 节点作为它们的第一个参数。 -## Creating nodes +## 创建节点 {{index "alt attribute", "img (HTML tag)"}} -Say we want to write a script that replaces all ((image))s (`The in the
@@ -377,24 +249,15 @@ to replace them. Text nodes are created with the
{{index "text node"}}
-Given a string, `createTextNode` gives us a text node that we can
-insert into the document to make it show up on the screen.
+给定一字符串,使用 `createTextNode` 方法可以让我们将该字符串生成文本节点,然后将其插入到文档中,以在屏幕上显示出来。
{{index "live data structure", "getElementsByTagName method", "childNodes property"}}
-The loop that goes over the images starts at the end of the list. This
-is necessary because the node list returned by a method like
-`getElementsByTagName` (or a property like `childNodes`) is _live_.
-That is, it is updated as the document changes. If we started from the
-front, removing the first image would cause the list to lose its first
-element so that the second time the loop repeats, where `i` is 1, it
-would stop because the length of the collection is now also 1.
+遍历图像的循环以节点列表的尾端为起点。这是有必要的,因为诸如 `getElementsByTagName` 这样的方法(或者类似 `childNodes` 的属性)返回的节点列表是 _动态的_ ,意味着文档的改变会让列表也随之改变。倘若我们从节点列表的开端进行遍历,移除第一个图像会导致列表失去第一个元素。第二次循环的时候 `i` 是 1,而集合的长度也是 1,于是该循环会终止。
{{index "slice method"}}
-If you want a _solid_ collection of nodes, as opposed to a live one,
-you can convert the collection to a real array by calling
-`Array.from`.
+如果你想要一个 _固定的_ 节点的集合,而不是动态的,你可以调用 `Array.from` 将其转换为真正的数组的集合。
```
let arrayish = {0: "one", 1: "two", length: 2};
@@ -405,17 +268,13 @@ console.log(array.map(s => s.toUpperCase()));
{{index "createElement method"}}
-To create ((element)) nodes, you can use the `document.createElement`
-method. This method takes a tag name and returns a new empty node of
-the given type.
+你可以使用 `document.createElement` 来创建((元素))节点。该方法接收一个标签名作为参数,并返回相应类型的新的空节点。
{{index "Popper, Karl", [DOM, construction], "elt function"}}
{{id elt}}
-The following example defines a utility `elt`, which creates an
-element node and treats the rest of its arguments as children to that
-node. This function is then used to add an attribution to a quote.
+下列示例定义了一个名为 `elt` 的工具函数,该方法创建一个元素节点,并将除类型之外的参数作为新元素的子节点。然后,该函数被用于为引用语增加作者的属性。
```{lang: "text/html"}
@@ -445,28 +304,21 @@ node. This function is then used to add an attribution to a quote. {{if book -This is what the resulting document looks like: +处理之后的文档看起来是这样的: {{figure {url: "img/blockquote.png", alt: "A blockquote with attribution",width: "8cm"}}} if}} -## Attributes +## 属性 {{index "href attribute", [DOM, attributes]}} -Some element ((attribute))s, such as `href` for links, can be accessed -through a property of the same name on the element's ((DOM)) -object. This is the case for most commonly used standard attributes. +某些元素的 ((属性)) 可以被元素的 ((DOM)) 对象含有的相同的属性名所访问,比如用于链接的 `href`。对于最常用的标准属性来说都是如此。 {{index "data attribute", "getAttribute method", "setAttribute method", attribute}} -But HTML allows you to set any attribute you want on nodes. This can -be useful because it allows you to store extra information in a -document. If you make up your own attribute names, though, such -attributes will not be present as properties on the element's node. -Instead, you have to use the `getAttribute` and `setAttribute` methods -to work with them. +然而,HTML 使你可以在节点上设置任意名称的属性。这样一来你便可以在文档中存储额外的信息。不过你使用了自己定义的属性名的话,这样的属性不会被呈现为元素节点的属性。你需要使用 `getAttribute` 和 `setAttribute` 方法来与之进行交互。 ```{lang: "text/html"}The launch code is 00000000.
@@ -482,47 +334,27 @@ to work with them. ``` -It is recommended to prefix the names of such made-up attributes with -`data-` to ensure they do not conflict with any other attributes. +推荐为这些创造出来的属性添加 `data-` 前缀,以确保它们不会和任何其他属性产生冲突。 {{index "getAttribute method", "setAttribute method", "className property", "class attribute"}} -There is a commonly used attribute, `class`, which is a ((keyword)) in -the JavaScript language. For historical reasons—some old JavaScript -implementations could not handle property names that matched -keywords—the property used to access this attribute is called -`className`. You can also access it under its real name, `"class"`, by -using the `getAttribute` and `setAttribute` methods. +`class` 是一个很常用的属性,它是 JavaScript 语言中的一个 ((关键词))。基于某些历史原因 ———— 某些旧有的 JavaScript 实现无法处理与关键词同名的属性名,因此用于访问 `class` 的属性名为 `className`。你亦可以通过 `getAttribute` 及 `setAttribute` 方法使用其真名 `"class"` 对其进行访问。 -## Layout +## 布局 {{index layout, "block element", "inline element", "p (HTML tag)", "h1 (HTML tag)", "a (HTML tag)", "strong (HTML tag)"}} -You may have noticed that different types of elements are laid out -differently. Some, such as paragraphs (``) or headings (`
`), -take up the whole width of the document and are rendered on separate -lines. These are called _block_ elements. Others, such as links -(``) or the `` element, are rendered on the same line with -their surrounding text. Such elements are called _inline_ elements. +你可能已经注意到不同类型的元素被摆放的布局是不同的。有些元素占据整个文档的宽度,诸如段落 (`
`) 和标题 (`
`),它们被渲染于单独的一行。这些被称为 _块_ 元素。而另一些元素与其周围的文本在同一行渲染,诸如链接 (``) 和 `` 元素。这类元素被称为 _内联_ 元素。 {{index drawing}} -For any given document, browsers are able to compute a layout, which -gives each element a size and position based on its type and content. -This layout is then used to actually draw the document. +对于任意一个指定的文档,浏览器能够计算出一个布局,该布局根据每个元素的类型及内容给元素分配尺寸及位置。最终用于绘制文档的就是这个计算出来的布局。 {{index "border (CSS)", "offsetWidth property", "offsetHeight property", "clientWidth property", "clientHeight property", dimensions}} -The size and position of an element can be accessed from JavaScript. -The `offsetWidth` and `offsetHeight` properties give you the space the -element takes up in _((pixel))s_. A pixel is the basic unit of -measurement in the browser. It traditionally corresponds to the -smallest dot that the screen can draw, but on modern displays, which -can draw _very_ small dots, that may no longer be the case, and a -browser pixel may span multiple display dots. +一个元素的尺寸和位置可以通过 JavaScript 来访问。`offsetWidth` 和 `offsetHeight` 属性能告诉你元素占用的以 _((像素))_ 为单位的空间大小。像素是浏览器中的基本测量单位。以前这个单位的定义是屏幕上绘制的最小的点,但由于现代显示器可以绘制 _非常_ 小的点,这个定义现在变得不那么适用了,一个浏览器像素可能涵盖多个显示点。 -Similarly, `clientWidth` and `clientHeight` give you the size of the -space _inside_ the element, ignoring border width. +与上述两个属性相似,`clientWidth` 和 `clientHeight` 属性能告诉你元素 _内在_ 的空间尺寸,忽略掉边框的宽度。 ```{lang: "text/html"}
@@ -548,34 +380,15 @@ if}} {{id boundingRect}} -The most effective way to find the precise position of an element on -the screen is the `getBoundingClientRect` method. It returns an object -with `top`, `bottom`, `left`, and `right` properties, indicating the -pixel positions of the sides of the element relative to the top left -of the screen. If you want them relative to the whole document, you -must add the current scroll position, which you can find in the -`pageXOffset` and `pageYOffset` bindings. +要想找到屏幕上某个元素的精确位置,使用 `getBoundingClientRect` 方法最为高效。该方法返回一个含有 `top`、`bottom`、`left` 和 `right` 四个属性的对象,表示元素边框相对于屏幕左上角的像素位置。倘若你想相对于整个文档的像素位置,你得加上当前的滚动位置,即用 `pageXOffset` 和 `pageYOffset` 绑定获取相应的值。 {{index "offsetHeight property", "getBoundingClientRect method", drawing, laziness, performance, efficiency}} -Laying out a document can be quite a lot of work. In the interest of -speed, browser engines do not immediately re-layout a document every -time you change it but wait as long as they can. When a JavaScript -program that changed the document finishes running, the browser will -have to compute a new layout to draw the changed document to -the screen. When a program _asks_ for the position or size of -something by reading properties such as `offsetHeight` or calling -`getBoundingClientRect`, providing correct information also requires -computing a ((layout)). +给文档进行布局所需的工作量可不小。为了考虑速度,浏览器引擎不会在你每次修改文档布局的时候立刻重新绘制文档,而是尽可能地推迟重绘。当一个修改文档的 JavaScript 程序运行完毕,浏览器必须计算出新的布局以将修改后的文档绘于屏幕。当一个程序通过读取诸如 `offsetHeight` 属性或调用 `getBoundingClientRect` 方法来 _查询_ 某个元素的位置或尺寸时,为了能提供正确的信息,浏览器也需要计算 ((布局))。 {{index "side effect", optimization, benchmark}} -A program that repeatedly alternates between reading DOM layout -information and changing the DOM forces a lot of layout computations -to happen and will consequently run very slowly. The following code is -an example of this. It contains two different programs that build up a -line of _X_ characters 2,000 pixels wide and measures the time each -one takes. +一个程序如果反复读取 DOM 布局信息以及修改 DOM,这将会引发大量的布局计算,从而导致运行十分缓慢。下列代码就是这样的例子。该示例包含两个程序,它们各自构建由多个 _X_ 字符组成的、2000 像素宽的一行,并且测量所用时长。 ```{lang: "text/html", test: nonumbers}
@@ -594,7 +407,7 @@ one takes. target.appendChild(document.createTextNode("X")); } }); - // → naive took 32 ms + // → 天真的方法用时 32 毫秒 time("clever", function() { let target = document.getElementById("two"); @@ -602,25 +415,19 @@ one takes. let total = Math.ceil(2000 / (target.offsetWidth / 5)); target.firstChild.nodeValue = "X".repeat(total); }); - // → clever took 1 ms + // → 聪明的方法用时 1 毫秒 ``` -## Styling +## 样式 {{index "block element", "inline element", style, "strong (HTML tag)", "a (HTML tag)", underline}} -We have seen that different HTML elements are drawn differently. Some -are displayed as blocks, others inline. Some add styling—`` -makes its content ((bold)), and `` makes it blue and underlines it. +我们已经了解到不同的 HTML 在页面上的绘制效果是不同的。有些元素显示为块,另一些则与其他元素显示在同一行。有些元素会增添样式 —— 比如 `` 会 ((加粗)) 内容, `` 使内容变蓝并且添加下划线。 {{index "img (HTML tag)", "default behavior", "style attribute"}} -The way an `
` tag shows an image or an `` tag causes a link to -be followed when it is clicked is strongly tied to the element type. -But we can change the styling associated with an element, such -as the text color or underline. Here is an example that uses -the `style` property: +一个 `
` 标签会显示图片,一个 `` 标签使得一个链接在被点击时可以被访问 —— 元素的行为与其类型紧密相关。然而我们可以改变与元素相关联的样式,比如说文本颜色或下划线。下列代码是使用 `style` 属性的示例: ```{lang: "text/html"} @@ -629,7 +436,7 @@ the `style` property: {{if book -The second link will be green instead of the default link color. +第二个链接会变成绿色,而非默认的链接颜色。 {{figure {url: "img/colored-links.png", alt: "A normal and a green link",width: "2.2cm"}}} @@ -637,16 +444,11 @@ if}} {{index "border (CSS)", "color (CSS)", CSS, "colon character"}} -A style attribute may contain one or more _((declaration))s_, which -are a property (such as `color`) followed by a colon and a value (such -as `green`). When there is more than one declaration, they must be -separated by ((semicolon))s, as in `"color: red; border: none"`. +样式属性可能含有一个或多个 _((声明))_,其格式为属性 (如 `color`) 后面跟着冒号和一个值 (如 `green`)。当声明的数量多于一个时,它们必须被 ((分号)) 隔开,比如 `"color: red; border: none"`。 {{index "display (CSS)", layout}} -A lot of aspects of the document can be influenced by -styling. For example, the `display` property controls whether an -element is displayed as a block or an inline element. +文档的很多方面都被样式所影响。举例来说,`display` 属性控制一个元素被显示为块元素或者内联元素。 ```{lang: "text/html"} This text is displayed inline, @@ -656,12 +458,7 @@ This text is displayed inline, {{index "hidden element"}} -The `block` tag will end up on its own line since ((block element))s -are not displayed inline with the text around them. The last tag is -not displayed at all—`display: none` prevents an element from showing -up on the screen. This is a way to hide elements. It is often -preferable to removing them from the document entirely because it -makes it easy to reveal them again later. +由于 ((块元素)) 不会与周遭的文本内联显示,上述代码中含有 `block` 标签的部分会显示在单独的一行。最后一个标签根本不会显示 —— `display: none` 会防止一个元素被显示在屏幕上。这是隐藏元素的一种方式。这种方式通常比将元素从文档中完全删除要更常见,因为稍后将元素重新显示出来是一件简单的事情。 {{if book @@ -671,11 +468,7 @@ if}} {{index "color (CSS)", "style attribute"}} -JavaScript code can directly manipulate the style of an element -through the element's `style` property. This property holds an object -that has properties for all possible style properties. The values of -these properties are strings, which we can write to in order to change -a particular aspect of the element's style. +JavaScript 代码可以通过元素的 `style` 属性直接操纵其样式。该属性持有一个包含所有可用的样式属性的对象。这些属性的值是字符串,我们可以改写这些值,从而改变元素样式的某一个方面。 ```{lang: "text/html"}
@@ -691,22 +484,16 @@ a particular aspect of the element's style. {{index "camel case", capitalization, "hyphen character", "font-family (CSS)"}} -Some style property names contain hyphens, such as `font-family`. -Because such property names are awkward to work with in JavaScript -(you'd have to say `style["font-family"]`), the property names in the -`style` object for such properties have their hyphens removed and the -letters after them capitalized (`style.fontFamily`). +有的样式属性名含有连字符,比如 `font-family`。然而这样的属性名在 JavaScript 里使用起来会有点尴尬(你得写成 `style["font-family"]`)。鉴于此,`style` 对象中诸如此类的属性名的连字符会被移除,并将尾随连字符的字母变成大写 (`style.fontFamily`)。 -## Cascading styles +## 层叠样式 {{index "rule (CSS)", "style (HTML tag)"}} {{indexsee "Cascading Style Sheets", CSS}} {{indexsee "style sheet", CSS}} -The styling system for HTML is called ((CSS)), for _Cascading Style -Sheets_. A _style sheet_ is a set of rules for how to style -elements in a document. It can be given inside a `