Como aplicar CSS ao iframe?

1017

Eu tenho uma página simples que possui algumas seções de iframe (para exibir os links RSS). Como posso aplicar o mesmo formato CSS da página principal à página exibida no iframe?

Akshay Mulgavkar
fonte
66
É possível, mas apenas se o domínio do iframe for o mesmo que o pai
gawpertron 30/06/10
13
gawpertron, só para esclarecer, você está dizendo que se eu usar o conteúdo do iFrame de outro domínio que não controle, não há como controlar o CSS desse conteúdo?
Ville M
Você pode listar um link para a página para que possamos apenas visualizar nossas alterações.
5
O domínio, porta e protocolo devem ser os mesmos, também não funcionam com subdomínios.
Lee penkman 11/11/19

Respostas:

434

Editar: isso não funciona entre domínios, a menos que o cabeçalho CORS apropriado esteja definido.

Há duas coisas diferentes aqui: o estilo do bloco iframe e o estilo da página incorporada no iframe. Você pode definir o estilo do bloco iframe da maneira usual:

<iframe name="iframe1" id="iframe1" src="empty.htm" 
        frameborder="0" border="0" cellspacing="0"
        style="border-style: none;width: 100%; height: 120px;"></iframe>

O estilo da página incorporada no iframe deve ser definido incluindo-o na página filha:

<link type="text/css" rel="Stylesheet" href="Style/simple.css" />

Ou pode ser carregado na página principal com Javascript:

var cssLink = document.createElement("link");
cssLink.href = "style.css"; 
cssLink.rel = "stylesheet"; 
cssLink.type = "text/css"; 
frames['iframe1'].document.head.appendChild(cssLink);
Tamas Czinege
fonte
30
Observe que parece que alguns dos exemplos publicados anteriormente agora são inválidos para html5. Você pode acessar o conteúdo do quadro da seguinte forma: document.getElementById("myframe").contentDocument. Incorporar o CSS ainda não parece funcionar para mim.
Rehno Lindeque 2/02
35
link pode aparecer apenas no HEAD
Knu
18
Só funcionou para mim quando o fiz ...document.head.appendChild(cssLink)- Firefox e Safari.
Mojuba 26/09
24
Isso realmente funciona entre domínios? Eu acho que não.
Simon Médio
89
Só assim ninguém mais precisa testá-lo para descobrir: correto, ele não funciona em vários domínios. Imediatamente após a criação dos quadros ['name'], você obtém "Tentativa de JavaScript inseguro para acessar o quadro com URL blá de quadro com URL blá. Domínios, protocolos e portas devem corresponder."
27411 Kevin
205

Eu conheci esse problema com o Google Agenda . Eu queria estilizá-lo em um fundo mais escuro e mudar a fonte.

Felizmente, a URL do código de incorporação não tinha restrições de acesso direto, portanto, usando a função PHP file_get_contents, é possível obter todo o conteúdo da página. Em vez de chamar o URL do Google, é possível chamar um arquivo php localizado no seu servidor, por exemplo, google.php, que conterá o conteúdo original com modificações:

$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');

Adicionando o caminho à sua folha de estilo:

$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);

Isso colocará sua folha de estilo por último antes da headtag final.

Especifique o URL base do URL original, caso css e js sejam chamados relativamente:

$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);

O google.phparquivo final deve ficar assim:

<?php
$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');
$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);
$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);
echo $content;

Então você altera o iframecódigo de incorporação para:

<iframe src="http://www.yourwebsiteurl.com/google.php" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>

Boa sorte!

