Comment appliquer CSS à iframe?


1017

J'ai une page simple qui contient des sections iframe (pour afficher les liens RSS). Comment puis-je appliquer le même format CSS de la page principale à la page affichée dans l'iframe?


66
C'est possible mais seulement si le domaine de l'iframe est le même que le parent
gawpertron

13
gawpertron, juste pour clarifier, dites-vous que si j'utilise du contenu iFrame d'un autre domaine que je ne contrôle pas, il n'y a aucun moyen pour moi de contrôler le CSS pour ce contenu?
Ville M

Pouvez-vous répertorier un lien vers la page afin que nous puissions simplement voir nos modifications.

5
Le domaine, le port et le protocole doivent être identiques, ne fonctionne pas non plus avec les sous-domaines.
Lee Penkman

Réponses:


434

Modifier: cela ne fonctionne pas entre domaines sauf si l'en- tête CORS approprié est défini.

Il y a deux choses différentes ici: le style du bloc iframe et le style de la page incorporée dans l'iframe. Vous pouvez définir le style du bloc iframe de la manière habituelle:

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

Le style de la page incorporée dans l'iframe doit être défini en l'incluant dans la page enfant:

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

Ou il peut être chargé à partir de la page parent avec Javascript:

var cssLink = document.createElement("link");
cssLink.href = "style.css"; 
cssLink.rel = "stylesheet"; 
cssLink.type = "text/css"; 
frames['iframe1'].document.head.appendChild(cssLink);

30
Veuillez noter qu'il me semble que certains des exemples publiés auparavant ne sont plus valides pour html5. Vous pouvez accéder au contenu du cadre comme suit:document.getElementById("myframe").contentDocument . Cependant, l'intégration du CSS ne semble pas fonctionner pour moi.
Rehno Lindeque

35
le lien ne peut apparaître que dans la TETE
Knu

18
A travaillé pour moi seulement quand je l'ai fait ...document.head.appendChild(cssLink) - Firefox et Safari.
mojuba

24
Cela fonctionne-t-il réellement entre domaines? Je ne pense pas que ce serait le cas.
Simon East

89
Juste pour que personne d'autre ne le teste pour le savoir: correct, cela ne fonctionne pas entre les domaines. Immédiatement après avoir créé les cadres ['nom'], vous obtenez "Tentative JavaScript non sécurisée d'accéder au cadre avec URL blah à partir du cadre avec URL blah. Les domaines, protocoles et ports doivent correspondre."
Kevin

205

J'ai rencontré ce problème avec Google Agenda . Je voulais le styliser sur un fond plus sombre et changer de police.

Heureusement, l'URL du code intégré n'avait aucune restriction sur l'accès direct, donc en utilisant la fonction PHP, file_get_contentsil est possible d'obtenir tout le contenu de la page. Au lieu d'appeler l'URL de Google, il est possible d'appeler un fichier php situé sur votre serveur, ex. google.php, qui contiendra le contenu original avec des modifications:

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

Ajout du chemin à votre feuille de style:

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

(Cela placera votre feuille de style en dernier juste avant le head balise de fin.)

Spécifiez l'URL de base de l'URL d'origine au cas où css et js sont appelés relativement:

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

Le google.phpfichier final devrait ressembler à ceci:

<?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;

Ensuite, vous changez le iframe code d'intégration en:

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

Bonne chance!


71
Vous pouvez appeler ce piratage par définition si vous le souhaitez. Mais vous n'avez pas proposé de meilleure solution ... Cette solution n'est pas un moyen d'endommager le service Google ou de tromper les gens de manière à exploiter leur faiblesse.
SequenceDigitale.com

5
Je tuerais pour un moyen de faire fonctionner cette solution avec google docs. Son jet toutes sortes d'erreurs javascript. "TypeError non capturé: Impossible de lire la propriété 'a' de non défini"
deweydb


9
@ChrisHoughton FYI, ce n'est pas le cas. Cependant, cela pourrait rendre l'iframe entier inutile (une raison pour utiliser des iframes, par exemple, est à des fins de sécurité, par exemple avec les paiements par carte, et si vous faites ce qui est suggéré ici, vous vous causerez probablement des problèmes).
alastair

