Codificación aprenderaprogramar.com: CU01126E
DIFERENCIAS ENTRE NAVEGADORES
Con cierta frecuencia nos tendremos que enfrentar a que una página web se muestra de cierta forma en un navegador y de otra forma en otro navegador. ¿Por qué estas diferencias entre navegadores? Pueden existir diferentes motivos, pero vamos a ver cómo la representación interna del DOM puede estar relacionado con esto.
EJEMPLO: ACCESO A NODOS DEL DOM
Vamos a trabajar con un código sencillo y trataremos de acceder a los nodos del DOM a través de código JavaScript. El código que emplearemos es este:
<!DOCTYPE html> <html> <head> <title>Ejemplo DOM - aprenderaprogramar.com</title><meta charset="utf-8"> </head> <body>Texto en body <div id="cabecera" class="brillante"> <h1>Portal web <span class="destacado">aprenderaprogramar.com</span>, para aprender</h1> <img name ="lagarto" src="http://i.imgur.com/afC0L.jpg" alt="Notepad++" title="Notepad++, un útil editor de texto"> </div> <!-- Final del código--> </body> </html> |
La primera cuestión que queremos destacar es que distintos navegadores pueden crear distintas representaciones de árbol de nodos. En concreto nosotros hemos probado dos navegadores a los que denominaremos navegador 1 y navegador 2. Hemos numerado los nodos conforme aparecen de izquierda a derecha con 0, 1, 2, 3, etc. y nos hemos encontrado con esto:
Hay distintas cuestiones que merece la pena comentar:
a) Aparecen una serie de nodos que podemos denominar “auxiliares”. En los árboles gráficamente los hemos denominado <<Texto vacío>>, y se corresponden con la representación interna que le da el navegador a elementos como saltos de línea. Por ejemplo:
<div id="cabecera" class="brillante"> <h1> |
Puede ser interpretado como que div tiene un hijo que es texto vacío (el salto de línea) y a su derecha aparece el hijo h1. En cambio:
<div id="cabecera" class="brillante"><h1> |
Sería interpretado como que div tiene un hijo que es h1 (no aparece el texto vacío asociado al salto de línea).
Esto no es demasiado importante para nosotros y en general ignoraremos a nodos como estos (texto vacío). Además distintos navegadores pueden usar nodos auxiliares de distinta manera. La idea con que debemos de quedarnos es que la representación de árbol de nodos que usa un navegador es compleja y en general no nos interesará conocer los detalles de cómo trabaja el navegador, sino simplemente ser prácticos y poder acceder de forma fácil a los nodos que nos interesen.
b) En el árbol de nodos del navegador 2 hemos señalado que hay un nodo que no es considerado por el navegador 2, pero que en cambio sí era considerado por el navegador 1. ¿Por qué? Porque cada navegador tiene su propia forma de construir el árbol de nodos. Ciertamente distintos navegadores pueden construir árboles de nodos parecidos, pero quizás no sean exactamente iguales (y esto en algunas ocasiones nos podrá generar problemas). Si probáramos otro navegador quizás nos encontráramos algún cambio adicional.
c) Dado que estamos representando un código muy muy sencillo, podemos extraer dos conclusiones rápidas: la primera, que si para este código encontramos algunas diferencias en el árbol de nodos, para un código extenso y complejo como suele tener cualquier página web existirán muchas diferencias internas. La segunda, que el árbol de nodos de una página web real será muy extenso y muy complejo, tanto que no nos interesará visualizarlo ni conocerlo. Unicamente nos interesa tener los conceptos claros para poder trabajar con el DOM y con JavaScript.
A continuación mostramos el código para acceder a los nodos del navegador 1 y mostrar algunos mensajes por pantalla:
CÓDIGO PARA EL NAVEGADOR 1:
<!DOCTYPE html> <html> <head> <title>Ejemplo DOM - aprenderaprogramar.com</title><meta charset="utf-8"> </head> <body>Texto en body <div id="cabecera" class="brillante"> <h1>Portal web <span class="destacado">aprenderaprogramar.com</span>, para aprender</h1> <img name ="lagarto" src="http://i.imgur.com/afC0L.jpg" alt="Notepad++" title="Notepad++, un útil editor de texto"> </div> <!-- Final del código--> <script type = "text/javascript"> var msg = ''; msg = '¿Quién es el nodo padre de document? '+ document.parentNode + '\n\n'; msg = msg + 'Para el nodo document el nodeType vale: ' + document.nodeType +' , y el nodeName vale '+ document.nodeName + '\n\n'; msg = msg+ 'El valor de nodeValue para el nodo document es: ' + document.nodeValue +'\n\n'; msg = msg + 'Nodo hijo del nodo raíz es la declaración DOCTYPE con nodeName: ' + document.childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo del nodo raíz es etiqueta html con nodeName: ' + document.childNodes[1].nodeName +' y nodeType: '+ document.childNodes[1].nodeType + '\n\n'; msg = msg + 'Número de hijos de nodo etiqueta html: ' + document.childNodes[1].childElementCount +' ( ' + document.childNodes[1].children.length +')\n\n'; msg = msg + 'Nodo hijo de etiqueta html es etiqueta head con nodeName: ' + document.childNodes[1].childNodes[0].nodeName +' y nodeType: '+ document.childNodes[1].childNodes[0].nodeType +'\n\n'; msg = msg + 'Nodo hijo de etiqueta html es tipo texto vacío (salto de línea entre terminación de head y comienzo de body): ' + document.childNodes[1].childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta html es etiqueta body con nodeName: ' + document.childNodes[1].childNodes[2].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeName: ' + document.childNodes[1].childNodes[2].childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: ' + document.childNodes[1].childNodes[2].childNodes[0].nodeValue +'\n\n'; var nodoBody = document.childNodes[1].childNodes[2]; msg = msg + '(Repetimos) Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: ' + nodoBody.childNodes[0].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es div con nodeName: ' + nodoBody.childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[1].childNodes[0].nodeName +' y node value: '+ nodoBody.childNodes[1].childNodes[0].nodeValue + '\n\n'; msg = msg + 'Nodo hijo de etiqueta div es etiqueta H1 con nodeName: ' + nodoBody.childNodes[1].childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es texto con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es etiqueta span con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[1].nodeName +'\n\n'; var nodoSpan = nodoBody.childNodes[1].childNodes[1].childNodes[1]; msg = msg + 'Nodo hijo de etiqueta span es texto con nodeName: ' + nodoSpan.childNodes[0].nodeName +' y nodeValue: '+ nodoSpan.childNodes[0].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es texto con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[2].nodeName +' y nodeValue: '+ nodoBody.childNodes[1].childNodes[1].childNodes[2].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[1].childNodes[2].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es img con nodeName: ' + nodoBody.childNodes[1].childNodes[3].nodeName +'\n\n'; msg = msg + 'Valor del atributo name de la imagen: ' + nodoBody.childNodes[1].childNodes[3].name +'\n\n'; var nodoImg = nodoBody.childNodes[1].childNodes[3]; msg = msg + 'Valor del atributo src de la imagen: ' + nodoImg.src +', valor de alt: ' + nodoImg.alt + '\n\n'; msg = msg + 'Valor del atributo title de la imagen: '+ nodoImg.title+'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[2].nodeName +' y nodeType: '+nodoBody.childNodes[2].nodeType+' \n\n'; msg = msg + 'Nodo hijo de etiqueta body es comentario con nodeName: ' + nodoBody.childNodes[3].nodeName +' y nodeType: '+nodoBody.childNodes[3].nodeType+' y nodeValue: '+nodoBody.childNodes[3].nodeValue+' \n\n'; alert (msg); </script> </body> </html> |
El resultado esperado en este navegador al tratar de mostrar la página web es el siguiente:
¿Quién es el nodo padre de document? nullPara el nodo document el nodeType vale: 9 , y el nodeName vale #document
El valor de nodeValue para el nodo document es: null
Nodo hijo del nodo raíz es la declaración DOCTYPE con nodeName: html
Nodo hijo del nodo raíz es etiqueta html con nodeName: HTML y nodeType: 1
Número de hijos de nodo etiqueta html: 2 ( 2)
Nodo hijo de etiqueta html es etiqueta head con nodeName: HEAD y nodeType: 1
Nodo hijo de etiqueta html es tipo texto vacío (salto de línea entre terminación de head y comienzo de body): #text
Nodo hijo de etiqueta html es etiqueta body con nodeName: BODY
Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeName: #text
Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: Texto en body
(Repetimos) Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: Texto en body
Nodo hijo de etiqueta body es div con nodeName: DIV
Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: #text y node value:
Nodo hijo de etiqueta div es etiqueta H1 con nodeName: H1
Nodo hijo de etiqueta h1 es texto con nodeName: #text
Nodo hijo de etiqueta h1 es etiqueta span con nodeName: SPAN
Nodo hijo de etiqueta span es texto con nodeName: #text y nodeValue: aprenderaprogramar.com
Nodo hijo de etiqueta h1 es texto con nodeName: #text y nodeValue: , para aprender
Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: #text
Nodo hijo de etiqueta div es img con nodeName: IMG
Valor del atributo name de la imagen: lagarto
Valor del atributo src de la imagen: http://i.imgur.com/afC0L.jpg, valor de alt: Notepad++
Valor del atributo title de la imagen: Notepad++, un útil editor de texto
Nodo hijo de etiqueta body es texto vacío (salto de línea) con nodeName: #text y nodeType: 3
Nodo hijo de etiqueta body es comentario con nodeName: #comment y nodeType: 8 y nodeValue: Final del código
A continuación mostramos el código para acceder a los nodos del navegador 2 y mostrar algunos mensajes por pantalla:
CÓDIGO PARA EL NAVEGADOR 2:
<!DOCTYPE html> <html> <head> <title>Ejemplo DOM - aprenderaprogramar.com</title><meta charset="utf-8"> </head> <body>Texto en body <div id="cabecera" class="brillante"> <h1>Portal web <span class="destacado">aprenderaprogramar.com</span>, para aprender</h1> <img name ="lagarto" src="http://i.imgur.com/afC0L.jpg" alt="Notepad++" title="Notepad++, un útil editor de texto"> </div> <!-- Final del código--> <script type = "text/javascript"> var msg = ''; msg = '¿Quién es el nodo padre de document? '+ document.parentNode + '\n\n'; msg = msg + 'Para el nodo document el nodeType vale: ' + document.nodeType +' , y el nodeName vale '+ document.nodeName + '\n\n'; msg = msg+ 'El valor de nodeValue para el nodo document es: ' + document.nodeValue +'\n\n'; msg = msg + 'Nodo hijo del nodo raíz es la declaración DOCTYPE con nodeName: ' + document.childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo del nodo raíz es etiqueta html con nodeName: ' + document.childNodes[1].nodeName +' y nodeType: '+ document.childNodes[1].nodeType + '\n\n'; msg = msg + 'Número de hijos de nodo etiqueta html: ' + document.childNodes[1].childElementCount +' ( ' + document.childNodes[1].children.length +')\n\n'; msg = msg + 'Nodo hijo de etiqueta html es etiqueta head con nodeName: ' + document.childNodes[1].childNodes[0].nodeName +' y nodeType: '+ document.childNodes[1].childNodes[0].nodeType +'\n\n'; msg = msg + 'Nodo hijo de etiqueta html es etiqueta body con nodeName: ' + document.childNodes[1].childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeName: ' + document.childNodes[1].childNodes[1].childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: ' + document.childNodes[1].childNodes[1].childNodes[0].nodeValue +'\n\n'; var nodoBody = document.childNodes[1].childNodes[1]; msg = msg + '(Repetimos) Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: ' + nodoBody.childNodes[0].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es div con nodeName: ' + nodoBody.childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[1].childNodes[0].nodeName +' y nodeValue ' + nodoBody.childNodes[1].childNodes[0].nodeValue + '\n\n'; msg = msg + 'Nodo hijo de etiqueta div es etiqueta H1 con nodeName: ' + nodoBody.childNodes[1].childNodes[1].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es texto con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[0].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es etiqueta span con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[1].nodeName +'\n\n'; var nodoSpan = nodoBody.childNodes[1].childNodes[1].childNodes[1]; msg = msg + 'Nodo hijo de etiqueta span es texto con nodeName: ' + nodoSpan.childNodes[0].nodeName +' y nodeValue: '+ nodoSpan.childNodes[0].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta h1 es texto con nodeName: ' + nodoBody.childNodes[1].childNodes[1].childNodes[2].nodeName +' y nodeValue: '+ nodoBody.childNodes[1].childNodes[1].childNodes[2].nodeValue +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[1].childNodes[2].nodeName +'\n\n'; msg = msg + 'Nodo hijo de etiqueta div es img con nodeName: ' + nodoBody.childNodes[1].childNodes[3].nodeName +'\n\n'; msg = msg + 'Valor del atributo name de la imagen: ' + nodoBody.childNodes[1].childNodes[3].name +'\n\n'; var nodoImg = nodoBody.childNodes[1].childNodes[3]; msg = msg + 'Valor del atributo src de la imagen: ' + nodoImg.src +', valor de alt: ' + nodoImg.alt + '\n\n'; msg = msg + 'Valor del atributo title de la imagen: '+ nodoImg.title+'\n\n'; msg = msg + 'Nodo hijo de etiqueta body es texto vacío (salto de línea) con nodeName: ' + nodoBody.childNodes[2].nodeName +' y nodeType: '+nodoBody.childNodes[2].nodeType+' \n\n'; msg = msg + 'Nodo hijo de etiqueta body es comentario con nodeName: ' + nodoBody.childNodes[3].nodeName +' y nodeType: '+nodoBody.childNodes[3].nodeType+' y nodeValue: '+nodoBody.childNodes[3].nodeValue+' \n\n'; alert (msg); </script> </body> </html> |
El resultado esperado en este navegador al tratar de mostrar la página web es el siguiente:
¿Quién es el nodo padre de document? nullPara el nodo document el nodeType vale: 9 , y el nodeName vale #document
El valor de nodeValue para el nodo document es: null
Nodo hijo del nodo raíz es la declaración DOCTYPE con nodeName: HTML
Nodo hijo del nodo raíz es etiqueta html con nodeName: HTML y nodeType: 1
Número de hijos de nodo etiqueta html: 2 ( 2)
Nodo hijo de etiqueta html es etiqueta head con nodeName: HEAD y nodeType: 1
Nodo hijo de etiqueta html es etiqueta body con nodeName: BODY
Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeName: #text
Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: Texto en body
(Repetimos) Nodo hijo de etiqueta body es texto <<Texto en body>> con nodeValue: Texto en body
Nodo hijo de etiqueta body es div con nodeName: DIV
Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: #text y node value:
Nodo hijo de etiqueta div es etiqueta H1 con nodeName: H1
Nodo hijo de etiqueta h1 es texto con nodeName: #text
Nodo hijo de etiqueta h1 es etiqueta span con nodeName: SPAN
Nodo hijo de etiqueta span es texto con nodeName: #text y nodeValue: aprenderaprogramar.com
Nodo hijo de etiqueta h1 es texto con nodeName: #text y nodeValue: , para aprender
Nodo hijo de etiqueta div es texto vacío (salto de línea) con nodeName: #text
Nodo hijo de etiqueta div es img con nodeName: IMG
Valor del atributo name de la imagen: lagarto
Valor del atributo src de la imagen: http://i.imgur.com/afC0L.jpg, valor de alt: Notepad++
Valor del atributo title de la imagen: Notepad++, un útil editor de texto
Nodo hijo de etiqueta body es texto vacío (salto de línea) con nodeName: #text y nodeType: 3
Nodo hijo de etiqueta body es comentario con nodeName: #comment y nodeType: 8 y nodeValue: Final del código
¿Por qué usamos distinto código para distintos navegadores si estamos trabajando con un mismo código HTML?
El motivo es que cada navegador trabaja, de forma interna, de distinta manera. En este caso, al navegador 2 usar distinto número de nodos que el navegador 1, los índices de acceso a nodos no son los mismos para distintos navegadores. En consecuencia, si tratamos de ejecutar el código para el navegador 2 en el navegador 1 posiblemente lo que ocurra es que “no se muestra nada”, debido a que al haber errores en los índices de acceso JavaScript detecta el error y simplemente no se ejecuta (sin mostrar ningún aviso).
¿Significa esto que tendremos que crear distinto código JavaScript para los distintos navegadores?
No, existen métodos más estándares y sencillos para acceder a nodos que veremos más adelante, con los que no cabe esperar diferencias entre distintos navegadores. No obstante, es importante recordar que cada navegador puede ofrecer distintos resultados ante un mismo código (o incluso no ejecutar algo que sí ejecuta otro). Nos tendremos que enfrentar a esta situación en diversas ocasiones y conviene tener conocimiento de ello. Muchas veces te preguntarán (o te preguntarás): ¿Por qué esta página web se muestra de esta manera en un navegador y de otra manera en otra navegador? Los motivos pueden ser varios, pero esto que estamos comentando es uno de ellos.
EJERCICIO
Comprueba cuál de los códigos que hemos empleado se ejecuta en tu navegador. Si no se ejecuta ninguno de ellos, corrígelo para que se ejecute (una estrategia puede ser ir añadiendo línea a línea para saber dónde surgen problemas).
Ambos códigos (el código para el navegador 1 y el código para el navegador 2) son muy similares. ¿Dónde podemos decir que se encuentra la principal diferencia entre uno y otro código? ¿Por qué?
Una vez tengas el código ejecutándose, modifica la forma de acceso a los nodos de modo que en vez de childNodes uses firstChild y nextSibling para acceder a todos los nodos.
Por ejemplo, en vez de: document.childNodes[0].nodeName
Usaríamos: document.firstChild.nodeName
Otro ejemplo. En vez de: document.childNodes[1].childNodes[0].nodeName
Usaríamos: document.firstChild.nextSibling.firstChild.nodeName
Vete probando el código línea a línea. Ten en cuenta que tu navegador podría no reconocer alguna palabra clave. Ten en cuenta que una referencia a un nodo no válida hará que no se ejecute tu código.
Para comprobar si tu respuesta es correcta puedes consultar en los foros aprenderaprogramar.com.
Para acceder a la información general sobre este curso y al listado completo de entregas pulsa en este link: Ver curso completo.
Para hacer un comentario o consulta utiliza los foros aprenderaprogramar.com, abiertos a cualquier persona independientemente de su nivel de conocimiento.