I want to know how can I load a css on a website before it loads.
I have tried the code below in main.js
win.webContents.on('did-start-loading', function () {
fs.readFile(__dirname + '/home.css', "utf-8", function (error, data) {
if (!error) {
var formatedData = data.replace(/\s{2,10}/g, ' ').trim()
win.webContents.insertCSS(formatedData)
}
})
})
It did work but the original style of the website popped up for few seconds and then it loaded my style, which makes zero sense if the original CSS and mine got whole different style.
I also tried loading the CSS below in preload.js
window.addEventListener("DOMContentLoaded", injecting)
function injecting() {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://example.com/hello.css';
document.documentElement.appendChild(link);
}
It also did not work. It keeps showing the original style and then loads my css after a second.
You cannot control the speed of the CSS download, but you can achieve a similar behavior. You could have body as:
<body class="invisible">
<!-- Some HTML here -->
</body>
and some helpful CSS
.invisible {
display: none;
}
Now, you could do
document.body.className = ""; once the CSS is loaded as:
window.addEventListener("DOMContentLoaded", injecting)
function injecting() {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://example.com/hello.css';
link.onload = (() => {document.body.className = "";});
document.documentElement.appendChild(link);
}
Related
I'm trying to inject some CSS into an iFrame and it works fine except there is a delay before the new CSS takes effect, so you get a page that loads one theme and then changes color. It's only visible for a second, but it's annoying. Is there any way to delay the iFrame render until that CSS is applied? I add a script after the CSS, but seems that since I'm injecting this into the DOM, it renders then re-renders. I've tried using readyState interactive and complete to get it before load, but no luck and not sure how to delay it. Also tried addEventListener("load"), but it appears to change before the load fires.
const frame_doc = document.getElementById("iframe").contentDocument;
function setFrameClass(light) {
if (light) {
frame_doc.body.classList.remove("dark")
} else {
frame_doc.body.classList.add("dark")
}
}
themeSwitch.addEventListener('change', function () {
setFrameClass(this.checked, frame_doc.body)
});
frame_doc.onreadystatechange = function () {
if (frame_doc.readyState === 'interactive') {
let link = frame_doc.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = new URL('rootstatic/css/dark.css', window.location.origin).href;
link.media = 'all';
frame_doc.head.appendChild(link);
let s = frame_doc.createElement("script");
s.type = "text/javascript";
s.src = new URL('rootstatic/js/dark-mode.js', window.location.origin).href;
frame_doc.head.appendChild(s);
setFrameClass(themeSwitch.checked)
}
}
The plan:
I have an iframe, called frame.html. If the frame.html is shown alone (not inside a page) it should load the no_frame.css.
If the frame.html is shown as an iframe inside a page it should load the frame.css.
The CSS should change divs inside the frame.html, so its important that the script check out if the page stays alone or inside an iframe. And I want to use this script in general for iframes, not only for the iframe.html.
Is there a better way to achieve this?
UPDATE:
#Alex K. - like this??:
<script type="text/javascript">
jQuery(document).ready(function($){
if (window!=window.top) { framed=true }
var cssId = 'myCss'; // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.id = cssId;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'http://website.com/css/frame.css';
link.media = 'all';
head.appendChild(link);
}
});
I'm working with a CMS that prevents us from editing the head section. I need to add css stylesheet to the site, right after the tag. Is there a way to do this with JS, where I can add a script to the bottom of the page (I have access to add script right before the tag) that would then inject the stylesheet into the head section?
Update: According to specs, the link element is not allowed in the body. However, most browsers will still render it just fine. So, to answer the questions in the comments - one really has to add link to the head of the page and not the body.
function addCss(fileName) {
var head = document.head;
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = fileName;
head.appendChild(link);
}
addCss('{my-url}');
Or a little bit easier with jquery
function addCss(fileName) {
var link = $("<link />",{
rel: "stylesheet",
type: "text/css",
href: fileName
})
$('head').append(link);
}
addCss("{my-url}");
Original answer:
You don't need necessarily add it to the head, just add it to the end of body tag.
$('body').append('<link rel="stylesheet" type="text/css" href="{url}">')
as Juan Mendes mentioned, you can insert stylesheet to the head instead
$('head').append('<link rel="stylesheet" type="text/css" href="{url}">')
And the same without jQuery (see code above)
This will do what you want in an intelligent way. Also using pure JS.
function loadStyle(href, callback){
// avoid duplicates
for(var i = 0; i < document.styleSheets.length; i++){
if(document.styleSheets[i].href == href){
return;
}
}
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = href;
if (callback) { link.onload = function() { callback() } }
head.appendChild(link);
}
I've modified Eddie's function to remove or toggle the stylesheet on or off. It will also return the current state of the stylesheet. This is useful for example, if you want to have a toggle button on your website for vision-impaired users and need to save their preference in a cookie.
function toggleStylesheet( href, onoff ){
var existingNode=0 //get existing stylesheet node if it already exists:
for(var i = 0; i < document.styleSheets.length; i++){
if( document.styleSheets[i].href && document.styleSheets[i].href.indexOf(href)>-1 ) existingNode = document.styleSheets[i].ownerNode
}
if(onoff == undefined) onoff = !existingNode //toggle on or off if undefined
if(onoff){ //TURN ON:
if(existingNode) return onoff //already exists so cancel now
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = href;
document.getElementsByTagName('head')[0].appendChild(link);
}else{ //TURN OFF:
if(existingNode) existingNode.parentNode.removeChild(existingNode)
}
return onoff
}
Sample usage:
toggleStylesheet('myStyle.css') //toggle myStyle.css on or off
toggleStylesheet('myStyle.css',1) //add myStyle.css
toggleStylesheet('myStyle.css',0) //remove myStyle.css
You can use pure javascript and still elegance in the modern browser.
const range = document.createRange()
const frag = range.createContextualFragment(`THE CONTENT IS THE SAME AS THE HTML.`)
document.querySelector("YOUR-NODE").append(frag)
It's very easy to add any HTML code.
Document
createRange
createContextualFragment
Example 1
Add the style on the head by javascript.
<head></head><body><button class="hover-danger">Hello World</button></body>
<script>
const range = document.createRange()
const frag = range.createContextualFragment(`
<style>
.hover-danger:hover{
background-color: red;
font-weight: 900
}
</style>
`
)
document.querySelector("head").append(frag)
</script>
Example 2
Import CSS, JS, and modify the existing stylesheet.
<head></head>
<body><button class="btn btn-primary hover-danger">Hello world</button></body>
<script>
const range = document.createRange()
const frag = range.createContextualFragment(`
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js"/>
`)
document.querySelector("head").append(frag)
window.onload = () => {
// 👇 If you don't want to import the new source, you can consider adding the data to exists source.
const nodeLink = document.querySelector(`link[href^="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css"]`) // ^: match begin with my input
if (nodeLink) { // !== null
const stylesheet = nodeLink.sheet
const myCSS = `
background-color:red;
font-weight: 900;
`
stylesheet.insertRule(`.hover-danger:hover{ ${myCSS} }`, stylesheet.cssRules.length)
}
}
</script>
📙 You must have permission to modify the CSS directly
If you get the error:
Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules,
then you can reference: https://stackoverflow.com/a/49994161/9935654
Here is a simple one-liner to add a stylesheet:
document.head.insertAdjacentHTML('beforeend', `<link typs="text/css" rel="stylesheet" href="<Source URL>">`);
I have this Javascript snippet in my application to prevent clickjacking:
<script language="javascript" type="text/javascript">
var style = document.createElement('style');
style.type = "text/css";
style.id = "antiClickjack";
style.innerHTML = "body{display:none !important;}";
document.head.appendChild(style);
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
Basically, it creates a style element (CSS on the fly) to hide the body of the current page by default. Then, if it doesn't detect clickjacking, it deletes it. So, doing it this way, everyone who doesn't have Javascript can see the page too (although they won't be protected from clickjacking).
It works for every browser except for Internet Explorer, which throws a Unknown runtime error exception. Does someone have a suggestion on how to fix this?
Thanks :-)
You can't set the content of a <style> element via innerHTML. I think the correct property name is cssText but I'll have to check MSDN.
edit — yup that's it.
Thus your code can do this:
var style = document.createElement('style');
style.type = "text/css";
style.id = "antiClickjack";
if ('cssText' in style)
style.cssText = "body{display:none !important;}";
else
style.innerHTML = "body{display:none !important;}";
In the document HEAD element, add the following:
<style id="antiClickjack">body{display:none !important;}</style>
<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
When running in a web browser, I can do this to dynamically inject a stylesheet:
var link = document.createElement('link'),
head = document.getElementsByTagName('HEAD')[0];
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '/path/to/stylesheet.css';
head.appendChild(link);
Is there a way to do the same in XULRunner? I've seen you can use something called Components.interfaces.mozIJSSubScriptLoader to load JavaScript, but does the same capability exist for CSS?
You can try using the style sheet service. Something like:
var sss = Cc["#mozilla.org/content/style-sheet-service;1"]
.getService(Ci.nsIStyleSheetService);
var ios = Cc["#mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService);
var uri = ios.newURI("chrome://pluginname/skin/notes.css", null, null);
if(!sss.sheetRegistered(uri, sss.USER_SHEET)) {
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
}
More examples.