10
En faisant cela, vous obtenez toujours le calendrier en tant qu'utilisateur non connecté. Avec l'iframe html normal, l'utilisateur verrait son propre calendrier personnel s'il était connecté à Google, mais comme votre code PHP ne peut pas connaître l'ID de session Google de l'utilisateur, il ne peut pas récupérer son calendrier personnel.
bdsl

72

Si le contenu de l'iframe n'est pas complètement sous votre contrôle ou si vous souhaitez accéder au contenu de différentes pages avec des styles différents, vous pouvez essayer de le manipuler à l'aide de 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);

Notez que selon le navigateur que vous utilisez, cela peut ne fonctionner que sur les pages diffusées depuis le même domaine.


82
Il peut être intéressant de noter que la même politique d'origine arrêtera ce fonctionnement si la page se trouve sur un domaine différent.
ConroyP

2
Dans le même esprit mais plus succinct: <iframe onload="this.contentDocument.body.style.overflow='hidden';" />
Protector one

Même Firefox est devenu

59
var $head = $("#eFormIFrame").contents().find("head");

$head.append($("<link/>", {
    rel: "stylesheet",
    href: url,
    type: "text/css"
}));

@deweydb je l'ai utilisé spécifiquement avec un iframe interdomaine. mais je ne peux que vous demander pardon!
Rami Sarieddine du

@ramie et vous l'avez testé dans plusieurs navigateurs? la plupart des navigateurs génèrent une erreur de sécurité.
deweydb

J'ai déjà vu cette idée mais j'ai ajouté un lien vers un fichier vraiment génial et professionnel ... + up
J.Tural

29

Un iframe est universellement géré comme une page HTML différente par la plupart des navigateurs. Si vous souhaitez appliquer la même feuille de style au contenu de l'iframe, faites-la simplement référence à partir des pages utilisées.


22
@hangry mais ... comment?
Un enfant de Dieu

29

Voici comment appliquer le code CSS directement sans utiliser <link>pour charger une feuille de style supplémentaire.

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

Cela masque la bannière dans la page iframe. Merci pour vos suggestions!


1
Cela nécessite-t-il un iframe avec l'id de iframe?
Jeremy

1
@jmalais Il suffit de remplacer #iframepar #<id>ou même iframede sélectionner tous les iframes
Zeb McCorkle

3
Cela ne semble pas fonctionner pour moi. L'iframe que j'essaie de modifier n'a pas non plus de tête directement en dessous dans le dom. Est-ce que cela signifie que je dois accéder à la tête à l'intérieur du document html ou est-ce quelque chose que la fonction de recherche jquery devrait être capable de faire par elle-même?
David A. French

1
Vérifié la console et il semble que l'accès au contenu iframe ait été bloqué en raison d'une incompatibilité de domaine. J'utilise Chrome et héberge mon environnement de développement localement actuellement.
David A. French

DOMException Uncaught: Blocage d'un cadre avec l'origine, cela me donne cette erreur
priyanka patel

26

Si vous contrôlez la page dans l'iframe, comme l'a dit hangy, l'approche la plus simple est de créer un fichier CSS partagé avec des styles communs, puis de le lier à partir de vos pages html.

Sinon, il est peu probable que vous puissiez modifier dynamiquement le style d'une page à partir d'une page externe dans votre iframe. Cela est dû au fait que les navigateurs ont renforcé la sécurité sur les scripts dom cross frame en raison d'une mauvaise utilisation possible pour l'usurpation d'identité et d'autres hacks.

Ce didacticiel peut vous fournir plus d'informations sur les scripts iframes en général. À propos des scripts inter-images explique les restrictions de sécurité du point de vue IE.


19

Ce qui précède avec un peu de changement fonctionne:

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);

Fonctionne très bien avec ff3 et ie8 au moins


7
Qu'est-ce que myData et d'où vient-il
Tigran

1
@Tigran c'est pourdynamic data
Akash

13

