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

Incorporação e iframes

docs.scrimba.com

Às vezes, a coisa que você quer em sua página já vive em outro lugar: um vídeo no YouTube, um local em um mapa, um formulário de pagamento executado por outra empresa. Em vez de reconstruir, você pode colocar essa página inteira dentro da sua. O elemento que faz isso é o <iframe>, e vem com um conjunto de controles para manter o conteúdo emprestado dimensionado, acessível e seguro.

O elemento iframe

Um iframe coloca outra página da web dentro da sua. O nome é abreviação para "inline frame", e é uma boa imagem disso: uma pequena janela emoldurada em sua página, com uma página completamente separada aparecendo através dela. Um vídeo do YouTube em um post de blog é quase sempre um iframe.

Você a aponta para a página que quer mostrar com o atributo src, o mesmo atributo que uma imagem usa para seu arquivo:

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

Essa única tag coloca o player do YouTube em sua página. Pense nisso como pendurar uma janela em uma parede: a parede é sua página, e através da janela você vê uma sala completamente diferente.

Um <iframe> carrega uma página da web separada e completa e a exibe como um retângulo dentro da sua. O atributo src contém o endereço dessa página, e tudo dentro do frame, seu próprio HTML, CSS e JavaScript, funciona independentemente, separado de sua página.

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

Qualquer coisa que você escreva entre as tags de abertura e fechamento é conteúdo de fallback, mostrado apenas por navegadores muito antigos que não suportam frames, o que na prática não é nenhum deles. O frame é configurado inteiramente através de seus atributos, e a próxima seção aborda os que você realmente irá definir.

Um <iframe> cria um contexto de navegação aninhado: um documento completo e independente incorporado dentro do seu documento (um contexto de navegação é o ambiente em que uma única página funciona, com seu próprio histórico, seu próprio escopo global e sua própria cópia do DOM). O frame não faz parte da árvore DOM da sua página de forma significativa; é uma página separada que acontece de ser desenhada dentro de uma caixa na sua.