SequenceDigitale.com
fonte
71
Você pode chamar isso de hacking por definição, se quiser. Mas você não ofereceu nenhuma solução melhor ... Essa solução não é uma maneira de prejudicar o serviço do Google ou enganar as pessoas de maneira a explorar suas fraquezas.
SequenceDigitale.com
5
Eu mataria por uma maneira de fazer essa solução funcionar com o Google Docs. Está lançando todos os tipos de erros de javascript. "TypeError não detectado: não é possível ler a propriedade 'a' de indefinida"
deweydb 19/08/2014
1
Não importa, eu percebi isso, postou a solução aqui: stackoverflow.com/questions/25395279/...
deweydb
9
@ChrisHoughton FYI, basicamente não é. No entanto, isso pode tornar inútil o iframe inteiro (uma razão para o uso de iframes, por exemplo, é para fins de segurança, por exemplo, com pagamentos com cartão, e se você fizer o que é sugerido aqui, provavelmente causará problemas a si mesmo).
Alastair
10
Ao fazer isso, você sempre obtém o calendário como um usuário não conectado. Com o iframe html normal, o usuário veria seu próprio calendário pessoal se estivesse conectado ao google, mas como o código PHP não pode conhecer o ID da sessão do usuário do Google, ele não pode buscar seu calendário pessoal.
precisa saber é
72

Se o conteúdo do iframe não estiver completamente sob seu controle ou você quiser acessar o conteúdo de páginas diferentes com estilos diferentes, tente manipulá-lo usando JavaScript.

var frm = frames['frame'].document;
var otherhead = frm.getElementsByTagName("head")[0];
var link = frm.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "style.css");
otherhead.appendChild(link);

Observe que, dependendo do navegador usado, isso pode funcionar apenas em páginas veiculadas no mesmo domínio.

Horst Gutmann
fonte
82
Vale a pena notar que a mesma política de origem interromperá o funcionamento se a página estiver em um domínio diferente.
ConroyP
2
Na mesma linha de pensamento, mas mais sucinta: <iframe onload="this.contentDocument.body.style.overflow='hidden';" />
Protector one
Até o Firefox se tornou CORS
59
var $head = $("#eFormIFrame").contents().find("head");

$head.append($("<link/>", {
    rel: "stylesheet",
    href: url,
    type: "text/css"
}));
Rami Sarieddine
fonte
@deweydb usei-o com um iframe entre domínios especificamente. mas só posso pedir seu perdão!
Rami Sarieddine
@ramie e você testou isso em vários navegadores? a maioria dos navegadores está apresentando um erro de segurança.
deweydb
Eu vi essa idéia antes, mas adicione um link para o arquivo ser realmente ótimo e profissional ... +
J.Tural
29

Um iframe é tratado universalmente como uma página HTML diferente pela maioria dos navegadores. Se você deseja aplicar a mesma folha de estilo ao conteúdo do iframe, basta referenciá-la nas páginas usadas.

enforcado
fonte
22
@hangry mas ... como?
Uma Criança de Deus
29

Aqui está como aplicar o código CSS diretamente sem usar <link>para carregar uma folha de estilo extra.

var head = jQuery("#iframe").contents().find("head");
var css = '<style type="text/css">' +
          '#banner{display:none}; ' +
          '</style>';
jQuery(head).append(css);

Isso oculta o banner na página iframe. Obrigado por suas sugestões!

domih
fonte
1
Isso precisa de um iframe com o ID de iframe?
Jeremy
1
@jmalais Basta substituir #iframecom #<id>ou mesmo iframepara selecionar todos os iframes
Zeb McCorkle
3
Isso não parece estar funcionando para mim. O iframe que estou tentando editar também não tem cabeça diretamente abaixo dele no dom. Então, isso significa que eu preciso acessar a cabeça dentro do documento html ou é algo que a função jquery find deve poder fazer sozinha?
David A. French
1
Verificou o console e parece que foi impedido de acessar o conteúdo do iframe devido a uma incompatibilidade de domínio. Atualmente, estou usando o chrome e hospedando meu ambiente de desenvolvimento localmente.
David A. French
DOMException Uncaught: Bloqueado um quadro com origem dá-me este erro
priyanka patel
26

