This question already has answers here:
How to apply CSS to iframe?
(28 answers)
Closed 5 years ago.
First of all, it seems like there are a lot of posts with the same kind of title, but none of them is focusing on the problem I am facing. That is the reason why I opened this new question, and I hope the title is explicit enought.
I am working on a text-editor on my own, and I was using a <textarea> at first, but I wanted to add various styles to the elements I was writing. After reading a lot of topics about it, I decided to change my <textarea> for an <iframe>.
Before trying anything new with design or whatever, I would like to have the same behaviour with this <iframe> and my previous <textarea>. But I am facing an issue :
My <iframe> element is in a page, index.html, which is linked with a CSS file, style.css. I am able to change the global <iframe> design (like width, height, border...) of the frame in style.css, but I can't add a special design to the elements inside the <iframe> with properties I added in my style.css.
I saw in the inspector that the iframe has a #document before any tag
But even if I tried to add this strange tag to the CSS, the style is not applied to the elements I want to change.
So to be concise, my question is this one : Is it possible to add some style to elements inside an iframe in the stylesheet file of the host page ?
Here are some relevant parts of my code, which shows what I would like to do : add a custom font to the <p> tags inside the <iframe>.
window.onload = function() {
var frameElement = document.getElementById("text-field");
var doc = frameElement.contentDocument;
doc.body.contentEditable = true;
}
html, body {
margin : 0px;
background : #f5f5f5;
font-family: 'Roboto', sans-serif;
}
input:focus, textarea:focus {
outline: none;
}
.text-editor {
min-width : 800px;
width : 1200px;
max-width : 1600px;
min-height : 400px;
height : 850px;
max-height : 850px;
background : #f0f0f0;
box-shadow : 0px 1px 4px #ccc;
margin : auto;
overflow:auto
}
.text-editor .text-field {
display : block;
background-color : white;
min-height : 300px;
height : 600px;
max-height : 600px;
width : 90%;
margin : auto;
padding : 5px;
border: 1px solid #ccc;
}
.text-editor .text-field #document html body {
font-family: 'Source Code Pro', monospace;
font-size : 14px;
}
<!DOCTYPE html>
<html>
<head>
<title>A Text Editor Project</title>
<link rel="stylesheet" type="text/css" href="CSS/style.css">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div class="text-editor">
<iframe class="text-field" id="text-field" src="about:blank" contenteditable="true">
</iframe>
</div>
</body>
</html>
Styles from the parent will not be applied to the document within the iframe. The best solution is to add the stylesheet to the document in the iframe. Either via javascript or creating a template page to load in via src.
Something like:
var head = doc.head
var link = doc.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = ...src...
head.appendChild(link)
in your existing javascript.
I've put together a small example with a style block here
Related
Assuming I have a folowing code - fiddle - with font-size attribute set for <html> tag. This styling along with header and footer is generated via js script which cannot be removed. This is already existing page for a long time.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<link rel="stylesheet" href="bootstrap4.css">
<link rel="stylesheet" href="myCustomCss.css">
<link rel="stylesheet" href="cssLoadedByJs.css">
</head>
<body>
<div>
Header (need to stay as it is now with smaller font)
</div>
<div class="content"> <!-- (need to reset it 100%, so content will be sized as I want...) -->
Content
<h2>
H1 here
</h2>
</div>
<div>
Footer (need to stay as it is now with smaller font)
</div>
</body>
</html>
Css file injected by remote js (cssLoadedByJs.css) - cannot remove it, need to stay:
html {font-size: 62.5% !important;}
myCustomCss.css - what I was trying to do:
html .content {
/* font-size: 100% !important; */
/* font-size: unset; */
/* font-size: 16px; */
}
How to reset font-size attribute for content div only and preserve header and footer as it is?
I've tried to set font-size: unset; or font-size: 100% for content div but no result. font-size: 16px let me render text in 16px as I want, but h2 still has only 20px insted of 32px (due to this sizing for html tag, bootstrap use 2rem for h2). Anyway I believe that there is better way than just hardcoded pixel size. Possible to do this somehow? Pls check fiddle for better understanding and tests...
I'm not sure why exactly are you using font size on html tag directly but maybe the following hack can help overcome your problem.
html > body > div.content,
html > body > div.content * {
font-size: 137.5%;
}
I seriously advise not using this approach and styling specific elements instead.
Check this: https://jsfiddle.net/5jdrta16/1/
I took the font-size... important setting off of the <html> and applied it to the <body> element (without important). I also moved all the styling into the CSS.
.content {
font-size: 30px; /* I used 30px vs. 16px to more clearly illustrate that it's applied */
}
body {
font-size: 62.5%;
}
What about:
.content, .content * {
font-size: initial;
}
I'm currently trying to load some CSS file into a page that has already been loaded and rendered by the browser and apply it's styling to the page without reloading it as a whole.
I can't modify the original page too much, so the CSS has to be linked/included in the html at a later moment using JavaScript. I tried adding a <link> element referring to the CSS file in the header, as well as adding <style> with the CSS itself.
The modification of the html does work fine, but the layout of the page isn't affected at all. Probably because the browser doesn't re-render the page at this point?
I saw some answers here suggesting that it would work like described above, but for me it does nothing. What could be the reason here?
As requested, some of the JavaScript i'm using to update the HTML of the page. Both ways work fine, the elements are added to the page. So I presume the error lies somewhere else.
1.) Adding actual CSS by reading it with XHR from file:
var promptCSS= document.createElement('style');
promptCSS.type="text/css";
var cssPromptFileSelectStyleURL= 'promptFileSelectStyle.css';
//add css of prompt into current page html
var cssFile = new XMLHttpRequest();
cssFile.open("GET",cssPromptFileSelectStyleURL,true);
cssFile.send();
cssFile.onreadystatechange = function(){
if (cssFile.readyState== 4 && cssFile.status == 200){
promptCSS.innerHTML=cssFile.responseText;
}};
var head=document.querySelectorAll("head")[0];
head.appendChild(promptCSS);
2.) adding <link> referencing CSS file
var promptCSS= document.createElement('link');
promptCSS.rel = 'stylesheet';
promptCSS.type = 'text/css';
promptCSS.href = 'promptFileSelectStyle.css';
var head=document.querySelectorAll("head")[0];
head.appendChild(promptCSS);
Inline CSS isn't set between <script> tags, but between <style> tags.
Also here is a Fiddle that tests your method : https://jsfiddle.net/sLpfLsLc/
It waits 2 seconds before loading a new CSS file containing
*{
background: red;
}
As you can see, it works fine !
Maybe this will point you in the right direction. I am not 100% sure I understood what you need. So if this is the case you can try appending a link tag with the css file url in it whenever you need. For instance you can trigger that script when you scroll X height or a click happened or whatever. For this case I am appending a style tag to the head every 2 seconds and then removing it so it won't keep appending every 2 seconds. Instead of style maybe you can do a <link rel="stylesheet" type="text/css" href="promptFileSelectStyle.css"/>
Hope this helps.
function remover(){
$(".style-tag").remove();
}
function x(){
var style = $('<style class="style-tag">.columns {justify-content: space-around;} </style>');
$('html > head').append(style);
$(".parent").toggleClass("columns");
}
$(document).ready(function(){
setInterval(function(){
remover();
x();
}, 2000);
});
.parent{
display:flex;
justify-content: center;
flex-wrap: wrap;
width: 100%;
}
.box{
background: red;
border: 1px solid black;
width: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
</div>
Is it possible to isolate elements inside a div as if it were in an iFrame?
I have an app inside SharePoint that is all jacked up from the global SharePoint styles which I want to turn off completely so my app uses only the css it contains.
EG: Let's say there is a global stylesheet for the page. Let's say I put a div on that page with it's own embed css. Can I somehow ignore the global stylesheet entirely?
https://plnkr.co/edit/2H2TJJz6rNZK18OK6VLW?p=preview
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
</body>
</html>
Web Components would be your only option for encapsulation similar to an iframe. You can get pretty good coverage with a polyfill like webcomponents.js
Polymer is a great framework for making Web Components easier.
This would make your code look like this:
... HTML here that uses your global styles ...
<my-element></my-element> <!-- this element would not inherit the global CSS -->
And inside of your my-element component (which would just be another file in your file system that you import into the page - see docs above), you can include unique styles to the content of my-element.
The problem is your global styles have a !important declaration in them. While I don't normally advise this, you'd have to add it to your declaration to be able to override them. i.e.
/* Global parent styles go here */
h1 {
color:red;
border: 5px solid red !important;
}
h1 {
color:red;
border: 1px solid blue !important;
}
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue !important;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
use shadow dom in my case i use angular 1 so i used an iframe but in angular 2 we can play with shadow dom
Use an iFrame with the srcdoc attribute set to your html.
var myIframe = document.createElement('iframe');
myIframe.src = 'about:blank';
var info = `<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
</body>
</html>`;
myIframe.srcdoc = info;
var body = window.document.querySelector('body');
body.insertBefore(myIframe, body.firstChild);
I needed to dynamically inject my html content without being impacted by the pages css so that is why my iframe was created with js, but shouldn't be any reason that yours couldn't be written in html only. Although the srcdoc might be a little messy, so it might be cleaner to write it (the srcdoc) as a js variable and then attach it.
Let look at the following codes as example.
var tst;
tst = document.getElementsByClassName("tst");
tst.style.backgroundColor = "#008000";
tst.style.marginTop = "50px";
tst.innerHTML = "Testing an element.";
body {
font-size: 0px;
padding: 0px;
margin: 0px;
width: 100%;
overflow-x: hidden;
}
.tst {
font-family: Arial;
font-size: 20px;
color: #FFFFFF;
text-align: center;
background-color: #FF0000;
padding: 10px;
margin: 10px auto 0px auto;
width: 200px;
display: block;
overflow: hidden;
}
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<div class="tst"></div>
<script src="./js_style.js"></script>
</body>
<html>
Now my question is, in which order browser will execute this codes,
like,
1. Browser default
2. External style sheet
3. Internal style sheet (in the head section)
4. Inline style (inside an HTML element)
5. Styles in JavaScript
or in different order?
And how can we change the order?
Thanks Everyone.
CSS is not executed. It's just a set of rules that dictates what an element should look like.
So yes, the order you specified is the right order, but that doesn't necessarily mean that a later style overrules an earlier one.
Most important here, is the specificity of the CSS selector. For instance a CSS selector with a class name (like .tst) is more specific than a selector with a tag name (like div). So if you would have both selectors, and both of them setting the color of your test div, then the color of .tst would be used over the other.
But when selectors are of the same specificity, the last one that is encountered is used, so there may be a later one in the same style sheet, or in a different external style sheet. When evaluating this, the order you mentioned is important.
However, that specificity merely affects the internal and external style sheets. When you have inline styles, they always overrule the styles in the style sheet.
the same applies to the JavaScript code, since it just changes the inline style of the element.
Is it possible to embed a scrollable text box to output text on my web page, in HTML or JavaScript?
I am trying not to use any Java libraries if possible.
<textarea></textarea>
<style type="text/css" media="screen">
#messages{
border : solid 2px #ff0000; background : #D5D5D5; padding : 4px; width : 500px; height : 350px; overflow : auto;
}
</style>
<div id='messages'>
</div>
to scroll down with jquery:
$('#messages').scrollTop( $('#messages')[0].scrollHeight );
Since the question is pretty vague i am going to recommend jScroller (since i've used it for some projects)