Si vous souhaitez réutiliser CSS et JavaScript à partir de la page principale, vous devriez peut-être envisager de remplacer <IFRAME> par un contenu chargé Ajax. C'est désormais plus convivial pour le référencement lorsque les robots de recherche sont capables d'exécuter JavaScript.

Il s'agit d'un exemple jQuery qui inclut une autre page html dans votre document. C'est beaucoup plus convivial que pour le référencement iframe. Afin d'être sûr que les bots n'indexent pas la page incluse, il suffit de l'ajouter pour interdirerobots.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>

Vous pouvez également inclure jQuery directement à partir de Google: http://code.google.com/apis/ajaxlibs/documentation/ - cela signifie une inclusion automatique facultative des versions plus récentes et une augmentation significative de la vitesse. Cela signifie également que vous devez leur faire confiance pour ne vous fournir que le jQuery;)


1
Il convient de noter que cette solution ne fonctionne pas si le contenu de la page est dynamique de quelque manière que ce soit.
nickdnk

12

Ce qui suit a fonctionné pour moi.

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();

1
Erreur:Uncaught TypeError: Cannot read property 'open' of undefined
KingRider

10

Extension de la solution jQuery ci-dessus pour faire face à tout retard dans le chargement du contenu du cadre.

$('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();
});

1
Le «$ this» doit être un «$ (this)» pour que cela fonctionne. Sympa quand c'est le cas :)
h.coates

9

Ma version compacte :

<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>

Cependant, parfois le iframen'est pas prêt sur une fenêtre chargée, il est donc nécessaire d'utiliser un minuteur .

Code prêt à l'emploi (avec minuterie):

<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>

... et lien jQuery:

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

8

D'autres réponses semblent utiliser des liens jQuery et CSS.

Ce code utilise du JavaScript vanille. Il crée un nouvel <style>élément. Il définit le contenu textuel de cet élément comme une chaîne contenant le nouveau CSS. Et il ajoute cet élément directement à la tête du document 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);

7

Lorsque vous dites "doc.open ()" cela signifie que vous pouvez écrire n'importe quelle balise HTML à l'intérieur de l'iframe, vous devez donc écrire toutes les balises de base pour la page HTML et si vous voulez avoir un lien CSS dans votre tête iframe, écrivez simplement un iframe avec un lien CSS dedans. Je vous donne un exemple:

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();

7

l'utilisation peut essayer ceci:

$('iframe').load( function() {
     $('iframe').contents().find("head")
     .append($("<style type='text/css'>  .my-class{display:none;}  </style>"));
  });

3
Si votre iframe provient d'une origine différente, le mécanisme CORS ne permettra pas cette solution de contournement.
M. Anderson

Que faire si l'iframe-url est compatible CORS pour tous les emplacements?
adrhc

6

Vous ne pourrez pas styliser le contenu de l'iframe de cette façon. Ma suggestion serait d'utiliser des scripts côté serveur (PHP, ASP ou un script Perl) ou de trouver un service en ligne qui convertira un flux en code JavaScript. La seule autre façon de le faire serait de faire une inclusion côté serveur.


29
Attention quand vous dites que quelque chose ne peut pas être fait, alors qu'en réalité c'est juste difficile
Lathan

4

Dans le cas où vous avez accès à la page iframe et que vous souhaitez appliquer un CSS différent uniquement lorsque vous le chargez via iframe sur votre page, j'ai trouvé ici une solution pour ce genre de choses

cela fonctionne même si iframe charge un autre domaine

vérifier postMessage()

plan est, envoyez le css à iframe comme un message comme

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

* est d'envoyer ce message quel que soit le domaine dans lequel se trouve iframe

et recevez le message dans iframe et ajoutez le message reçu (CSS) à cette tête de document.

code à ajouter dans la page iframe

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

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

});

4

Comme de nombreuses réponses sont écrites pour les mêmes domaines, j'écrirai comment procéder dans des domaines croisés.

Tout d'abord, vous devez connaître l' API Post Message . Nous avons besoin d'un messager pour communiquer entre deux fenêtres.

Voici un messager que j'ai créé.

