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

Embedding e iframes ​

docs.scrimba.com

Às vezes, o que você quer colocar na sua página já existe em outro lugar: um vídeo no YouTube, uma localização em um mapa, um formulário de pagamento operado por outra empresa. Em vez de recriar isso do zero, você pode colocar a página inteira dentro da sua. O elemento que faz isso é o <iframe>, e ele vem com um conjunto de controles para manter o conteúdo emprestado com o tamanho certo, acessível e seguro.

O elemento iframe ​

Um iframe coloca outra página da web dentro da sua. O nome é a abreviação de "inline frame" (moldura em linha), e essa é uma boa imagem para entender: uma pequena janela emoldurada na 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ê aponta ele para a página que quer mostrar com o atributo src, o mesmo atributo que uma imagem usa para o seu arquivo:

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

Essa única tag traz o player do YouTube para a sua página. Pense nisso como pendurar uma janela em uma parede: a parede é a sua página, e através da janela você vê um cômodo 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 guarda o endereço dessa página, e tudo dentro do frame, seu próprio HTML, CSS e JavaScript, roda de forma independente, mantido separado da sua página.

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

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

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 é executada, 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 nenhuma forma relevante; é uma página separada que, por acaso, é desenhada dentro de uma caixa na sua.

Essa separação é justamente o objetivo, e ela é garantida pela política de mesma origem (same-origin policy): a sua página e a página emoldurada só conseguem ler ou executar scripts uma na outra se compartilharem a mesma origem (uma origem é a combinação de esquema, host e porta, então https://exemplo.com e https://outro.com são origens diferentes). Um frame de mesma origem você consegue alcançar com JavaScript por meio de iframe.contentWindow; um frame de origem diferente é uma caixa fechada que você pode apontar, mas não inspecionar. Praticamente todo embed que você coloca, um vídeo, um mapa, um widget, é de origem diferente, e é exatamente por isso que é seguro colocá-lo ali.

JunoO elemento iframe Um <iframe> mostra uma página da web completamente diferente dentro da sua, como uma pequena janela dando vista para outro cômodo. Você aponta ele para algum 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 autocontida, e a mostra em uma caixa na sua. O próprio HTML, CSS e JavaScript dela ficam isolados da sua página. Você configura tudo por meio de atributos, começando pelo src.
JunoO elemento iframe Um frame é um contexto de navegação aninhado: um documento totalmente separado com seu próprio escopo e DOM, não um ramo do seu. A política de mesma origem é o que mantém isso isolado, então um embed de origem diferente pode ser exibido, mas não manipulado por script pela sua página. Essa barreira é o recurso, não uma limitação para contornar.

Incorporando vídeos, mapas e widgets ​

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

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

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

A maior parte do código de embed vem direto da fonte. Procure por um botão de Compartilhar ou Incorporar, e o serviço te entrega um bloco <iframe> já dimensionado e configurado. Três atributos vale a pena entender, e não só colar:

html
<iframe
  src="https://www.youtube.com/embed/aqz-KE-bpKQ"
  width="560"
  height="315"
  title="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 title é lido como um "frame" sem rótulo e não ajuda ninguém. loading="lazy" diz ao navegador para esperar antes de baixar a página emoldurada até o leitor rolar até perto dela, o que evita que embeds mais abaixo na página deixem o carregamento inicial mais lento.

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

O trecho de embed que um serviço te entrega é um padrão razoável, não uma decisão final. Alguns atributos determinam o quão bem ele se comporta em produção.

html
<iframe
  src="https://www.youtube-nocookie.com/embed/aqz-KE-bpKQ"
  title="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 (softwares como leitores de tela, que leem a página em voz alta) trata um frame como um ponto de referência e anuncia seu título, então a ausência dele deixa uma região em branco na ordem de leitura. loading="lazy" posterga o carregamento do documento do frame até ele se aproximar da viewport (a área visível da página), o que importa bastante aqui porque cada frame é o carregamento de uma página completa, não de um único recurso. referrerpolicy controla quanto da URL da sua página é enviado ao serviço incorporado no cabeçalho Referer (o campo que um navegador anexa para dizer a um servidor de onde veio uma requisição), e restringi-lo revela menos sobre os seus usuários. Dimensione de forma responsiva com aspect-ratio em vez de pixels fixos, para que o frame se reajuste em telas pequenas. O hábito que vale manter: leia o trecho antes de colar, porque você está herdando quaisquer padrões que o provedor escolheu.

JunoIncorporando vídeos, mapas e widgets Você quase nunca escreve o código de embed sozinho. Encontre o botão Compartilhar ou Incorporar no YouTube, em um mapa ou em um player, e ele te entrega um <iframe> para colar. Mude width e height para redimensionar. Isso é a maior parte do trabalho.
JunoIncorporando vídeos, mapas e widgets Pegue o código de embed da fonte e depois ajeite. Sempre adicione um title para que os leitores de tela possam nomear o frame, e loading="lazy" para que um frame mais abaixo na página não atrase a primeira renderização. Para um dimensionamento flexível, retire a largura e altura em pixels e use o CSS aspect-ratio.
JunoIncorporando vídeos, mapas e widgets O trecho do provedor é só um ponto de partida. title para a ordem de leitura, loading="lazy" porque um frame é o carregamento de uma página inteira e não de um único recurso, um referrerpolicy restrito para revelar menos sobre seus usuários, e aspect-ratio para dimensionamento responsivo. Leia o que você cola, já que você herda cada padrão que eles escolheram.

Sandboxing e permissões ​

Como um frame executa uma página completamente diferente, você pode querer limitar o que essa página tem permissão de fazer. O atributo sandbox faz exatamente isso: ele 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 fica sujeita à configuração mais estrita possível: 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 a uma, apenas as que o embed realmente precisa. Pense nisso como emprestar um cômodo a alguém, mas trancar os armários que você não quer que sejam abertos.

Dois atributos controlam o que um frame tem permissão de fazer. sandbox restringe o frame, e allow concede acesso a recursos do dispositivo e do navegador.

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

html
<iframe
  src="https://exemplo.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 separado allow rege recursos sensíveis do navegador, como tela cheia, câmera e microfone:

html
<iframe src="https://exemplo.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 peça.

Existem dois modelos distintos aqui, e vale a pena mantê-los separados. sandbox remove capacidades do frame; allow concede acesso a recursos protegidos. Não são duas formas de escrever a mesma coisa.

sandbox sem nenhum valor aplica todas as restrições de uma vez: nenhum script, nenhum envio de formulário, nenhum popup, nenhuma mídia com autoplay e, o mais importante, o frame é forçado a assumir uma origem opaca única (uma origem que não corresponde a nenhuma outra, então o frame não pode se declarar de mesma origem com ninguém, incluindo o site do qual foi carregado). Você adiciona capacidades de volta com tokens:

html
<iframe
  src="https://exemplo.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 a partir da sua própria origem permite que a página emoldurada execute código capaz de alcançar de volta e remover seu próprio sandbox, o que anula todo o propósito. Combine essas duas apenas quando o conteúdo do frame for totalmente confiável.

O atributo allow é uma Permissions Policy (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 fica indisponível para o frame, não importa o que o script dele solicite. É assim que você coloca um widget de chamada de vídeo que precisa da câmera sem também entregar essa câmera a todos os outros frames da página.

JunoSandboxing e permissões Adicione sandbox a um frame e ele trava a página incorporada: nenhum script, nenhum popup, nenhuma travessura. Depois você devolve apenas as permissões que ela realmente precisa. É como emprestar um cômodo, mas manter alguns armários trancados.
JunoSandboxing e permissõessandbox restringe um frame e você relaxa isso token por token, como allow-scripts e allow-forms. O atributo separado allow é o que concede câmera, microfone ou tela cheia. Dê a cada embed apenas o que ele realmente pede.
JunoSandboxing e permissões Mantenha os dois modelos separados na sua cabeça: sandbox remove capacidades, allow concede recursos protegidos e nega por padrão. A armadilha é combinar allow-scripts com allow-same-origin em um frame de mesma origem, já que isso permite que a página destranque seu próprio sandbox. Só faça isso quando confiar totalmente no que está dentro.

Cuidados com segurança e performance ​

Embeds são úteis, mas cada frame carrega uma página inteira extra, então uma pilha deles pode deixar a sua com uma sensação de lentidão. Dois hábitos te mantêm fora de problemas: incorpore apenas de sites em que você confia, já que você está convidando a página deles para dentro da sua, e não adicione mais frames do que você precisa.

O atributo loading="lazy" visto antes também ajuda aqui, retendo os frames até o leitor rolar até eles. Use um embed quando ele te poupar trabalho de verdade, como um vídeo ou um mapa, e evite quando um link simples fizer o mesmo trabalho.

Cada frame que você adiciona é o carregamento de uma página completa: seu próprio HTML, seu próprio CSS e, frequentemente, sua própria pilha de JavaScript, tudo obtido de outro servidor. Uma página com três embeds de terceiros é, na prática, quatro páginas carregando ao mesmo tempo, e é por isso que páginas cheias de embeds parecem pesadas. loading="lazy" em frames fora da tela é o ganho mais barato, e preferir um embed a três é o próximo passo.

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

Dois custos merecem um olhar atento e sem ilusões: o que um frame faz com a sua performance, e o que a incorporação pode fazer com a sua segurança.

Em termos de performance, um frame de terceiros não é uma única requisição; é o carregamento de um documento aninhado que executa toda a pilha do provedor (o markup, os estilos, as fontes, a análise de dados e os scripts dele) dentro da sua página. Ele compete pela mesma rede e pela mesma thread principal, e seus scripts rodam em seu próprio contexto, mas no mesmo dispositivo, então um embed pesado pode atrasar o momento em que o seu próprio conteúdo se torna interativo. loading="lazy" posterga frames fora da tela, e consolidar embeds vale mais do que otimizar um único deles. Meça o custo real antes de assumir que um embed é de graça.

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

  • X-Frame-Options: DENY recusa deixar a sua página carregar em qualquer frame. SAMEORIGIN permite que apenas o seu próprio site a emolde. Esse é o controle mais antigo e mais rígido.
  • Content-Security-Policy: frame-ancestors 'self' é o substituto moderno. frame-ancestors lista exatamente quais origens podem emoldurar a 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 o X-Frame-Options, permite uma lista de permissões específica em vez de uma regra única e geral, e é a que você deve definir em qualquer página com login ou 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 incorporar você. As duas direções importam, e são configuradas em lugares diferentes.

JunoCuidados com segurança e performance Cada frame carrega uma página inteira extra, então uma pilha deles deixa a sua mais lenta. Incorpore apenas de sites em que você confia, mantenha a quantidade baixa e conte com loading="lazy". Se um link simples fizer o mesmo trabalho, use o link.
JunoCuidados com segurança e performance 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 é o ganho barato, e menos embeds vale mais do que otimizar um só. Há também um risco de incorporação que vale a pena se proteger, e o Deep Dive aborda isso com dois cabeçalhos de servidor.
JunoCuidados com segurança e performance Um frame de terceiros executa toda a pilha do provedor dentro da sua página e compete pela sua rede e pela sua thread principal, então meça antes de assumir que é barato. Em segurança, evite o clickjacking declarando quem pode te emoldurar: 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 incorpora você.