aboutsummaryrefslogtreecommitdiff
path: root/files/es/web/api/document_object_model/whitespace/index.html
blob: 866185204cc987f177c71ba59f4d3c63d5e4f9b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
---
title: Cómo manejan el espacio en blanco HTML, CSS y el DOM
slug: Web/API/Document_Object_Model/Whitespace
tags:
  - CSS
  - DOM
  - HTML
  - JavaScript
  - espacioenblanco
  - whitespace
translation_of: Web/API/Document_Object_Model/Whitespace
original_slug: Referencia_DOM_de_Gecko/Cómo_espacioenblanco
---
<div>{{APIRef("DOM")}}</div>

<p>La presencia de espacios en blanco en el <a href="/es/docs/Web/API/Document_Object_Model">DOM</a> puede causar problemas de diseño y dificultar la manipulación del árbol de contenido de formas inesperadas, dependiendo de dónde se encuentra. Este artículo explora cuándo pueden surgir dificultades y analiza qué se puede hacer para mitigar los problemas resultantes.</p>

<h2 id="¿Qué_es_el_espacio_en_blanco">¿Qué es el espacio en blanco?</h2>

<p>El espacio en blanco es cualquier cadena de texto compuesta solo por espacios, tabulaciones o saltos de línea (para ser precisos, secuencias CRLF, retornos de carro o avances de línea). Estos caracteres te permiten formatear tu código de una manera que lo hará fácilmente legible por ti y otras personas. De hecho, gran parte de nuestro código fuente está lleno de estos caracteres de espacio en blanco, y solo tendemos a deshacernos de ellos en un paso de compilación de producción para reducir el tamaño de descarga del código.</p>

<h3 id="¿HTML_ignora_en_gran_medida_los_espacios_en_blanco">¿HTML ignora en gran medida los espacios en blanco?</h3>

<p>En el caso de HTML, los espacios en blanco se ignoran en gran medida: los espacios en blanco entre palabras se tratan como un solo carácter y los espacios en blanco al principio y al final de los elementos y los elementos externos se ignoran. Tomemos el siguiente ejemplo minimalista:</p>

<h3 class="hidden" id="HTML_largely_ignores_whitespace">HTML largely ignores whitespace?</h3>

<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;

    &lt;h1&gt;       ¡Hola      mundo!     &lt;/h1&gt;</pre>

<p>{{EmbedLiveSample('HTML_largely_ignores_whitespace')}}</p>

<p>Este código fuente contiene un par de avances de línea después del <code>DOCTYPE</code> y un montón de caracteres de espacio antes, después y dentro del elemento <code>&lt;h1&gt;</code>, pero al navegador no parece importarle en absoluto y solo muestra las palabras "¡Hola mundo!" como si estos caracteres no existieran en absoluto:</p>

<p>Esto es para que los espacios en blanco no afecten el diseño de tu página. Crear espacio alrededor y dentro de los elementos es el trabajo de CSS.</p>

<h3 id="¿Qué_sucede_con_los_espacios_en_blanco">¿Qué <em>sucede</em> con los espacios en blanco?</h3>

<p>Sin embargo, no solo desaparecen.</p>

<p>Cualquier carácter de espacio en blanco que esté fuera de los elementos HTML del documento original se representan en el DOM. Esto es necesario internamente para que el editor pueda preservar el formato de los documentos. Esto significa que:</p>

<ul>
 <li>Habrá algunos nodos de texto que contienen solo espacios en blanco, y</li>
 <li>Algunos nodos de texto tendrán espacios en blanco al principio o al final.</li>
</ul>

<p>Tomemos el siguiente documento, por ejemplo:</p>

<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Mi Documento&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Encabezado&lt;/h1&gt;
  &lt;p&gt;
    Párrafo
  &lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>

<p>El árbol del DOM para esto se ve así:</p>

<p><img alt="árbol de dom equivalente al ejemplo de HTML anterior" src="https://mdn.mozillademos.org/files/17084/dom-string.png" style="display: block; height: 288px; margin: 0 auto; width: 562px;"></p>

<p>Conservar caracteres de espacio en blanco en el DOM es útil de muchas maneras, pero hay ciertos lugares donde esto hace que ciertos diseños sean más difíciles de implementar y causa problemas a los desarrolladores que quieren iterar a través de los nodos del DOM. Veremos estas y algunas soluciones más adelante.</p>

