Skip to content
This page has been auto-translated and may contain errors.View in English

Incrustación e iframes ​

docs.scrimba.com

A veces lo que quieres poner en tu página ya existe en otro lugar: un video en YouTube, una ubicación en un mapa, un formulario de pago gestionado por otra empresa. En vez de reconstruirlo, puedes colocar esa página completa dentro de la tuya. El elemento que hace esto es el <iframe>, y viene con un conjunto de controles para mantener el contenido prestado con el tamaño correcto, accesible y seguro.

El elemento iframe ​

Un iframe coloca otra página web dentro de la tuya. El nombre es la forma corta de "inline frame" (marco en línea), y esa es una buena imagen mental: una pequeña ventana enmarcada en tu página, a través de la cual se ve una página completamente separada. Un video de YouTube en una publicación de blog casi siempre es un iframe.

Lo apuntas hacia la página que quieres mostrar con el atributo src, el mismo atributo que usa una imagen para su archivo:

html
<iframe src="https://www.youtube.com/embed/aqz-KE-bpKQ"></iframe>

Esa sola etiqueta trae el reproductor de YouTube a tu página. Piénsalo como colgar una ventana en una pared: la pared es tu página, y a través de la ventana ves toda una habitación distinta.

Un <iframe> carga una página web separada y completa, y la muestra como un rectángulo dentro de la tuya. El atributo src contiene la dirección de esa página, y todo lo que hay dentro del marco (su propio HTML, CSS y JavaScript) funciona de forma independiente, separado de tu página.

html
<iframe src="https://www.openstreetmap.org/export/embed.html"></iframe>

Cualquier cosa que escribas entre la etiqueta de apertura y la de cierre es contenido de respaldo, que solo se muestra en navegadores demasiado antiguos como para soportar marcos, lo cual en la práctica no ocurre con ninguno. El marco se configura por completo mediante sus atributos, y la siguiente sección cubre los que realmente vas a usar.

Un <iframe> crea un contexto de navegación anidado: un documento completo e independiente incrustado dentro de tu documento (un contexto de navegación es el entorno en el que se ejecuta una sola página, con su propio historial, su propio ámbito global y su propia copia del DOM). El marco no forma parte del árbol DOM de tu página en ningún sentido real; es una página separada que resulta estar pintada dentro de una caja en la tuya.