Se você controla a página no iframe, como disse hangy, a abordagem mais fácil é criar um arquivo CSS compartilhado com estilos comuns, basta vinculá-lo a partir de suas páginas html.

Caso contrário, é improvável que você consiga alterar dinamicamente o estilo de uma página a partir de uma página externa no seu iframe. Isso ocorre porque os navegadores aumentaram a segurança dos scripts de dominação cruzada de quadros, devido ao possível uso indevido de falsificações e outros hacks.

Este tutorial pode fornecer mais informações sobre iframes de script em geral. Sobre scripts entre quadros explica as restrições de segurança da perspectiva do IE.

Cinza
fonte
19

O acima com uma pequena mudança funciona:

var cssLink = document.createElement("link") 
cssLink.href = "pFstylesEditor.css"; 
cssLink.rel = "stylesheet"; 
cssLink.type = "text/css"; 

//Instead of this
//frames['frame1'].document.body.appendChild(cssLink);
//Do this

var doc=document.getElementById("edit").contentWindow.document;

//If you are doing any dynamic writing do that first
doc.open();
doc.write(myData);
doc.close();

//Then append child
doc.body.appendChild(cssLink);

Funciona bem com ff3 e ie8 pelo menos

Eric
fonte
7
O que é myData e onde ela vem
Tigran
1
@Tigran is for fordynamic data
Akash
13

Se você deseja reutilizar CSS e JavaScript a partir da página principal, considere substituir <IFRAME> por um conteúdo carregado pelo Ajax. Isso é mais amigável ao SEO agora, quando os robôs de pesquisa são capazes de executar JavaScript.

Este é um exemplo de jQuery que inclui outra página html no seu documento. Isso é muito mais amigável para SEO do que iframe. Para ter certeza de que os bots não estão indexando a página incluída, adicione-a para não permitirrobots.txt

<html>
  <header>
    <script src="/js/jquery.js" type="text/javascript"></script>
  </header>
  <body>
    <div id='include-from-outside'></div>
    <script type='text/javascript'>
      $('#include-from-outside').load('http://example.com/included.html');
    </script> 
  </body>
</html>

Você também pode incluir o jQuery diretamente do Google: http://code.google.com/apis/ajaxlibs/documentation/ - isso significa inclusão automática opcional de versões mais recentes e aumento significativo da velocidade. Além disso, significa que você precisa confiar neles para fornecer apenas o jQuery;)

sorin
fonte
1
Deve-se observar que esta solução não funciona se o conteúdo da página for dinâmico de alguma forma.
nickdnk
12

O seguinte funcionou para mim.

var iframe = top.frames[name].document;
var css = '' +
          '<style type="text/css">' +
          'body{margin:0;padding:0;background:transparent}' +
          '</style>';
iframe.open();
iframe.write(css);
iframe.close();
Pedro
fonte
1
Erro:Uncaught TypeError: Cannot read property 'open' of undefined
KingRider 19/09/16
10

Expandir a solução jQuery acima para lidar com qualquer atraso no carregamento do conteúdo do quadro.

$('iframe').each(function(){
    function injectCSS(){
        $iframe.contents().find('head').append(
            $('<link/>', { rel: 'stylesheet', href: 'iframe.css', type: 'text/css' })
        );
    }

    var $iframe = $(this);
    $iframe.on('load', injectCSS);
    injectCSS();
});
David Bradshaw
fonte
1
O '$ this' precisa ser um '$ (this)' para que ele funcione. Bom quando ele faz :)
h.coates
9

Minha versão compacta :

<script type="text/javascript">
$(window).load(function () {
    var frame = $('iframe').get(0);
    if (frame != null) {
        var frmHead = $(frame).contents().find('head');
        if (frmHead != null) {
            frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
            //frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
        }
    }   
});
</script>

No entanto, às vezes o iframenão está pronto na janela carregada, portanto, é necessário usar um timer .

Código pronto para uso (com timer):