Essa separação é o ponto inteiro, e é aplicada pela política de mesma origem: sua página e a página emoldurada só podem ler ou fazer script uma da outra se compartilharem uma origem (uma origem é a combinação de esquema, host e porta, então https://example.com e https://other.com são origens diferentes). Um frame de mesma origem que você pode alcançar com JavaScript através de iframe.contentWindow; um frame de origem diferente é uma caixa selada que você pode apontar mas não inspecionar. Quase todo embed que você coloca, um vídeo, um mapa, um widget, é de origem diferente, o que é exatamente por que é seguro colocar em primeiro lugar.

JunoO elemento iframe Um <iframe> mostra uma página da web inteira dentro da sua, como uma pequena janela olhando para outra sala. Você a aponta para um lugar com src, do mesmo jeito que uma imagem faz. Aquele player do YouTube em um blog? Quase sempre é um desses.
JunoO elemento iframe Um <iframe> carrega uma página separada e autossuficiente e a mostra em uma caixa na sua. Seu próprio HTML, CSS e JavaScript ficam isolados da sua página. Você o configura inteiramente através de atributos, começando com src.
JunoO elemento iframe Um frame é um contexto de navegação aninhado: um documento completamente separado com seu próprio escopo e DOM, não uma ramificação do seu. A política de mesma origem é o que o mantém selado, então um embed de origem diferente pode ser mostrado mas não executado por script na sua página. Esse muro é a funcionalidade, não uma limitação para contornar.

Incorporando vídeo, mapas e widgets

A boa notícia: você raramente escreve código de embed à mão. O site de onde você está incorporando escreve para você. No YouTube você clica em Compartilhar, depois em Incorporar, e ele lhe dá um <iframe> pronto para copiar. Mapas, players de música e calendários funcionam da mesma forma. Você copia seu bloco e cola no seu HTML.

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

O width e height definem o tamanho do frame, medido em pixels. Altere esses dois números e o vídeo fica maior ou menor em sua página.

A maioria do código de embed vem direto da fonte. Procure por um botão Compartilhar ou Incorporar, e o serviço lhe dá um bloco <iframe> dimensionado e apontado para você. Três atributos valem a pena ser compreendidos em vez de apenas colar:

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

width e height definem o tamanho do frame em pixels. O atributo title nomeia o frame para leitores de tela, que o anunciam da mesma forma que anunciam o texto de um link, então um frame sem um título é lido como um "frame" não rotulado e não ajuda ninguém. loading="lazy" diz ao navegador para adiar o download da página emoldurada até o leitor rolar perto dela, o que mantém embeds baixos na página de desacelerar o carregamento inicial.

Para um frame que deve se estender para caber em seu contêiner em vez de um tamanho fixo em pixels, remova os atributos width e height e dimensione-o com CSS, usando aspect-ratio para manter as proporções corretas de um vídeo.

O snippet de embed que um serviço lhe dá é um padrão razoável, não uma decisão final. Alguns atributos decidem como ele se comporta bem em produção.

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

title não é opcional na prática: tecnologia assistiva (software como leitores de tela que leem a página em voz alta) trata um frame como um landmark e anuncia seu título, então um ausente deixa uma região em branco na ordem de leitura. loading="lazy" adia o carregamento do documento do frame até ele se aproximar da janela de visualização (a área visível da página), o que importa muito aqui porque cada frame é um carregamento de página completo, não um único ativo. referrerpolicy controla quanto da URL da sua página é enviado para o serviço incorporado no cabeçalho Referer (o campo que um navegador anexa para dizer a um servidor de onde uma solicitação veio), e apertá-lo vaza menos sobre seus usuários. Dimensione responsivamente com aspect-ratio em vez de pixels fixos para que o frame reflua em telas pequenas. O único hábito que vale a pena manter: leia o snippet antes de colar, porque você está herdando os padrões que o provedor escolheu.

JunoIncorporando vídeo, mapas e widgets Você quase nunca escreve código de embed você mesmo. Encontre o botão Compartilhar ou Incorporar no YouTube, um mapa ou um player, e ele lhe dá um <iframe> para colar. Altere width e height para redimensioná-lo. Esse é a maior parte do trabalho.
JunoIncorporando vídeo, mapas e widgets Pegue o código de embed da fonte, depois organize-o. Sempre adicione um title para que leitores de tela possam nomear o frame, e loading="lazy" para que um frame no meio da página não desacelere a primeira pintura. Para dimensionamento flexível, remova a altura e largura em pixels e use CSS aspect-ratio.
JunoIncorporando vídeo, mapas e widgets O snippet do provedor é um ponto de partida. title para a ordem de leitura, loading="lazy" porque um frame é um carregamento de página completo e não um único ativo, uma referrerpolicy apertada para que você vaze menos sobre seus usuários, e aspect-ratio para dimensionamento responsivo. Leia o que você cola, já que você herda todos os padrões que eles escolheram.

Sandboxing e permissões

Porque um frame executa uma página inteira diferente, você pode querer limitar o que essa página é permitida fazer. O atributo sandbox faz exatamente isso: coloca o frame atrás de uma cerca de segurança.

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

Com sandbox sozinho, a página emoldurada é mantida na configuração mais estrita: ela não pode executar seus próprios scripts, enviar formulários ou abrir novas janelas. Você então devolve permissões específicas uma de cada vez, apenas as que o embed realmente precisa. Pense nisso como emprestar uma sala para alguém mas trancar os armários que você não quer abertos.

Dois atributos controlam o que um frame é permitido fazer. sandbox restringe o frame, e allow concede acesso a recursos de dispositivo e navegador.

Adicionar sandbox sem um valor bloqueia quase tudo o que a página emoldurada poderia fazer: scripts, formulários, popups e se tratar como mesma-origem. Você o afrouxar listando tokens de permissão separados por espaço:

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

allow-scripts permite que o frame execute JavaScript, allow-forms permite que ele envie formulários, allow-popups permite que ele abra novas janelas. Conceda apenas o que o embed precisa. O atributo allow separado governa recursos sensíveis do navegador como tela cheia, câmera e microfone:

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

Se um recurso não estiver listado em allow, a página emoldurada não pode usá-lo, mesmo que seu próprio código o solicite.

Dois modelos distintos estão aqui, e vale a pena mantê-los separados. sandbox remove capacidades do frame; allow concede acesso a recursos fechados. Não são duas ortografias da mesma coisa.

sandbox sem um valor aplica cada restrição de uma vez: sem scripts, sem envio de formulário, sem popups, sem mídia com reprodução automática, e, importantemente, o frame é forçado em uma origem opaca única (uma origem que não corresponde a nada mais, então o frame não pode afirmar ser mesma-origem com ninguém, incluindo o site de onde foi carregado). Você adiciona capacidades de volta com tokens:

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

Há uma combinação a evitar. Conceder tanto allow-scripts quanto allow-same-origin a um frame que carrega da sua própria origem permite que a página emoldurada execute código que pode se estender e remover seu próprio sandbox, o que derrota o objetivo. Apenas emparelhe esses dois quando o conteúdo do frame é totalmente confiável.

O atributo allow é uma Política de Permissões (um mecanismo do navegador para decidir quais páginas podem usar recursos sensíveis como câmera, microfone, geolocalização ou tela cheia). Seu padrão é negar: um recurso não nomeado em allow não está disponível para o frame não importa o que seu script solicite. É assim que você coloca um widget de chamada de vídeo que precisa da câmera sem também entregar essa câmera para cada outro frame na página.

JunoSandboxing e permissões Adicione sandbox a um frame e ele bloqueia a página incorporada: sem scripts, sem popups, sem travessuras. Então você devolve apenas as permissões que ela realmente precisa. É como emprestar uma sala mas manter alguns armários fechados.
JunoSandboxing e permissõessandbox restringe um frame e você o afrouxar token por token, como allow-scripts e allow-forms. O atributo allow separado é o que concede câmera, microfone ou tela cheia. Dê a cada um apenas o que o embed realmente pede.
JunoSandboxing e permissões Mantenha os dois modelos em linha reta: sandbox tira capacidades, allow concede recursos fechados e traz como padrão negar. A armadilha é emparelhar allow-scripts com allow-same-origin em um frame de mesma origem, já que isso permite que a página desbloqueie seu próprio sandbox. Faça isso apenas quando você confiar totalmente no que está dentro.

Cautelas de segurança e desempenho

Os embeds são convenientes, mas cada frame carrega uma página extra inteira, então uma pilha deles pode fazer a sua se sentir lenta. Dois hábitos o mantêm fora do problema: incorpore apenas de sites que você confia, já que você está convidando sua página para a sua, e não adicione mais frames do que precisa.

O atributo loading="lazy" de antes também ajuda aqui, retendo frames até o leitor rolar para eles. Recorra a um embed quando economiza trabalho real, como um vídeo ou um mapa, e pule quando um link simples faria o mesmo trabalho.

Cada frame que você adiciona é um carregamento de página completo: seu próprio HTML, seu próprio CSS e frequentemente sua própria pilha de JavaScript, tudo buscado de outro servidor. Uma página com três embeds de terceiros é realmente quatro páginas carregando ao mesmo tempo, que é por que páginas com muitos embeds se sentem pesadas. loading="lazy" em frames fora da tela é a vitória mais barata, e preferir um embed sobre três é a próxima.

Há uma segunda preocupação além da velocidade. Você pode proteger sua própria página de ser colocada dentro do frame de outra pessoa, o que para um truque onde um atacante emoldura seu site e engana usuários a clicar em coisas que eles não conseguem ver. Essa proteção é definida no servidor, e o nível avançado aborda os dois cabeçalhos que fazem isso.

Dois custos merecem um olhar claro: o que um frame faz para seu desempenho, e o que framing pode fazer para sua segurança.

No desempenho, um frame de terceiro não é uma única solicitação; é um carregamento de documento aninhado que executa a pilha completa do provedor (sua marcação, estilos, fontes, análise e scripts) dentro da sua página. Ele compete pelos mesmos recursos de rede e thread principal, e seus scripts funcionam em seu próprio contexto mas no mesmo dispositivo, então um embed pesado pode atrasar seu próprio conteúdo de se tornar interativo. loading="lazy" adia frames fora da tela, e consolidar embeds vence afinar qualquer um deles. Meça o custo real antes de assumir que um embed é gratuito.

Na segurança, o risco é clickjacking: um atacante carrega sua página em um frame em seu próprio site, a torna invisível ou a sobrepõe, e atrai um usuário conectado a clicar em um controle real da sua página sem perceber. A defesa é declarar quem, se alguém, pode emoldurar suas páginas, e é definido com um cabeçalho de resposta no seu servidor, não no HTML:

  • X-Frame-Options: DENY recusa deixar sua página carregar em qualquer frame. SAMEORIGIN permite apenas seu próprio site emoldurá-la. Esse é o controle mais antigo e mais grosseiro.
  • Content-Security-Policy: frame-ancestors 'self' é a substituição moderna. frame-ancestors lista exatamente quais origens podem emoldurar sua página (uma Content-Security-Policy, ou CSP, é um cabeçalho que diz ao navegador quais fontes de conteúdo e comportamento permitir). Ela substitui X-Frame-Options, permite uma lista de permissão específica em vez de uma regra única geral, e é a que deve ser definida em qualquer coisa com um login ou um formulário.

Observe a direção: sandbox e allow controlam páginas que você incorpora, enquanto frame-ancestors e X-Frame-Options controlam quem pode incorporá-lo. Ambas as direções importam, e são configuradas em diferentes lugares.

JunoCautelas de segurança e desempenho Cada frame carrega uma página extra inteira, então uma pilha deles desacelera a sua. Incorpore apenas de sites que você confia, mantenha a contagem baixa e apoie-se em loading="lazy". Se um link simples faria o mesmo trabalho, use o link.
JunoCautelas de segurança e desempenho Três embeds significam quatro páginas carregando ao mesmo tempo, então trate cada frame como um custo real. loading="lazy" em frames fora da tela é a vitória barata, e menos embeds vence afinar um. Há também um risco de framing que vale a pena se guardar, que o mergulho profundo aborda com dois cabeçalhos de servidor.
JunoCautelas de segurança e desempenho Um frame de terceiro executa a pilha inteira do provedor dentro da sua página e compete por sua rede e thread principal, então meça antes de assumir que é barato. Na segurança, pare clickjacking declarando quem pode emoldurá-lo: frame-ancestors em uma CSP é o controle moderno, X-Frame-Options o mais antigo. Lembre-se da direção, já que sandbox protege páginas que você incorpora e frame-ancestors protege quem o incorpora.