184

How can I control the background image and colour of a body element within an iframe? Note, the embedded body element has a class, and the iframe is of a page that is part of my site.

The reason I need this is that my site has a black background assigned to the body, and then a white background assigned to divs that contain text. A WYSIWYG editor uses an iframe to embed content when editing, but it doesn't include the div, so the text is very hard to read.

The body of the iframe when in the editor has a class that isn't used anywhere else, so I'm assuming this was put there so problems like this could be solved. However, when I apply styles to class.body they don't override the styles applied to body. The weird thing is that the styles do appear in Firebug, so I've no idea what's going on!

Thanks

UPDATE - I've tried @mikeq's solution of adding a style to the class that is the body's class. This doesn't work when added to the main page's stylesheet, but it does work when added with Firebug. I'm assuming this is because Firebug is applied to all elements on the page whereas the CSS is not applied within iframes. Does this mean that adding the css after window load with JavaScript would work?

wazz
  • 4,057
  • 5
  • 18
  • 32
jd6699
  • 1,877
  • 2
  • 12
  • 6
  • 1
    Possible duplicate of [How to apply CSS to iframe?](http://stackoverflow.com/questions/217776/how-to-apply-css-to-iframe) – 2540625 Jul 07 '16 at 00:52
  • While it's not possible to touch anything in an iframe, loading that URL per Ajax into a `
    ` can at times be a workaround (if given CORS-Header are allowing for that)... (and „sanitizing“ the loaded data by regexp on the way. Yes, all hacky...)
    – Frank Nocke Apr 05 '17 at 13:31
  • You can use javascript if the page domains match, but why not just put a style block in your inner page's HTML to override the colors you want changed? Just add more selectors in your override or use important! if all else fails, to override any color styles you want only on that one page... – OG Sean Sep 27 '17 at 19:45

10 Answers10

262

The below only works if the iframe content is from the same parent domain.

The following jquery script works for me. Tested on Chrome and IE8. The inner iframe references a page that is on the same domain as the parent page.

In this particular case, I am hiding an element with a specific class in the inner iframe.

Basically, you just append a style element to the head section of the document loaded in a frame:

frame.addEventListener("load", ev => {
    const new_style_element = document.createElement("style");
    new_style_element.textContent = ".my-class { display: none; }"
    ev.target.contentDocument.head.appendChild(new_style_element);
});

You can also instead of style use a link element, for referencing a stylesheet resource.

Nidhin Joseph
  • 8,658
  • 3
  • 18
  • 40
SimpleSam5
  • 2,889
  • 2
  • 13
  • 13
  • 5
    @SimpleSam5 Can you provide the Javascript alternative (without using Jquery) ? – Kamalakannan J Sep 09 '16 at 04:33
  • 2
    @sincerekamal Here's the code without the need of jQuery: https://jsfiddle.net/9g9wkpon/ You just need to know that hyphenated CSS properties are written in camelCase in JavaScript, like in my example. :) – Dennis98 Sep 27 '16 at 10:19
  • 2
    jquery.js?ver=1.12.4:2 Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "https://xxxxxxxxx.com" from accessing a cross-origin frame. – Alex Stanese Dec 09 '16 at 08:50
  • 2
    @AlexStanese as jeremy states, this only works if the iframe page is coming from the same server as the parent page...which typically means you don't need to bother with javascript anyways...just add the CSS to the other page in the f irst place. – DA. Jan 27 '17 at 17:12
  • @KamalakannanJ you don't even need to use Javascript. Just edit the page that's in the iFrame and put the CSS there. – DA. Jan 27 '17 at 17:13
  • @KamalakannanJ in order to get a better understanding, read the following article form MDN that explains what CORS (Cross-Origin Resource Sharing ) is. https://mzl.la/2E4ehEX I hope it helps! – vasilisdmr Feb 22 '18 at 09:54
  • Does an iframe with an embedded pdf from the same domain qualify ? `` – Peter Buju Apr 16 '19 at 07:27
118

An iframe is a 'hole' in your page that displays another web page inside of it. The contents of the iframe is not in any shape or form part of your parent page.

As others have stated, your options are:

  • give the file that is being loaded in the iframe the necessary CSS
  • if the file in the iframe is from the same domain as your parent, then you can access the DOM of the document in the iframe from the parent.
Louis
  • 4,007
  • 3
  • 36
  • 52
DA.
  • 36,871
  • 47
  • 133
  • 201
27

You cannot change the style of a page displayed in an iframe unless you have direct access and therefore ownership of the source html and/or css files.

This is to stop XSS (Cross Site Scripting)

Myles Gray
  • 8,055
  • 7
  • 46
  • 69
  • What do you mean by 'direct access'? The page in the iframe is from my site, its all one domain. – jd6699 Jun 27 '11 at 15:02
  • 3
    Well then you will need to change the source file on your site (you cannot modify any contents in an iframe) - so if the iframe is pointing at mysite.com/test.html then you will need to modify test.html directly... – Myles Gray Jun 27 '11 at 15:05
  • 1
    Cannot? Under the conditions the OP says you can. For example, his inner iframe URL is same as his parent site so he should be able to access the DOM ok with any flavor of javascript you like... – OG Sean Sep 27 '17 at 19:41
  • @Myles Gray Wrong. You can modify the content in an iframe from it's parent page if it's on the same domain, both with JavaScript and CSS. – Kevin M Apr 08 '19 at 21:22
12

This code uses vanilla JavaScript. It creates a new <style> element. It sets the text content of that element to be a string containing the new CSS. And it appends that element directly to the iframe document's head.

Keep in mind, however, that accessing elements of a document loaded from another origin is not permitted (for security reasons) -- contentDocument of the iframe element will evaluate to null when attempted from the browsing context of the page embedding the frame.

var iframe = document.getElementById('the-iframe');
var style = document.createElement('style');
style.textContent =
  'body {' +
  '  background-color: some-color;' +
  '  background-image: some-image;' +
  '}' 
;
iframe.contentDocument.head.appendChild(style);
amn
  • 6,917
  • 6
  • 48
  • 75
2540625
  • 9,332
  • 5
  • 41
  • 51
  • 8
    `Blocked a frame with origin xxxxxxxxx from accessing a cross-origin frame.` I'm afraid it won't work – Mike Oct 06 '17 at 21:16
  • @Mike I bypassed that by using a serverside lang(PHP) to parse iframe url and return html response to prevent cors errors – Justine M. Jan 18 '21 at 03:35
9

Override another domain iframe CSS

By using part of SimpleSam5's answer, I achieved this with a few of Tawk's chat iframes (their customization interface is fine but I needed further customizations).

In this particular iframe that shows up on mobile devices, I needed to hide the default icon and place one of my background images. I did the following:

Tawk_API.onLoad = function() {
// without a specific API, you may try a similar load function
// perhaps with a setTimeout to ensure the iframe's content is fully loaded
  $('#mtawkchat-minified-iframe-element').
    contents().find("head").append(
     $("<style type='text/css'>"+
       "#tawkchat-status-text-container {"+
         "background: url(https://example.net/img/my_mobile_bg.png) no-repeat center center blue;"+
         "background-size: 100%;"+
       "} "+
       "#tawkchat-status-icon {display:none} </style>")
   );
};

I do not own any Tawk's domain and this worked for me, thus you may do this even if it's not from the same parent domain (despite Jeremy Becker's comment on Sam's answer).

Community
  • 1
  • 1
CPHPython
  • 6,842
  • 2
  • 41
  • 58
9

An iframe has another scope, so you can't access it to style or to change its content with javascript.

It's basically "another page".

The only thing you can do is to edit its own CSS, because with your global CSS you can't do anything.

Alessandro Vendruscolo
  • 12,889
  • 4
  • 29
  • 38
  • Yes you can, with javascript. Note it works best with the iframe URL and the parent URL sharing the same domain. But, I think you are right in pointing out this can just be done with CSS on the page inside the iframe. – OG Sean Sep 27 '17 at 19:42
1

If you have control of the page hosting the iframe and the page of the iframe, you can pass a query parameter to the iframe...

Here's an example to add a class to the iframe based on whether or not the hosting site is mobile...

Adding iFrame:

var isMobile=$("mobile").length; //detect if page is mobile
var iFrameUrl ="https://myiframesite/?isMobile=" + isMobile; 

$(body).append("<div id='wrapper'><iframe src=''></iframe></div>");
$("#wrapper iframe").attr("src", iFrameUrl ); 

Inside iFrame:

//add mobile class if needed
var url = new URL(window.location.href);
var isMobile = url.searchParams.get("isMobile");
if(isMobile == "1") {
    $("body").addClass("mobile");
}
Ben
  • 1,521
  • 13
  • 19
  • Maybe you can help me. Look at this : https://stackoverflow.com/questions/60923168/how-can-i-override-css-of-content-in-an-iframe – Success Man Mar 30 '20 at 04:21
0

I have a blog and I had a lot of trouble finding out how to resize my embedded gist. Post manager only allows you to write text, place images and embed HTML code. Blog layout is responsive itself. It's built with Wix. However, embedded HTML is not. I read a lot about how it's impossible to resize components inside body of generated iFrames. So, here is my suggestion:

If you only have one component inside your iFrame, i.e. your gist, you can resize only the gist. Forget about the iFrame.

I had problems with viewport, specific layouts to different user agents and this is what solved my problem:

<script language="javascript" type="text/javascript" src="https://gist.github.com/roliveiravictor/447f994a82238247f83919e75e391c6f.js"></script>

<script language="javascript" type="text/javascript">

function windowSize() {
  let gist = document.querySelector('#gist92442763');

  let isMobile = {
    Android: function() {
        return /Android/i.test(navigator.userAgent)
    },
    BlackBerry: function() {
        return /BlackBerry/i.test(navigator.userAgent)
    },
    iOS: function() {
        return /iPhone|iPod/i.test(navigator.userAgent)
    },
    Opera: function() {
        return /Opera Mini/i.test(navigator.userAgent)
    },
    Windows: function() {
        return /IEMobile/i.test(navigator.userAgent) || /WPDesktop/i.test(navigator.userAgent)
    },
    any: function() {
        return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
    }
};

  if(isMobile.any()) {
    gist.style.width = "36%";
    gist.style.WebkitOverflowScrolling = "touch"
    gist.style.position = "absolute"
  } else {
    gist.style.width = "auto !important";
  }
}

windowSize();

window.addEventListener('onresize', function() {
    windowSize();
});

</script>

<style type="text/css">

.gist-data {
  max-height: 300px;
}

.gist-meta {
  display: none;
}

</style>

The logic is to set gist (or your component) css based on user agent. Make sure to identify your component first, before applying to query selector. Feel free to take a look how responsiveness is working.

Zoe
  • 23,712
  • 16
  • 99
  • 132
Victor R. Oliveira
  • 2,434
  • 5
  • 36
  • 66
-5

Perhaps it's changed now, but I have used a separate stylesheet with this element:

.feedEkList iframe
{
max-width: 435px!important;
width: 435px!important;
height: 320px!important;
}

to successfully style embedded youtube iframes...see the blog posts on this page.

pwdst
  • 12,609
  • 3
  • 30
  • 48
  • 4
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Shaiful Islam May 05 '15 at 00:00
  • 4
    This only applies to the iFrame element itself - the question asks specifically about the iFrame content, which it currently isn't possible to change through CSS alone. – pwdst Jul 22 '15 at 14:18
  • @ShaifulIslam which is precisely what has happened. Rending Tims answer useless. – Alex Foxleigh Sep 05 '17 at 11:43
-28

give the body of your iframe page an ID (or class if you wish)

<html>
<head></head>
<body id="myId">
</body>
</html>

then, also within the iframe's page, assign a background to that in CSS

#myId {
    background-color: white;
}
Troy Alford
  • 24,997
  • 8
  • 60
  • 77
mikeq
  • 821
  • 5
  • 5
  • This is weird. Your solution works for me when I add it to the page with firebug, but doesn't work if its in the page's normal css file. Could this be part of your comment 'assuming the page within the iFrame is yours to edit'? I didnt understand what you meant by that. Thanks – jd6699 Jun 27 '11 at 15:45
  • I mean by that, is the page you are loading into the iFrame from your site and under your control? or is it from an external site that you cannot edit the source to include that id/class. – mikeq Jun 28 '11 at 08:31
  • It is from my site, but as its done in by the editor it wont be easy to change the mark up that is pulled through. – jd6699 Jun 28 '11 at 10:54
  • ps I didnt mean add the id="myId" to your main page, but to the page within the iFrame. That way you can target the body of the iFrame page with a different style to your main page. You are also referencing the CSS file in your iFrame pages also aren't you. You need to treat the page loaded in the iFrame as a completely independant page. If you load just that page into a web browser does it have the correct style? – mikeq Jun 28 '11 at 13:16
  • Im not actually sure where the 'page' is as its not the whole page the editor uses. Thanks for your help, I think I understand how all this stuff works noe. – jd6699 Jun 29 '11 at 08:31