<script type="text/javascript">
var frameListener;
$(window).load(function () {
    frameListener = setInterval("frameLoaded()", 50);
});
function frameLoaded() {
    var frame = $('iframe').get(0);
    if (frame != null) {
        var frmHead = $(frame).contents().find('head');
        if (frmHead != null) {
            clearInterval(frameListener); // stop the listener
            frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
            //frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
        }
    }
}
</script>

... e link do jQuery:

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>
Zbigniew Wiadro
fonte
8

Outras respostas aqui parecem usar links jQuery e CSS.

Este código usa JavaScript vanilla. Cria um novo <style>elemento. Ele define o conteúdo de texto desse elemento como uma sequência que contém o novo CSS. E anexa esse elemento diretamente ao cabeçalho do documento iframe.

var iframe = document.getElementById('the-iframe');
var style = document.createElement('style');
style.textContent =
  '.some-class-name {' +
  '  some-style-name: some-value;' +
  '}' 
;
iframe.contentDocument.head.appendChild(style);
2540625
fonte
7

Quando você diz "doc.open ()", significa que você pode escrever qualquer tag HTML dentro do iframe; portanto, você deve escrever todas as tags básicas para a página HTML e se quiser ter um link CSS na cabeça do iframe, basta escrever um iframe com o link CSS nele. Eu dou um exemplo:

doc.open();

doc.write('<!DOCTYPE html><html><head><meta charset="utf-8"/><meta http-quiv="Content-Type" content="text/html; charset=utf-8"/><title>Print Frame</title><link rel="stylesheet" type="text/css" href="https://stackoverflow.com/css/print.css"/></head><body><table id="' + gridId + 'Printable' + '" class="print" >' + out + '</table></body></html>');

doc.close();
Parham Fazel
fonte
7

use pode tentar o seguinte:

$('iframe').load( function() {
     $('iframe').contents().find("head")
     .append($("<style type='text/css'>  .my-class{display:none;}  </style>"));
  });
Ajay Malhotra
fonte
3
Se o seu iframe for de origem diferente, o mecanismo CORS não permitirá essa solução alternativa.
Mr. Anderson
E se o iframe-url estiver habilitado com CORS para todos os locais?
Adrhc 25/10/19
6

Você não poderá estilizar o conteúdo do iframe dessa maneira. Minha sugestão seria usar scripts no servidor (PHP, ASP ou um script Perl) ou encontrar um serviço online que converterá um feed em código JavaScript. A única outra maneira de fazer isso seria se você pudesse incluir um servidor.

Peter Mortensen
fonte
29
Cuidado quando você diz que algo não pode ser feito, quando, na realidade, é apenas difícil
Lathan
4

Caso você tenha acesso à página iframe e queira que um CSS diferente seja aplicado somente quando você o carrega via iframe na sua página, aqui encontrei uma solução para esse tipo de coisa

isso funciona mesmo se o iframe estiver carregando um domínio diferente

verifique sobre postMessage()

O plano é enviar o css para o iframe como uma mensagem como

iframenode.postMessage('h2{color:red;}','*');

* é enviar esta mensagem independentemente do domínio em iframe

e receba a mensagem em iframe e adicione a mensagem recebida (CSS) a esse cabeçalho do documento.

código para adicionar na página iframe

window.addEventListener('message',function(e){

    if(e.data == 'send_user_details')
    document.head.appendChild('<style>'+e.data+'</style>');

});
CodeRows
fonte
4

Como muitas respostas são escritas para os mesmos domínios, escreverei como fazer isso em domínios cruzados.

Primeiro, você precisa conhecer a API Post Message . Precisamos de um mensageiro para se comunicar entre duas janelas.

Aqui está um mensageiro que eu criei.

/**
 * Creates a messenger between two windows
 *  which have two different domains
 */
class CrossMessenger {