<h3 id="¿CSS_cómo_procesa_los_espacios_en_blanco">¿CSS cómo procesa los espacios en blanco?</h3>

<p>La mayoría de los espacios en blanco se ignoran, no todos. En el ejemplo anterior, uno de los espacios entre "!Hola" y "mundo!" todavía existe cuando la página se representa en un navegador. Hay reglas en el motor del navegador que deciden qué caracteres de espacio en blanco son útiles y cuáles no; estos se especifican al menos en parte en el <a href="https://www.w3.org/TR/css-text-3">Módulo de texto CSS Nivel 3</a>, y especialmente las partes sobre la <a href="https://www.w3.org/TR/css-text-3/#white-space-property">propiedad <code>white-space</code> en CSS</a> y <a href="https://www.w3.org/TR/css-text-3/#white-space-processing">detalles de procesamiento del espacio en blanco</a>, pero también ofrecemos una explicación más sencilla a continuación.</p>

<p>Tomemos otro ejemplo realmente simple. Para hacerlo más fácil, ilustramos todos los espacios con ◦, todas las tabulaciones con ⇥ y todos los saltos de línea con ⏎:</p>

<p>Este ejemplo:</p>

<pre class="brush: html notranslate">&lt;h1&gt;◦◦◦¡Hola◦⏎
⇥⇥⇥⇥&lt;span&gt;◦mundo!&lt;/span&gt;⇥◦◦&lt;/h1&gt;</pre>

<p>se representa en el navegador así:</p>

<div class="hidden">
<h4 id="Hidden_example">Hidden example</h4>

<pre class="brush: html notranslate">&lt;h1&gt;   ¡Hola
    &lt;span&gt; mundo!&lt;/span&gt;   &lt;/h1&gt;</pre>
</div>

<p>{{EmbedLiveSample('Hidden_example')}}</p>

<p>El elemento <code>&lt;h1&gt;</code> contiene solo elementos en línea. De hecho contiene:</p>

<ul>
 <li>Un nodo de texto (que consta de algunos espacios, la palabra "¡Hola" y algunas tabulaciones).</li>
 <li>Un elemento en línea (el <code>&lt;span&gt;</code>, que contiene un espacio, y la palabra "mundo!").</li>
 <li>Otro nodo de texto (que consta solo de tabulaciones y espacios).</li>
</ul>

<p>Debido a esto, establece lo que se llama un {{cssxref("Inline_formatting_context", "contexto de formato en línea")}}. Este es uno de los posibles contextos de representación de diseño con los que funcionan los motores del navegador.</p>

<p>Dentro de este contexto, el procesamiento de caracteres de espacio en blanco se puede resumir de la siguiente manera:</p>

<ol>
 <li>
  <p>Primero, todos los espacios y tabulaciones inmediatamente antes y después de un salto de línea se ignoran, por lo que, si tomamos nuestro marcado de ejemplo anterior y aplicamos esta primera regla, obtenemos:</p>

  <pre class="brush: html notranslate">&lt;h1&gt;◦◦◦¡Hola⏎
&lt;span&gt;◦mundo!&lt;/span&gt;⇥◦◦&lt;/h1&gt;</pre>
 </li>
 <li>
  <p>A continuación, todos los caracteres de tabulación se tratan como caracteres de espacio, por lo que el ejemplo se convierte en:</p>

  <pre class="brush: html notranslate">&lt;h1&gt;◦◦◦¡Hola⏎
&lt;span&gt;◦mundo!&lt;/span&gt;◦◦◦&lt;/h1&gt;</pre>
 </li>
 <li>
  <p>A continuación, los saltos de línea se convierten en espacios:</p>

  <pre class="brush: html notranslate">&lt;h1&gt;◦◦◦¡Hola◦&lt;span&gt;◦mundo!&lt;/span&gt;◦◦◦&lt;/h1&gt;</pre>
 </li>
 <li>
  <p>Después de eso, cualquier espacio inmediatamente después de otro espacio (incluso a través de dos elementos en línea separados) se ignora, por lo que terminamos con:</p>

  <pre class="brush: html notranslate">&lt;h1&gt;◦¡Hola◦&lt;span&gt;mundo!&lt;/span&gt;&lt;/h1&gt;</pre>
 </li>
 <li>
  <p>Y finalmente, las secuencias de espacios al principio y al final de una línea se eliminan, por lo que eventualmente obtenemos esto:</p>

  <pre class="brush: html notranslate">&lt;h1&gt;¡Hola◦&lt;span&gt;mundo!&lt;/span&gt;&lt;/h1&gt;</pre>
 </li>