Esa separación es precisamente el punto, y está impuesta por la política del mismo origen: tu página y la página enmarcada solo pueden leerse o controlarse mutuamente mediante scripts si comparten un origen (un origen es la combinación de esquema, host y puerto, así que https://example.com y https://other.com son orígenes distintos). A un marco del mismo origen puedes acceder desde JavaScript mediante iframe.contentWindow; un marco de origen distinto es una caja sellada a la que puedes apuntar pero no inspeccionar. Casi todo lo que incrustas (un video, un mapa, un widget) es de origen distinto, y por eso mismo es seguro incrustarlo.

JunoEl elemento iframe Un <iframe> muestra toda una página web distinta dentro de la tuya, como una pequeña ventana que da a otra habitación. Lo apuntas a algún lugar con src, igual que haces con una imagen. ¿Ese reproductor de YouTube en un blog? Casi siempre es uno de estos.
JunoEl elemento iframe Un <iframe> carga una página separada y autocontenida, y la muestra en una caja dentro de la tuya. Su propio HTML, CSS y JavaScript se mantienen aislados de tu página. Lo configuras completamente mediante atributos, empezando por src.
JunoEl elemento iframe Un marco es un contexto de navegación anidado: un documento completamente separado con su propio ámbito y su propio DOM, no una rama del tuyo. La política del mismo origen es lo que lo mantiene sellado, así que una incrustación de origen distinto puede mostrarse pero no puede ser controlada por script desde tu página. Ese muro es la característica, no una limitación que haya que evitar.

Incrustar videos, mapas y widgets ​

La buena noticia: casi nunca escribes código de incrustación a mano. El sitio desde el que estás incrustando lo escribe por ti. En YouTube haces clic en Compartir, luego en Insertar, y te entrega un <iframe> ya armado para copiar. Los mapas, reproductores de música y calendarios funcionan igual. Copias su bloque y lo pegas en tu HTML.

html
<iframe src="https://www.youtube.com/embed/aqz-KE-bpKQ" width="560" height="315"></iframe>

width y height definen el tamaño del marco, medido en píxeles. Cambia esos dos números y el video se agranda o se achica en tu página.

La mayoría del código de incrustación viene directo de la fuente. Busca un botón de Compartir o Insertar, y el servicio te entrega un bloque <iframe> con el tamaño y el destino ya definidos. Vale la pena entender tres atributos en vez de solo pegarlos:

html
<iframe
  src="https://www.youtube.com/embed/aqz-KE-bpKQ"
  width="560"
  height="315"
  title="Cortometraje Big Buck Bunny"
  loading="lazy"
></iframe>

width y height definen el tamaño del marco en píxeles. El atributo title le da un nombre al marco para los lectores de pantalla, que lo anuncian de la misma forma en que anuncian el texto de un enlace, así que un marco sin título se lee como un "frame" sin etiqueta y no le sirve a nadie. loading="lazy" le dice al navegador que espere para descargar la página enmarcada hasta que el lector se acerque desplazándose, lo cual evita que las incrustaciones más abajo en la página frenen la carga inicial.

Para un marco que deba ajustarse a su contenedor en vez de tener un tamaño fijo en píxeles, elimina los atributos width y height y define el tamaño con CSS, usando aspect-ratio para mantener las proporciones correctas de un video.

El fragmento de incrustación que te entrega un servicio es un punto de partida razonable, no una decisión terminada. Unos pocos atributos determinan qué tan bien se comporta en producción.

html
<iframe
  src="https://www.youtube-nocookie.com/embed/aqz-KE-bpKQ"
  title="Cortometraje Big Buck Bunny"
  loading="lazy"
  referrerpolicy="strict-origin-when-cross-origin"
  allowfullscreen
  style="width: 100%; aspect-ratio: 16 / 9; border: 0;"
></iframe>

title no es opcional en la práctica: la tecnología de asistencia (software como los lectores de pantalla que leen la página en voz alta) trata un marco como un landmark y anuncia su título, así que si falta, deja una región en blanco en el orden de lectura. loading="lazy" posterga la carga del documento del marco hasta que se acerca al viewport (el área visible de la página), y esto importa muchísimo aquí porque cada marco es la carga de una página completa, no de un solo recurso. referrerpolicy controla cuánta información de la URL de tu página se envía al servicio incrustado en el encabezado Referer (el campo que un navegador adjunta para indicarle a un servidor de dónde vino una solicitud), y restringirlo filtra menos información sobre tus usuarios. Define el tamaño de forma responsiva con aspect-ratio en vez de píxeles fijos, para que el marco se reajuste en pantallas pequeñas. El hábito que vale la pena mantener: lee el fragmento antes de pegarlo, porque estás heredando cualquier configuración predeterminada que haya elegido el proveedor.

JunoIncrustar videos, mapas y widgets Casi nunca escribes tú mismo el código de incrustación. Busca el botón Compartir o Insertar en YouTube, un mapa o un reproductor, y te entrega un <iframe> para pegar. Cambia width y height para redimensionarlo. Eso es la mayor parte del trabajo.
JunoIncrustar videos, mapas y widgets Toma el código de incrustación de la fuente y luego ordénalo. Agrega siempre un title para que los lectores de pantalla puedan nombrar el marco, y loading="lazy" para que un marco más abajo en la página no frene la primera pintura. Para un tamaño flexible, quita el ancho y alto en píxeles y usa aspect-ratio de CSS.
JunoIncrustar videos, mapas y widgets El fragmento del proveedor es solo un punto de partida. title para el orden de lectura, loading="lazy" porque un marco es la carga de una página entera y no de un solo recurso, un referrerpolicy restrictivo para filtrar menos información de tus usuarios, y aspect-ratio para un tamaño responsivo. Lee lo que pegas, porque heredas cada valor predeterminado que ellos elegieron.

Sandboxing y permisos ​

Como un marco ejecuta toda otra página, quizás quieras limitar lo que esa página tiene permitido hacer. El atributo sandbox hace exactamente eso: pone al marco detrás de una cerca de seguridad.

html
<iframe src="widget.html" sandbox></iframe>

Con sandbox solo, sin más valores, la página enmarcada queda sujeta a la configuración más estricta: no puede ejecutar sus propios scripts, enviar formularios ni abrir ventanas nuevas. Luego le devuelves permisos específicos uno a la vez, solo los que la incrustación realmente necesita. Piénsalo como prestarle a alguien una habitación pero dejar con llave los armarios que no quieres que abra.

Dos atributos controlan lo que a un marco se le permite hacer. sandbox restringe el marco, y allow otorga acceso a funciones del dispositivo y del navegador.

Agregar sandbox sin ningún valor bloquea casi todo lo que la página enmarcada podría hacer: scripts, formularios, ventanas emergentes y considerarse a sí misma del mismo origen. Lo relajas listando tokens de permisos separados por espacios:

html
<iframe
  src="https://example.com/widget"
  sandbox="allow-scripts allow-forms"
></iframe>

allow-scripts deja que el marco ejecute JavaScript, allow-forms deja que envíe formularios, allow-popups deja que abra ventanas nuevas. Otorga solo lo que la incrustación necesita. El atributo separado allow rige funciones sensibles del navegador como pantalla completa, cámara y micrófono:

html
<iframe src="https://example.com/call" allow="camera; microphone; fullscreen"></iframe>

Si una función no está listada en allow, la página enmarcada no puede usarla, aunque su propio código la solicite.

Aquí hay dos modelos distintos, y vale la pena mantenerlos separados. sandbox le quita capacidades al marco; allow otorga acceso a funciones restringidas. No son dos formas de escribir lo mismo.

sandbox sin ningún valor aplica todas las restricciones a la vez: sin scripts, sin envío de formularios, sin ventanas emergentes, sin reproducción automática de medios, y, algo importante, el marco queda forzado a un origen opaco único (un origen que no coincide con ningún otro, así que el marco no puede alegar ser del mismo origen que nadie, ni siquiera del sitio desde el que se cargó). Vas devolviendo capacidades con tokens:

html
<iframe
  src="https://example.com/widget"
  sandbox="allow-scripts allow-popups allow-popups-to-escape-sandbox"
></iframe>

Hay una combinación que debes evitar. Otorgarle tanto allow-scripts como allow-same-origin a un marco que carga desde tu propio origen permite que la página enmarcada ejecute código capaz de alcanzar hacia fuera y quitarse su propio sandbox, lo que anula el propósito. Combina esos dos solo cuando confías completamente en el contenido del marco.

El atributo allow es una Política de Permisos (un mecanismo del navegador para decidir qué páginas pueden usar funciones sensibles como la cámara, el micrófono, la geolocalización o pantalla completa). Su valor predeterminado es denegar: una función que no se nombre en allow no está disponible para el marco sin importar lo que su script solicite. Así es como colocas un widget de videollamada que necesita la cámara sin entregarle también esa cámara a cualquier otro marco de la página.

JunoSandboxing y permisos Agrega sandbox a un marco y bloquea la página incrustada: sin scripts, sin ventanas emergentes, sin travesuras. Luego le devuelves solo los permisos que realmente necesita. Es como prestar una habitación pero dejar algunos armarios con llave.
JunoSandboxing y permisossandbox restringe un marco y lo relajas token por token, como allow-scripts y allow-forms. El atributo separado allow es el que otorga cámara, micrófono o pantalla completa. Dale a cada uno solo lo que la incrustación realmente pide.
JunoSandboxing y permisos Mantén los dos modelos claros: sandbox quita capacidades, allow otorga funciones restringidas y su valor predeterminado es denegar. La trampa es combinar allow-scripts con allow-same-origin en un marco del mismo origen, porque eso le permite a la página desbloquear su propio sandbox. Hazlo solo cuando confíes plenamente en lo que hay dentro.

Precauciones de seguridad y rendimiento ​

Las incrustaciones son útiles, pero cada marco carga toda una página adicional, así que una pila de ellas puede hacer que la tuya se sienta lenta. Dos hábitos te mantienen fuera de problemas: incrusta solo desde sitios en los que confíes, ya que estás invitando su página a la tuya, y no agregues más marcos de los que necesitas.

El atributo loading="lazy" de antes también ayuda aquí, reteniendo los marcos hasta que el lector se desplaza hacia ellos. Recurre a una incrustación cuando te ahorre trabajo real, como un video o un mapa, y evítala cuando un simple enlace haría el mismo trabajo.

Cada marco que agregas es la carga de una página completa: su propio HTML, su propio CSS y a menudo su propia pila de JavaScript, todo obtenido desde otro servidor. Una página con tres incrustaciones de terceros en realidad son cuatro páginas cargando a la vez, y por eso las páginas cargadas de incrustaciones se sienten pesadas. loading="lazy" en marcos fuera de pantalla es la ganancia más barata, y preferir una sola incrustación en vez de tres es el siguiente paso.

Hay una segunda preocupación además de la velocidad. Puedes proteger tu propia página para que no pueda colocarse dentro del marco de otra persona, lo cual detiene un truco donde un atacante enmarca tu sitio y engaña a los usuarios para que hagan clic en cosas que no pueden ver. Esa protección se define en el servidor, y el nivel Deep Dive cubre los dos encabezados que lo logran.

Vale la pena mirar con claridad dos costos: lo que un marco le hace a tu rendimiento, y lo que la incrustación puede hacerle a tu seguridad.

En cuanto al rendimiento, un marco de terceros no es una sola solicitud; es una carga de documento anidada que ejecuta toda la pila del proveedor (su marcado, estilos, fuentes, analítica y scripts) dentro de tu página. Compite por la misma red y el mismo hilo principal, y sus scripts corren en su propio contexto pero en el mismo dispositivo, así que una incrustación pesada puede retrasar que tu propio contenido se vuelva interactivo. loading="lazy" posterga los marcos fuera de pantalla, y consolidar incrustaciones supera a optimizar una sola. Mide el costo real antes de asumir que una incrustación es gratis.

En cuanto a la seguridad, el riesgo se llama clickjacking: un atacante carga tu página en un marco dentro de su propio sitio, la hace invisible o la superpone, y engaña a un usuario con sesión iniciada para que haga clic en un control real de tu página sin darse cuenta. La defensa consiste en declarar quién, si alguien, puede enmarcar tus páginas, y se define con un encabezado de respuesta en tu servidor, no en el HTML:

  • X-Frame-Options: DENY impide que tu página se cargue en cualquier marco. SAMEORIGIN permite que solo tu propio sitio la enmarque. Este es el control más antiguo y más tosco.
  • Content-Security-Policy: frame-ancestors 'self' es el reemplazo moderno. frame-ancestors lista exactamente qué orígenes pueden enmarcar tu página (una Content-Security-Policy, o CSP, es un encabezado que le indica al navegador qué fuentes de contenido y comportamiento permitir). Sustituye a X-Frame-Options, permite una lista específica de sitios permitidos en vez de una sola regla general, y es el que debes definir en cualquier cosa que tenga un inicio de sesión o un formulario.

Fíjate en la dirección: sandbox y allow controlan las páginas que tú incrustas, mientras que frame-ancestors y X-Frame-Options controlan quién puede incrustarte a ti. Ambas direcciones importan, y se configuran en lugares distintos.

JunoPrecauciones de seguridad y rendimiento Cada marco carga toda una página adicional, así que un montón de ellos vuelve lenta la tuya. Incrusta solo desde sitios en los que confíes, mantén la cantidad baja y apóyate en loading="lazy". Si un simple enlace haría el mismo trabajo, usa el enlace.
JunoPrecauciones de seguridad y rendimiento Tres incrustaciones significan cuatro páginas cargando a la vez, así que trata cada marco como un costo real. loading="lazy" en marcos fuera de pantalla es la ganancia barata, y menos incrustaciones supera a optimizar una sola. También existe un riesgo de enmarcado del que hay que cuidarse, y el nivel Deep Dive lo cubre con dos encabezados del servidor.
JunoPrecauciones de seguridad y rendimiento Un marco de terceros ejecuta toda la pila del proveedor dentro de tu página y compite por tu red y tu hilo principal, así que mide antes de asumir que es barato. En cuanto a seguridad, detén el clickjacking declarando quién puede enmarcarte: frame-ancestors en una CSP es el control moderno, X-Frame-Options el más antiguo. Recuerda la dirección: sandbox protege las páginas que tú incrustas y frame-ancestors protege quién te incrusta a ti.