    /**
     * 
     * @param {object} otherWindow - window object of the other
     * @param {string} targetDomain - domain of the other window
     * @param {object} eventHandlers - all the event names and handlers
     */
    constructor(otherWindow, targetDomain, eventHandlers = {}) {
        this.otherWindow = otherWindow;
        this.targetDomain = targetDomain;
        this.eventHandlers = eventHandlers;

        window.addEventListener("message", (e) => this.receive.call(this, e));
    }

    post(event, data) {

        try {
            // data obj should have event name
            var json = JSON.stringify({
                event,
                data
            });
            this.otherWindow.postMessage(json, this.targetDomain);

        } catch (e) {}
    }

    receive(e) {
        var json;
        try {
            json = JSON.parse(e.data ? e.data : "{}");
        } catch (e) {
            return;
        }
        var eventName = json.event,
            data = json.data;

        if (e.origin !== this.targetDomain)
            return;

        if (typeof this.eventHandlers[eventName] === "function") 
            this.eventHandlers[eventName](data);
    }

}

Usar isso em duas janelas para se comunicar pode resolver seu problema.

Nas janelas principais,

var msger = new CrossMessenger(iframe.contentWindow, "https://iframe.s.domain");

var cssContent = Array.prototype.map.call(yourCSSElement.sheet.cssRules, css_text).join('\n');
msger.post("cssContent", {
   css: cssContent
})

Em seguida, receba o evento do Iframe.

No Iframe:

var msger = new CrossMessenger(window.parent, "https://parent.window.domain", {
    cssContent: (data) => {
        var cssElem = document.createElement("style");
        cssElem.innerHTML = data.css;
        document.head.appendChild(cssElem);
    }
})

Consulte o tutorial Completo sobre Javascript e Iframes para obter mais detalhes.

Supun Kavinda
fonte
3

Encontrei outra solução para colocar o estilo no html principal assim

<style id="iframestyle">
    html {
        color: white;
        background: black;
    }
</style>
<style>
    html {
        color: initial;
        background: initial;
    }
    iframe {
        border: none;
    }
</style>

e, em seguida, no iframe, faça isso (consulte o js onload)

<iframe  onload="iframe.document.head.appendChild(ifstyle)" name="log" src="/upgrading.log"></iframe>

e em js

<script>
    ifstyle = document.getElementById('iframestyle')
    iframe = top.frames["log"];
</script>

Pode não ser a melhor solução, e certamente pode ser aprimorada, mas é outra opção se você deseja manter uma tag "style" na janela pai

jperelli
fonte
3

Aqui, existem duas coisas dentro do domínio

  1. Seção iFrame
  2. Página carregada dentro do iFrame

Então, você deseja estilizar essas duas seções da seguinte maneira:

1. Estilo para a seção iFrame

Pode estilizar usando CSS com esse nome idou classnome respeitado . Você também pode estilizá-lo nas folhas de estilo principais.

<style>
#my_iFrame{
height: 300px;
width: 100%;
position:absolute;
top:0;
left:0;
border: 1px black solid;
}
</style>

<iframe name='iframe1' id="my_iFrame" src="#" cellspacing="0"></iframe>

2. Estilize a página carregada dentro do iFrame

Este Styles pode ser carregado na página principal com a ajuda de Javascript

var cssFile  = document.createElement("link") 
cssFile.rel  = "stylesheet"; 
cssFile.type = "text/css"; 
cssFile.href = "iFramePage.css"; 

defina esse arquivo CSS para a seção respeitada do iFrame

//to Load in the Body Part
frames['my_iFrame'].document.body.appendChild(cssFile); 
//to Load in the Head Part
frames['my_iFrame'].document.head.appendChild(cssFile);

Aqui, você pode editar a parte principal da página dentro do iFrame usando desta maneira também

var $iFrameHead = $("#my_iFrame").contents().find("head");
$iFrameHead.append(
   $("<link/>",{ 
      rel: "stylesheet", 
      href: urlPath, 
      type: "text/css" }
     ));
