I loaded a complete html(see below for skeleton) page with the following structure into the another html page using clicking of the button.
<!--START:HTML to be loaded by ajax-->
<head>
<!--START: The content inside this head tag is not processed while the page is loaded via ajax-->
<link rel="stylesheet" type="text/css" href="css/rrr.css" media="screen, projection, print" />
<script>
...
</script>
<script type="text/javascript" src="aaas/xxxx.js"></script>
<!--END: The content inside this head tag is not processed while the page is loaded via ajax-->
</head>
<div id="content">
<!--Page content on which the above script tags inside head tag to act-->
</div>
<!--END:HTML to be loaded by ajax-->
In safari version 5.0.1 and in 5.0.2, the content inside the head tag is not parsed, but the content inside html is parsed in all IE,FF and chrome and safari 5.1.2.
and Content inside div with id equal to "content" is shown in all browsers including safari 5.0.1 and 5.0.2.
Please help me in this.Thanks in advance.
The LINK element can only be used in the HEAD of a document.
From the reference :
Unlike A, it may only appear in the HEAD section of a document,
although it may appear any number of times.
So you may load this inside a iframe (which holds a document) but not inside a div, except for browsers not following the norm.
In your case the easiest workaround would probably be to use an iframe. Note that the css won't apply to the parent document.
Use a documentFragment to store the responseText, then perform the following steps:
Strip out the CSS that should not be applied
Move the script tag into the body
Remove the head tag
Append the result to the parent page
Related
tldr: I'm looking to keep the other text in the srcdoc attribute of an iframe alone, but only swap out the link to the stylesheet using vanilla Javascript.
Longer version:
I'm customizing a Publii blog template and embedding a Cusdis comment widget using their hosted JS SDK.
Publii makes use of HTML, CSS, Javascript, and Handlebars.
The Cusdis widget works by pasting the following code in your html document:
<div id="cusdis_thread"
data-host="https://cusdis.com"
data-app-id="{{ APP_ID }}"
data-page-id="{{ PAGE_ID }}"
data-page-url="{{ PAGE_URL }}"
data-page-title="{{ PAGE_TITLE }}"
>
<script async src="https://cusdis.com/js/cusdis.es.js"></script>
Then, the Cusdis SDK will find the element with id cusdis_thread, then mount the iframe widget on it:
<iframe srcdoc='<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cusdis.com/js/style.css">
<base target="_parent" />
<link>
<script>
window.CUSDIS_LOCALE = undefined
window.__DATA__ = {"host":"https://cusdis.com","appId":"...","pageId":"...","pageUrl":"...","pageTitle":"..."}
</script>
</head>
<body>
<div id="root"></div>
<script src="https://cusdis.com/js/iframe.umd.js" type="module"
</script>
</body>
</html>'
style="width: 100%; border: 0px none; height: 323px;">
#document
</iframe>
My issue is the following:
I want to edit the Cusdis widget's CSS so that the look goes better with my site.
I've tried editing my own stylesheet and selecting Cusdis's CSS classes, but the changes aren't reflected in the output (even with !important). I suspect that it's because the widget generates an iframe, and the elements I want to edit are contained in the iframe.
The workaround seems to be to replace the stylesheet in the iframe's "srcdoc" attribute with a link to another external stylesheet
Because the iframe is automatically generated by Cusdis's SDK, I can't edit that HTML on my end. I'm trying to find a way to replace the stylesheet in the generated iframe's srcdoc using vanilla Javascript.
Here is what I've tried:
Using setAttribute to replace the contents of the attribute:
document.querySelector("#cusdis_thread iframe").setAttribute('srcdoc', '<!DOCTYPE html><html><head><link rel="stylesheet" href="..."><base target="_parent" /><link><script> window.CUSDIS_LOCALE = undefined window.__DATA__ = {"host":"https://cusdis.com", appId":"...","pageId":"{{id}}","pageUrl":"{{url}}","pageTitle":"{{title}}"} </script> </head> <body> <div id="root"></div> <script src="https://cusdis.com/js/iframe.umd.js" type="module"> </script></body></html>');
Result: It worked in theory, but the comment section wasn't generated. When I inspected the code, the attribute's content was replaced. However, I'm using handlebars expressions {{}} to add the PAGE_ID, PAGE_URL, and PAGE_TITLE dynamically, but these expressions are kept inside the srcdoc (so, instead of the iframe displaying the actual URL in the window.__DATA__ =... section, it's still showing the handlebars expression {{url}}).
So, I'm looking for a solution which will keep the other text in the srcdoc attribute alone, but only swap out the link to the stylesheet. Here are my attempts at this:
Using .replace to find the url of Cusdis's stylesheet and replacing it with my own:
document.querySelector("#cusdis_thread iframe").replace("https://cusdis.com/js/style.css", "...");
Result: it was ignored
Using setAttribute for just the stylesheet:
document.querySelector("#cusdis_thread iframe").setAttribute('srcdoc', '<link rel="stylesheet" href="...">');
Result: it was ignored
Since this iframe is loaded through its srcdoc attribute, you can access its inner document from your own document, (because about:srcdoc is magic).
So the best will be to wait for the iframe to load, and to inject your own <link> in there (or modify the StyleSheets as you wish).
const iframe = document.querySelector("iframe");
iframe.addEventListener("load", (evt) => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "your-stylesheet.css";
iframe.contentDocument.head.append(link);
}, { once: true });
Live Demo (as a jsfiddle because StackSnippets null-origined iframes are dark-magic against same-origin...
The complicated part might be to detect when this iframe is inserted into the document. It seems you already are able to do so, but for the ones who can't, they could either check which event the library fires from, or in worst case scenario, use a MutationObserver.
I have to follow a Google advice to first load critical CSS inline in the header then load other styles. Some articles advise to load other styles asynchronously with the help of JS. However, I wonder whether I can simply place them before the closing body tag. Is it going to affect rendering negatively (taken that the above the fold styles are already loaded)?
<html>
<head>
<style>
<!-- Critical CSS goes here to display what's above the fold -->
</style>
</head>
<body>
...
<link rel="stylesheet" ... >
</body>
</html>
In HTML5.0 the <link> element is only allowed in the <head>:
If the rel attribute is used, the element is restricted to the head element.
(Note also the previous line: "A link element must have a rel attribute".)
But the HTML5.2 working draft relaxes this requirement:
Keywords that are body-ok affect whether link elements are allowed in the body. The body-ok keywords defined by this specification are prefetch, and stylesheet.
I am loading .html content with jquery .load() but the javascript and css is not applied to the one.html/two.html after it is loaded by the .load() function.
Example below:
<head>
<style> styles1 </style>
<link href="stylesheets/style2.css" rel="stylesheet">
<script src="script1.js">
<script>
$(document).ready(function(){
$("button.os").click(function(){
fillmein = $(this).attr("target");
fillmeinfile = $(this).attr("target")+'.html';
$("."+fillmein).load("/contentfolder/"+fillmeinfile);
});
});
...
other scripts
...
</script>
</head>
<body>
<p>the css and any js is applied to this block</p>
<button class="os" target="one">replace</button>
<div class="one">I will be replaced by one.html</div>
<button class="os" target="two">replace</button>
<div class="two">I will be replaced by two.html</div>
</body>
I understand that the one.html/two.html is loaded after the styles and javascript is loaded by the browser but how I get the styles and javascript that is in the <head> to apply to the newly loaded one.html/two.html?
I new to jQuery so let me know how I clarify if needed. thanks!
EDITED
Thanks for providing answers everyone! Updated the code example to clarify what I meant.
copying the <style> and <script> into the one.html and two.html works but if I load the javascript twice it could conflict. for example, having logic that searches $(document), and functions that collapse and expand a section can be called multiple times. Is it possible to have the js and css that was loaded in the main page work on the newly loaded .html files or is there any clean and DRY way to do this?
As suggested by Arun P Johny in his comment
You simply put your CSS inline on the target document and it will be automatically loaded along with the content.
You can write
$('button').on('click','Classname',function(){
//write your structure here
})
This will work for all tags with 'Classname',which are already present or dyanamically added later on.
I know this question was asked many times, but I haven't found answer. So why its recommended to include scripts at the end of body tag for better rendering?
From Udacity course https://www.udacity.com/course/ud884 - rendering starts after DOM and CSSOM are ready. JS is HTML parse blocking and any script starts after CSSOM is ready.
So if we got:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- content -->
<script src="script.js"></script>
</body>
</html>
CRP would be:
CSSOM ready > JS execute > DOM ready > Rendering
And if script is at head:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CRP</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<!-- content -->
</body>
</html>
CRP would be the same:
CSSOM ready > JS execute > DOM ready > Rendering
This question is only about "sync" scripts (without async/defer attribute).
Scripts, historically, blocked additional resources from being downloaded more quickly. By placing them at the bottom, your style, content, and media could download more quickly giving the perception of improved performance.
Further reading: The async and defer attributes.
In my opinion, this is an outdated practice. More recently, the preference is for JavaScript to separate any code that requires the DOM to be present into a "DOMContentLoaded" event listener. This isn't necessarily all logic; lots of code can initialize without access to the complete DOM.
It's true that this causes a small moment when only the script file is being retrieved, and nothing else (for instance, images). This small window can be skipped by adding the async attribute, but even without it I recommend putting script tags in the head so that the browser knows as soon as possible to load them, rather than saving them (and any future JS-initiated requests) for last.
It is a best practice to put JavaScript tags just before the
closing tag rather than in the section of your HTML.
The reason for this is that HTML loads from top to bottom. The head
loads first, then the body, and then everything inside the body. If we
put our JavaScript links in the head section, the entire JavaScript
file will load before loading any of the HTML, which could cause a few
problems.
1.If you have code in your JavaScript that alters HTML as soon as the
JavaScript file loads, there won't actually be any HTML elements
available for it to affect yet, so it will seem as though the
JavaScript code isn't working, and you may get errors.
2.If you have a lot of JavaScript, it can visibly slow the loading of your page
because it loads all of the JavaScript before it loads any of the
HTML. When you place your JavaScript links at the bottom of your HTML
body, it gives the HTML time to load before any of the JavaScript
loads, which can prevent errors, and speed up website response time.
One more thing: While it is best to include your Javascript at the end
of your HTML , putting your Javascript in the of your
HTML doesn't ALWAYS cause errors. When using jQuery, it is common to
put all of your code inside a "document ready" function:
$("document").ready(function(){ // your code here });
This function basically says, don't run any of the code inside until
the document is ready, or fully loaded. This will prevent any errors,
but it can still slow down the loading time of your HTML, which is why
it is still best to include the script after all of the HTML.
Images placed below the script tag will wait to load until the JS script loads. By placing the script tag at the bottom you load images first, giving the appearance of a faster page load.
I think it depends on your website or app. Some web apps are based on JavaScript. Then it does not make sense to include it at the bottom of the page, but load it immediately. If JavaScript just adds some not so important features to some content based page, then better load it at the end. Loading time will almost be the same, but the user will see the important parts earlier (before the page finished loading).
It’s not about a whole site loading faster, but giving a user the impression of some website loading faster.
For example:
This is why Ajax based websites can give a much faster impression. The interface is always the same. Just some content parts will alter.
This was an extremely useful link. For any given webpage, a document object model is created from the .html. A CSS object model is also created from .css.
We also know that JS files also modify objects. When the browser encounters a tag, the creation of DOM and CSS object models are immediately halted when the script is run because it can edit everything. As a result, if the js file needed to extract information from either of the trees (DOM and CSS object model), it would not have enough information.
Therefore, script srces are generally at the end of the body where most of the trees have already been rendered.
Not sure if this helps,
But from this resource script-tag-in-web the inline script is always render blocking even if kept at the end of body tag.
Below inline script is first render blocking.Browser will not paint anything on screen till the long for loop is executed
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script>
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
But'index.js' below is not initial render blocking, the screen will be painted , then once external 'index.js' is finished running the span tag will be updated.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path: Script</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script type="text/javascript" src="./index.js">
</script>
</body>
</html>
index.js
let word = 0
for(let i =0; i<3045320332; i++){
word += i;
}
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = word + 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
When I insert this code into my file it seems to block my CSS from showing. I made a script to try and print text once the page has loaded which I am then going to use later to make a loaded bar. This is my code. All that happens is I get the text "Test" printed on my page.
<html>
<head>
<link rel="stylesheet" type="text/css" href="custom.css">
<script>
function myFunction() {
document.getElementById('index').innerHTML = "test";
}
</script>
</head>
<!-- Page Body -->
<body id="index" onload="myFunction()">
<div class="header">
<div id="headerbar"></div>
<ul id="">
</div>
</body>
</html>
When you set the innerHTML of the index element, it completely replaces everything in the body. So you no longer have the DIV with the header class, and you no longer have the DIV with the headerbar ID. There's nothing for your CSS to refer to. It's as if you had written:
<body id="index">test</body>
Well for one we have no way of knowing what your CSS does, but an issue I see is that when you are using innerHTML it overwrites existing HTML. As in everything inside the body tag is overwritten to just test text.
Caveat: My presumption is that you don't have styles on the body either.
What exactly is your CSS supposed to style when you set the innerHTML of your body element to "test" ? You're removing all other contained elements by doing this.
I guess what you wanted to do is add a text node like this:
document.body.appendChild(document.createTextNode("test"));