/**
 * 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);
    }

}

L'utiliser dans deux fenêtres pour communiquer peut résoudre votre problème.

Dans les fenêtres principales,

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
})

Ensuite, recevez l'événement de l'Iframe.

Dans l'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);
    }
})

Voir le tutoriel complet Javascript et Iframes pour plus de détails.


3

J'ai trouvé une autre solution pour mettre le style dans le html principal comme celui-ci

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

puis dans iframe faire ceci (voir la js onload)

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

et en js

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

Ce n'est peut-être pas la meilleure solution, et elle peut certainement être améliorée, mais c'est une autre option si vous souhaitez conserver une balise "style" dans la fenêtre parente


3

Ici, il y a deux choses à l'intérieur du domaine

  1. Section iFrame
  2. Page chargée à l'intérieur de l'iFrame

Vous voulez donc styliser ces deux sections comme suit,

1. Style pour la section iFrame

Il peut de style en utilisant CSS avec qui respecte idou classnom. Vous pouvez également le styliser dans vos feuilles de style parent.

<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. Style de la page chargée à l'intérieur de l'iFrame

Ces styles peuvent être chargés à partir de la page parent à l'aide de Javascript

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

puis définissez ce fichier CSS dans la section iFrame respectée

//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);

Ici, vous pouvez modifier la partie tête de la page à l'intérieur de l'iFrame en utilisant également cette méthode

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

2

Nous pouvons insérer une balise de style dans iframe. Publié aussi ici ...

<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>

1
Ça ne marche pas. Semble insérer correctement la balise de style, mais il n'y a aucun contenu à l'intérieur et aucun 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);


1
J'ai vérifié cette réponse plusieurs fois ce qui est richTextFieldici?
Kirankumar Dafda

1
c'est le nom de l'iframe
Jeeva

Je n'ai pas essayé, mais je suppose que ce ne sera pas le cas car c'est contre le bac à sable
Jeeva

1

Je pense que la façon la plus simple est d'ajouter un autre div, au même endroit que l'iframe, puis

faire son z-indexplus grand que le conteneur iframe, de sorte que vous pouvez facilement simplement styler votre propre div. Si vous devez cliquer dessus, utilisez-le pointer-events:nonesur votre propre div, pour que l'iframe fonctionne au cas où vous auriez besoin de cliquer dessus;)

J'espère que ça va aider quelqu'un;)


1

Il existe un merveilleux script qui remplace un nœud par une version iframe de lui-même. Démo CodePen

entrez la description de l'image ici

Exemples d'utilisation:

// 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">'
});

1
Pourquoi voudriez-vous faire ça?!
Dylan Watson


0

Ce n'est qu'un concept, mais ne l'implémentez pas sans contrôles de sécurité et filtrage! Sinon, le script pourrait pirater votre site!

Réponse: si vous contrôlez le site cible, vous pouvez configurer le script récepteur comme:

1) définissez le lien iframe avec un styleparamètre, comme:

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

(la dernière phrase est a{color:red} codée par urlencodefonction.

2) définissez la page du récepteur target.phpcomme ceci:

<head>
..........
$col = FILTER_VAR(SANITIZE_STRING, $_GET['color']);
<style>.xyz{color: <?php echo (in_array( $col, ['red','yellow','green'])?  $col : "black") ;?> } </style>
..........

3
Attention: c'est l'injection à son meilleur.
kano

1
yap, ne faites pas cela, sauf que vous voulez une charge de bots de test de stylo et de script kiddies sur votre serveur =) ...
extérieur du

1
J'ai mis à jour la réponse maintenant, avec un avertissement de sécurité supplémentaire
T.Todua

-18

Eh bien, j'ai suivi ces étapes:

  1. Div avec une classe à tenir iframe
  2. Ajoutez iframeau div.
  3. Dans le fichier CSS,
divClass { width: 500px; height: 500px; }
divClass iframe { width: 100%; height: 100%; }

Cela fonctionne dans IE 6. Devrait fonctionner dans d'autres navigateurs, vérifiez!


9
besoin de contrôler les div à l'intérieur de l'iframe, cela ne fonctionne pas
MSD
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.