</ol>

<p>Es por eso que las personas que visitan la página web simplemente verán la frase "¡Hola mundo!" muy bien escrita en la parte superior de la página, en lugar de un "!Hola" con una sangría extraña, seguido de un "mundo!" en la línea debajo de esa.</p>

<div class="blockIndicator note">
<p><strong>Nota</strong>: <a href="/es/docs/Tools">Firefox DevTools</a> ha admitido el resaltado de nodos de texto desde la versión 52, lo que facilita ver exactamente qué contenido hay dentro de los nodos de espacios en blanco. Los nodos de espacios en blanco puros están marcados con una etiqueta "<code>whitespace</code>".</p>
</div>

<h3 id="Espacio_en_blanco_en_contextos_de_formato_de_bloque">Espacio en blanco en contextos de formato de bloque</h3>

<p>Anteriormente, solo miramos elementos que contienen elementos en línea y contextos de formato en línea. Si un elemento contiene al menos un elemento de bloque, entonces establece lo que se llama un {{cssxref("Block_formatting_context", "contexto de formato de bloque")}}.</p>

<p>En este contexto, los espacios en blanco se tratan de manera muy diferente. Veamos un ejemplo para explicar cómo. Hemos marcado los espacios en blanco como antes.</p>

<pre class="brush: html notranslate">&lt;body&gt;⏎
⇥&lt;div&gt;◦◦¡Hola◦◦&lt;/div&gt;⏎
⏎
◦◦◦&lt;div&gt;◦◦mundo!◦◦&lt;/div&gt;◦◦⏎
&lt;/body&gt;</pre>

<p>Tenemos 3 nodos de texto que contienen solo espacios en blanco, uno antes del primer <code>&lt;div&gt;</code>, uno entre los 2 <code>&lt;div&gt;</code>s y uno después del segundo <code>&lt;div&gt;</code>.</p>

<p>Esto se renderiza así:</p>

<div class="hidden">
<h4 id="Hidden_example_2">Hidden example 2</h4>

<pre class="brush: html notranslate">&lt;body&gt;
  &lt;div&gt;  ¡Hola  &lt;/div&gt;

   &lt;div&gt;  mundo!   &lt;/div&gt;
&lt;/body&gt;</pre>
</div>

<p>{{EmbedLiveSample('Hidden_example_2')}}</p>

<p>Podemos resumir cómo se maneja el espacio en blanco aquí de la siguiente manera (puede haber algunas pequeñas diferencias en el comportamiento exacto entre los navegadores, pero básicamente, esto funciona):</p>

<ol>
 <li>
  <p>Debido a que estamos dentro de un contexto de formato de bloque, todo debe ser un bloque, por lo que nuestros 3 nodos de texto también se convierten en bloques, al igual que los 2 <code>&lt;div&gt;</code>s. Los bloques ocupan todo el ancho disponible y se apilan unos encima de los otros, lo cual significa que terminamos con un diseño compuesto por esta lista de bloques:</p>

  <pre class="brush: html notranslate">&lt;block&gt;⏎⇥&lt;/block&gt;
&lt;block&gt;◦◦¡Hola◦◦&lt;/block&gt;
&lt;block&gt;⏎◦◦◦&lt;/block&gt;
&lt;block&gt;◦◦mundo!◦◦&lt;/block&gt;
&lt;block&gt;◦◦⏎&lt;/block&gt;</pre>
 </li>
 <li>
  <p>Esto luego se simplifica aún más aplicando las reglas de procesamiento para espacios en blanco en contextos de formato en línea a estos bloques:</p>

  <pre class="brush: html notranslate">&lt;block&gt;&lt;/block&gt;