K.Suthagar
fonte
2

Podemos inserir uma tag de estilo no iframe. Postado também aqui ...

<style type="text/css" id="cssID">
.className
{
    background-color: red;
}
</style>

<iframe id="iFrameID"></iframe>

<script type="text/javascript">
    $(function () {
        $("#iFrameID").contents().find("head")[0].appendChild(cssID);
        //Or $("#iFrameID").contents().find("head")[0].appendChild($('#cssID')[0]);
    });
</script>
Palanikumar
fonte
1
Isso não funciona. Parece inserir a tag de estilo corretamente, mas não há conteúdo e nem ID.
darylknight
2

var link1 = document.createElement('link');
    link1.type = 'text/css';
    link1.rel = 'stylesheet';
    link1.href = "../../assets/css/normalize.css";
window.frames['richTextField'].document.body.appendChild(link1);

Jeeva
fonte
1
Eu verifiquei esta resposta muitas vezes o que está richTextFieldaqui?
Kirankumar Dafda
1
é o nome do iframe
Jeeva
Eu não tentei, mas eu acho que não vai porque a sua contra o sandbox
Jeeva
1

Eu acho que a maneira mais fácil é adicionar outra div, no mesmo lugar que o iframe, então

faça com z-indexque seja maior que o contêiner iframe, para que você possa facilmente estilizar sua própria div. Se você precisar clicar nele, basta usar pointer-events:nonesua própria div, para que o iframe funcione caso você precise clicar nele;)

Espero que ajude alguém;)

Mateusz Winnicki
fonte
1

Há um script maravilhoso que substitui um nó por uma versão em iframe. CodePen Demo

insira a descrição da imagem aqui

Exemplos de uso:

// Single node
var component = document.querySelector('.component');
var iframe = iframify(component);

// Collection of nodes
var components = document.querySelectorAll('.component');
var iframes = Array.prototype.map.call(components, function (component) {
  return iframify(component, {});
});

// With options
var component = document.querySelector('.component');
var iframe = iframify(component, {
  headExtra: '<style>.component { color: red; }</style>',
  metaViewport: '<meta name="viewport" content="width=device-width">'
});
karlisup
fonte
1
Por que você gostaria de fazer isso?!
Dylan Watson
1

Como alternativa, você pode usar a tecnologia CSS-in-JS, como abaixo da lib:

https://github.com/cssobj/cssobj

Ele pode injetar o objeto JS como CSS no iframe, dinamicamente

James Yang
fonte
0

Este é apenas um conceito, mas não o implemente sem verificações e filtros de segurança! Caso contrário, o script pode invadir o seu site!

Resposta: se você controlar o site de destino, poderá configurar o script do receptor como:

1) defina o link iframe com o styleparâmetro, como:

http://your_site.com/target.php?color=red

(a última frase é a{color:red} codificada por urlencodefunção.

2) defina a página do receptor target.phpassim:

<head>
..........
$col = FILTER_VAR(SANITIZE_STRING, $_GET['color']);
<style>.xyz{color: <?php echo (in_array( $col, ['red','yellow','green'])?  $col : "black") ;?> } </style>
..........
T.Todua
fonte
3
Aviso: esta é a melhor injeção.
Kano
1
yap, não faça isso, a não ser que você quer uma carga de bots pen-teste e script kiddies em seu servidor =) ...
exside
1
Eu atualizei resposta agora, com aviso de segurança adicional
T.Todua
-18

Bem, eu segui estes passos:

  1. Div com uma classe para realizar iframe
  2. Adicione iframeao div.
  3. No arquivo CSS,
divClass { width: 500px; height: 500px; }
divClass iframe { width: 100%; height: 100%; }

Isso funciona no IE 6. Deve funcionar em outros navegadores, verifique!

JannuD
fonte
9
precisa controlar div dentro do iframe, isso não acontece #
MSD