&lt;block&gt;¡Hola&lt;/block&gt;
&lt;block&gt;&lt;/block&gt;
&lt;block&gt;mundo!&lt;/block&gt;
&lt;block&gt;&lt;/block&gt;</pre>
 </li>
 <li>
  <p>Los 3 bloques vacíos que tenemos ahora no van a ocupar ningún espacio en el diseño final, porque no contienen nada, así que terminaremos con solo 2 bloques ocupando espacio en la página. Las personas que visitan la página web ven las palabras "!Hola" y "mundo!" en 2 líneas separadas, ya que esperarías que se distribuyeran 2 <code>&lt;div&gt;</code>s. El motor del navegador esencialmente ha ignorado todos los espacios en blanco que se agregaron en el código fuente.</p>
 </li>
</ol>

<h2 id="Espacios_entre_elementos_en_línea_y_bloques_en_línea">Espacios entre elementos en línea y bloques en línea</h2>

<p>Ahora analicemos algunos problemas que pueden surgir debido a los espacios en blanco y qué se puede hacer al respecto. En primer lugar, veremos qué sucede con los espacios entre los elementos en línea y de bloque en línea. De hecho, ya vimos esto en nuestro primer ejemplo, cuando describimos cómo se procesan los espacios en blanco dentro de los contextos de formato en línea.</p>

<p>Dijimos que había reglas para ignorar la mayoría de los caracteres, pero que los caracteres que separan palabras permanecen. Cuando solo se trata de elementos a nivel de bloque como <code>&lt;p&gt;</code> que solo contienen elementos en línea como <code>&lt;em&gt;</code>, <code>&lt;strong&gt;</code>, <code>&lt;span&gt;</code>, etc., normalmente no te importa esto porque el espacio en blanco adicional que llega al diseño es útil para separar las palabras en la oración.</p>

<p>Sin embargo, se vuelve más interesante cuando comienzas a usar elementos <code>inline-block</code>. Estos elementos se comportan como elementos en línea en el exterior y como bloques en el interior, y a menudo se utilizan para mostrar piezas de la IU más complejas que solo texto, una al lado de la otra en la misma línea, por ejemplo, elementos del menú de navegación.</p>

<p>Debido a que son bloques, muchas personas esperan que se comporten como tales, pero en realidad no es así. Si hay espacios en blanco de formato entre elementos en línea adyacentes, esto dará como resultado un espacio en el diseño, al igual que los espacios entre palabras en el texto.</p>

<p>Considera este ejemplo (nuevamente, los espacios en blanco en el HTML están marcados para que sean visibles):</p>

<pre class="brush: css notranslate" id="ef6f">.people-list {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.people-list li {
  display: inline-block;
  width: 2em;
  height: 2em;
  background: #f06;
  border: 1px solid;
}
</pre>

<pre class="brush: html notranslate" id="24bb">&lt;ul class="people-list"&gt;⏎

◦◦&lt;li&gt;&lt;/li&gt;⏎

◦◦&lt;li&gt;&lt;/li&gt;⏎

◦◦&lt;li&gt;&lt;/li&gt;⏎

◦◦&lt;li&gt;&lt;/li&gt;⏎

◦◦&lt;li&gt;&lt;/li&gt;&lt;/ul&gt;</pre>

<p>Esto se traduce de la siguiente manera:</p>

<div class="hidden">
<h3 id="Hidden_example_3">Hidden example 3</h3>

<pre class="brush: css notranslate" id="ef6f">.people-list { list-style-type: none; margin: 0; padding: 0; }
.people-list li { display: inline-block; width: 2em; height: 2em; background: #f06; border: 1px solid; }
</pre>

<pre class="brush: html notranslate" id="24bb">&lt;ul class="people-list"&gt;

  &lt;li&gt;&lt;/li&gt;

  &lt;li&gt;&lt;/li&gt;

  &lt;li&gt;&lt;/li&gt;

  &lt;li&gt;&lt;/li&gt;

  &lt;li&gt;&lt;/li&gt;

&lt;/ul&gt;</pre>
</div>

<p>{{EmbedLiveSample('Hidden_example_3')}}</p>

<p>Probablemente no desees los espacios entre los bloques — dependiendo del caso de uso (¿esta es una lista de avatares o botones de navegación horizontales?), Probablemente desees que los lados del elemento estén alineados entre sí y poder controlar cualquier espacio tú mismo.</p>

<p>El <em>Inspector HTML de Firefox DevTools</em> resaltará los nodos de texto y también te mostrará exactamente qué áreas están ocupando los elementos, lo que es útil si te preguntas qué está causando el problema y tal vez estés pensando que tienes un margen adicional allí o algo así.</p>

<p><img alt="Espacio en blanco en Devtools" src="https://mdn.mozillademos.org/files/17085/whitespace-devtools.png" style="border-style: solid; border-width: 1px; height: 454px; width: 797px;"></p>

<p>Hay algunas formas de solucionar este problema:</p>

<p>Utiliza <a href="/es/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a> para crear la lista horizontal de elementos en lugar de probar una solución de <code>inline-block</code>. Esto se encarga de todo por ti y definitivamente es la solución preferida:</p>

<pre class="brush: css notranslate">ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  display: flex;
}</pre>

<p>Si necesitas confiar en <code>inline-block</code>, puedes establecer el {{cssxref("font-size")}} de la lista a 0. Esto solo trabaja si tus bloques no tienen el tamaño <code>ems</code> (según el <code>font-size</code>, por lo que el tamaño del bloque también terminaría siendo 0). <code>rems</code> sería una buena opción aquí:</p>

<pre class="brush: css notranslate">ul {
  font-size: 0;
  ...
}

li {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  ...
}
</pre>

<p>O puedes establecer un margen negativo en los elementos de la lista:</p>

<pre class="brush: css notranslate">li {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  margin-right: -0.25rem;
}</pre>

<p>También puedes resolver este problema colocando los elementos de tu lista en la misma línea en la fuente, lo cual hace que los nodos de espacios en blanco no se creen en primer lugar:</p>

<pre class="brush: html notranslate">&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;</pre>

<h2 id="Recorrido_del_DOM_y_el_espacio_en_blanco">Recorrido del DOM y el espacio en blanco</h2>

<p>Al intentar realizar una manipulación del <a href="/es/docs/Web/API/Document_Object_Model">DOM</a> en JavaScript, también puedes encontrar problemas debido a los nodos de espacios en blanco. Por ejemplo, si tienes una referencia a un nodo padre y deseas afectar su primer elemento hijo usando <a href="/es/docs/Web/API/Node/firstChild"><code>Node.firstChild</code></a>, si hay un nodo de espacio en blanco deshonesto justo después de la etiqueta de apertura principal, no obtendrás el resultado que esperabas. Se seleccionaría el nodo de texto en lugar del elemento al que deseas afectar.</p>

<p>Veamos otro ejemplo, si tienes un determinado subconjunto de elementos en los que deseas hacer algo en función de si están vacíos (no tienen nodos secundarios) o, no puedes verificar si cada elemento está vacío usando algo como <a href="/es/docs/Web/API/Node/hasChildNodes"><code>Node.hasChildNodes()</code></a>, pero nuevamente, si algún elemento destino contiene nodos de texto, podrías terminar con resultados falsos.</p>

<h2 id="Funciones_auxiliares_de_espacios_en_blanco">Funciones auxiliares de espacios en blanco</h2>

<p>El siguiente código JavaScript define varias funciones que facilitan el manejo de espacios en blanco en el DOM:</p>

<pre class="brush: js notranslate">/**
 * En todo, el espacio en blanco se define como uno de los caracteres
 *  "\t" TAB \u0009
 *  "\n" LF  \u000A
 *  "\r" CR  \u000D
 *  " "  SPC \u0020
 *
 * Esto no usa la "\s" de Javascript porque eso incluye
 * espacios irrompibles (y también algunos otros caracteres).
 */


/**
 * Determina si el contenido de texto de un nodo es completamente de espacios en blanco.
 *
 * @param nod  Un nodo que implementa la interfaz | CharacterData | (es decir,
 *             un nodo |Text|, |Comment| o |CDATASection|
 * @return     True si todo el contenido de texto de |nod| es espacio en blanco,
 *             de lo contrario false.
 */
function is_all_ws( nod )
{
  // Usa las características de String y RegExp de ECMA-262 Edición 3
  return !(/[^\t\n\r ]/.test(nod.textContent));
}


/**
 * Determina si un nodo debe ser ignorado por las funciones del iterador.
 *
 * @param nod  Un objeto implementando la interfaz |Node| de DOM1.
 * @return     true si el nodo es:
 *                1) Un nodo |Text| en que todo es espacio en blanco
 *                2) Un nodo |Comment|
 *             y de lo contrario false.
 */

function is_ignorable( nod )
{
  return ( nod.nodeType == 8) || // Un nodo comment
         ( (nod.nodeType == 3) &amp;&amp; is_all_ws(nod) ); // un nodo text, todo es eeb
}

/**
 * Versión de |previousSibling| que omite los nodos que son completamente
 * espacio en blanco o comentarios.  (Normalmente |previousSibling| es una propiedad
 * de todos los nodos DOM que devuelve el nodo hermano, el nodo que es
 * un hijo del mismo padre, que ocurre inmediatamente antes del
 * nodo de referencia).
 *
 * @param sib  El nodo de referencia.
 * @return     O bien:
 *               1) El hermano anterior más cercano a |sib| eso no es
 *                  ignorable según |is_ignorable|, o
 *               2) null si no existe tal nodo.
 */
function node_before( sib )
{
  while ((sib = sib.previousSibling)) {
    if (!is_ignorable(sib)) return sib;
  }
  return null;
}

/**
 * Versión de |nextSibling| que omite los nodos que son completamente
 * espacio en blanco o comentarios.
 *
 * @param sib  El nodo de referencia.
 * @return     O bien:
 *               1) El hermano más cercano a |sib| eso no es
 *                  ignorable según |is_ignorable|, o
 *               2) null si no existe tal nodo.
 */
function node_after( sib )
{
  while ((sib = sib.nextSibling)) {
    if (!is_ignorable(sib)) return sib;
  }
  return null;
}

/**
 * Versión de |lastChild| que omite los nodos que son completamente
 * espacio en blanco o comentarios.  (Normalmente |lastChild| es una propiedad
 * de todos los nodos del DOM que da el último de los nodos contenidos
 * directamente en el nodo de referencia).
 *
 * @param sib  El nodo de referencia.
 * @return     O bien:
 *               1) El último hijo de |sib| eso no es
 *                  ignorable según |is_ignorable|, o
 *               2) null si no existe tal nodo.
 */
function last_child( par )
{
  var res=par.lastChild;
  while (res) {
    if (!is_ignorable(res)) return res;
    res = res.previousSibling;
  }
  return null;
}

/**
 * Versión de |firstChild| que omite los nodos que son completamente
 * espacios en blanco y comentarios.
 *
 * @param sib  El nodo de referencia.
 * @return     O bien:
 *               1) El primer hijo de |sib| eso no es
 *                  ignorable según |is_ignorable|, o
 *               2) null si no existe tal nodo.
 */
function first_child( par )
{
  var res=par.firstChild;
  while (res) {
    if (!is_ignorable(res)) return res;
    res = res.nextSibling;
  }
  return null;
}

/**
 * Versión de |data| que no incluye espacios en blanco al principio
 * y finaliza y normaliza todos los espacios en blanco a un solo espacio.  (Normalmente
 * |data| es una propiedad de los nodos de texto que proporciona el texto del nodo).
 *
 * @param txt  El nodo de texto cuyos datos se deben devolver
 * @return     Una cadena que proporciona el contenido del nodo de texto con
 *             espacios en blanco colapsados.
 */
function data_of( txt )
{
  var data = txt.textContent;
  // Usa las características de String y RegExp de ECMA-262 Edición 3
  data = data.replace(/[\t\n\r ]+/g, " ");
  if (data.charAt(0) == " ")
    data = data.substring(1, data.length);
  if (data.charAt(data.length - 1) == " ")
    data = data.substring(0, data.length - 1);
  return data;
}
</pre>

<h3 id="Ejemplo">Ejemplo</h3>

<p>El siguiente código demuestra el uso de las funciones anteriores. Itera sobre los hijos de un elemento (cuyos hijos son todos elementos) para encontrar aquel cuyo texto es <code>"Este es el tercer párrafo"</code>, y luego cambia el atributo de clase y el contenido de ese párrafo.</p>

<pre class="brush: js notranslate">var cur = first_child(document.getElementById("test"));
while (cur)
{
  if (data_of(cur.firstChild) == "Este es el tercer párrafo.")
  {
    cur.className = "magic";
    cur.firstChild.textContent = "Este es el párrafo mágico.";
  }
  cur = node_after(cur);
}
</pre>