I have the following code that is run after the page loads:
function prepare_bootstrap()
{
console.log("Preparing bootstrap...");
var items = document.body.getElementsByTagName("*");
for (var i = items.length; i--;)
{
items[i].style.cssText = '!important';
}
var style1 = document.createElement("link");
style1.rel = "stylesheet";
style1.href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css";
document.body.appendChild(style1);
var style2 = document.createElement("link");
style2.rel = "stylesheet";
style2.href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css";
document.body.appendChild(style2);
var script = document.createElement("script");
script.src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js";
script.onload = script.onreadystatechange = function()
{
if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")
{
prepare_bootstrapdialog();
}
};
document.body.appendChild(script);
}
I am loading bootstrap to allow for nicely formatted popups.
However, the bootstrap overrides almost everything, making the page look messed up.
I tried making every style important, but to be honest, I have no idea what I'm doing.
Is there any way to make css NOT override previous css?
Thanks!
EDIT: As before stated, it is impossible to load bootstrap first as the javascript is part of a bookmarklet.
Have a read of this:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style#A_scoped_stylesheet
Will only work in some browsers though, so not an option for an publicly facing site. The best way to do this really would be to not just include bootstrap in its entirety, instead picking out the bits you need and just using them. You can get custom builds of bootstrap here:
http://getbootstrap.com/customize/
You really shouldn't just load css styles that you aren't actively using. Doing so creates more debugging work for you if you encounter styling issues, and also means you're potentially wasting bandwidth.
You should load the bootstrap stylesheet first, that way any stylesheets linked after that will override bootstrap's
(This is making use of the cascading part of CSS)
See https://stackoverflow.com/a/964343/4206206
Related
I've been working hard to achieve 100/100 on Google Pagespeed (https://developers.google.com/speed/pagespeed/insights/) but I keep getting hungup when trying to use Javascript to download CDN based files. I get 'CAUTION: Provisional headers are shown.' and I assume it's blocking this kind of call for security reasons but I'm stuck.
I can call script files asycn like this, which Google likes:
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" async></script>
But what am I to do about the CSS files? If I call it the normal way:
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
Google complains and says I have a 'blocking CSS resources'.
Here's a copy of the code I've been trying to use so far:
var headID = document.getElementsByTagName("head")[0];
var cssNode = document.createElement('link');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.href = '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css';
headID.appendChild(cssNode);
Anyone have any suggestions?
Here is the code I ended up creating to handle loading both css and js files async at the same time. Just put this at the bottom of your HTML before you closing tag and edit the loadjscssfile() calls as necessary.
<script>
/* Beginning of async download code. */
window.onload = function(){
function loadjscssfile(filename, filetype) {
if(filetype == "js") {
var cssNode = document.createElement('script');
cssNode.setAttribute("type", "text/javascript");
cssNode.setAttribute("src", filename);
} else if(filetype == "css") {
var cssNode = document.createElement("link");
cssNode.setAttribute("rel", "stylesheet");
cssNode.setAttribute("type", "text/css");
cssNode.setAttribute("href", filename);
}
if(typeof cssNode != "undefined")
document.getElementsByTagName("head")[0].appendChild(cssNode);
}
loadjscssfile("//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css", "css");
loadjscssfile("//fonts.googleapis.com/css?family=Open+Sans:300&subset=latin,cyrillic-ext,latin-ext,cyrillic,greek-ext,greek,vietnamese", "css");
loadjscssfile("/css/style.css", "css");
loadjscssfile("//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js", "js");
loadjscssfile("//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js", "js");
};
/* End of async download code. */
</script>
Google provides a good explanation of this here:
https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery
It seems like they want you to inline CSS that is crucial to the page's initial display. Then load secondary CSS after. Since the bootstrap CSS is one large mix, I think it'll be non-trivial to separate crucial/non-crucial for your page.
Perhaps you can inline some duplicate CSS that exists in bootstrap.css
I'd suggest you to inline the styles for the critical path (above the fold):
https://github.com/addyosmani/above-the-fold-css-tools
https://github.com/addyosmani/critical
Then load the other css async:
https://github.com/filamentgroup/loadCSS/
I'm new to Javascript (but not HTML or CSS) and am trying to use this script by Lalit Patel to detect whether a font is installed on the user's system, and if not, to serve a modified style sheet. I've been successful in getting the first part to work: I uploaded the fontdetect.js file, called it in my header, then pasted this before the end of my body tag:
<script type="text/javascript">
window.onload = function() {
var detective = new Detector();
alert(detective.detect('Courier'));
};
</script>
(With Courier used as an example.) This causes an alert to pop up on page load telling me whether a font is installed, and works beautifully. But I don't know how to get the script to, instead of triggering an alert, grab a different stylesheet. This seems like basic stuff but I just can't find the specifics anywhere, even though I've been plowing through Javascript tutorials. Any guidance would be greatly appreciated!
If any more specifics are needed: If a user doesn't have the custom font installed or has custom fonts turned off entirely, I'd like to, using CSS change the size/spacing properties of the text so that the fallback font is able to fit in the same space.
var detective = new Detector();
if (!detective.detect('Courier')){
var s = document.createElement('link');
s.rel = 'stylesheet';
s.type = 'text/css';
s.media = 'all';
s.href = '/link/to/alternative/stylesheet.css';
document.getElementsByTagName('head')[0].appendChild(s);
}
Guessing something like that. if .detect() fails, it will dynamically create and insert a stylesheet in to the page. If you encounter problems, you can also use .setAttribute() off of the s element.
You can use JS to add a stylesheet to the website:
var detective = new Detector();
if (!detective.detect('Courier')){
document.createStyleSheet('location/stylesheet.css');
}
else
{
document.createStyleSheet('location/otherstylesheet.css');
}
So you could do a check to see if the Dectector returns true, if not load one style, if it does then load the other.
After trying all the methods presented, this is the one that worked for me (from this answer, but it's really a mix of the two answers presented here). It should be noted that this works in IE8, unlike most of the other methods (sadly I do need IE8 compatibility).
<script type="text/javascript">
window.onload = function() {
var detective = new Detector();
if (!detective.detect('Meat')){
var url = 'link/to/style.css'
if(document.createStyleSheet) {
try { document.createStyleSheet(url); } catch (e) { }
}
else {
var css;
css = document.createElement('link');
css.rel = 'stylesheet';
css.type = 'text/css';
css.media = "all";
css.href = url;
document.getElementsByTagName("head")[0].appendChild(css);
}
}
};
</script>
This detected that my browser wasn't accepting embedded fonts ("Meat" being one of the fonts I embedded) and served up the alternate CSS (although with a slight delay/flash of unstyled text, maybe because it's at the bottom of the page?) Anyhow, thanks again for all the help!
I want to dynamically insert some HTML content and some CSS urls through JS.
I have 3+ CSS files. I want them to be downloaded before my content is inserted on the page.
Is there a way to find out whether the above-mentioned files have been downloaded?
This is how it should work:
Download css files;
Show HTML after all the css files have been downloaded;
Start loading JS files after inserting the HTML;
Trigger callback after all the JS files have been loaded;
You could use YepNope.js, YepNope allows you to build asynchronous conditional tests to see whether resources have loaded. Once your tests have passed you can tell it to inject new CSS or JS files.
Example below has been taken from the YepNope.js site.
yepnope.injectCss( stylesheetSource [, callback ] [, elemAttributes ] [, timeout ]);
// Example
yepnope.injectCss("print.css", function () {
console.log("css injected!");
}, {
media: "print"
}, 5000);
You can even make YepNope load the initial CSS files first and then once they have completed loading YepNope can trigger a callback to do additional tasks, such as loading more JS or CSS files.
Source: https://stackoverflow.com/a/3794242/1292652
Retreiving CSS text using AJAX
Instead of using messy workarounds to determine of the CSS has loaded, you can use AJAX function to create a dynamic CSS URL and fetch the it as plain text.
Inserting the CSS
After fetching the raw text, you can use this function to insert the CSS into a style tag and add a callback:
function loadCss(cssText, callback) {
var style = document.createElement('style');
style.type='text/css';
if(callBack != undefined){
style.onload = function() {
callback();
};
}
style.innerHTML = cssText;
head.appendChild(style);
}
Using it
And now you can use this as:
loadCss(ajaxResponseText, function(){
console.log("CSS loaded, you can show the dialog now :)");
})
Allowing cross-domain AJAX
In your comment, you mentioned you had to load jQuery and jQueryUI which I'm guessing wil de on a different domain.
To get around the AJAX cross-domain restriction, check out this link or this one or this library
<html>
<head>
<!--
Put your styles here. Make sure the *last* CSS file has the following:
body { display: block !important }
This will allow the stylesheets to load while the body is hidden.
When the last stylesheet is loaded, the body will be visible.
-->
</head>
<body style="display: none">
<!-- Lots of HTML here -->
<!--
Put your script tags here.
In the first script, I recommend binding to the window.load event...
which will be fired once all your scripts are done loading.
-->
</body>
</html>
I think this is somewhat along the lines of what you wanted:
<html>
<head>
<!-- CSS Stuff goes here -->
<!-- JS Stuff come right after -->
</head>
<body>
<!-- HTML Stuff comes withing Body -->
</body>
</html>
This will cause:-
All the CSS files to download in parallel;
Then the HTML stuff gets parsed and displayed;
The browser gets all the JS;
The JS is tun and it does whatever inserting it wants;
Your question is a bit confusing, can you clarify it? I didn't understand why you'd require to have such an order, can you give the big picture? JS is meant to be a fire-and-forget language, it will be awkard to see if everything's downloaded. Did this make sense to you and/or help you?
I know it is not a pretty solution, but you can fetch the CSS files using AJAX and add their content to a <style>, instead of inserting a <link> to the DOM.
Using AJAX, you can know for sure when the CSS is completely downloaded and add the whole thing into the page under your terms.
Source: https://stackoverflow.com/a/8122005/1292652
I don't recommend this for the same reason why you shouldn't use a while loop to implement sleep(), but if you must, you can try it.
In the linked answer, a reference style was added. For example: #ensure-cssload-8473649 { display: none }. But since you're downloading files not in your control, you'll have to select a few styles from the sheet for detection.
The cssLoad() function is:
var onCssLoad = function (options, callback) {
var body = $("body");
var div = document.createElement(constants.TAG_DIV);
for (var key in options) {
if (options.hasOwnProperty(key)) {
if (key.toLowerCase() === "css") {
continue;
}
div[key] = options[key];
}
}
var css = options.css;
if (css) {
body.appendChild(div);
var handle = -1;
handle = window.setInterval(function () {
var match = true;
for (var key in css) {
if (css.hasOwnProperty(key)) {
match = match && utils.getStyle(div, key) === css[key];
}
}
if (match === true) {
window.clearTimeout(handle);
body.removeChild(div);
callback();
}
}, 100);
}
}
You can use it as:
onCssLoad({
"id": <insert element CSS applies to>,
css: <insert sample CSS styles>
}, function () {
console.log("CSS loaded, you can show the dialog now :)");
});
Why don't you add an element on page and check some style that it should have with some js. If it has that style then that stylesheet is probably load.
Like this:
if (document.getElementById("csspage-3-box").style.color === "#somethingUnique") {
//it is loaded
}
You could append a few hidden divs with IDs unique to each style sheet. If they have any styles at all then you know that the sheet you want is loaded. This operation is cheap. It does add some non-semantic div elements though. That being said, I feel like everyone has at least one non-semantic element in their DOM.
Just a suggestion, but 3 css files isn't that many. Other easy solutions include the following:
A) You could just cat and minify them and deliver them all at once.
B) Throw them onto a CDN (like aws s3 + cloudfront), which is super cheap and they will get loaded in parallel.
C) Just load them in as normal. You could also put them on a sub domain.
Now that aside if I were you I'd divide my CSS down into a bunch of files. 3 is too few files. I'd separate out grid and every element type. Then re-assemble them on a per page basis (or page group). This allows you to include each individual piece as you need.
After all that it is fairly easily to append a link tag (as long as you can easily get a path to it). I recommend using the link instead of the style tag because if you do go the CDN route or subdomain route you will have issues with cross-domain issues if trying to grab the content of the css file with some xhr.
In building the apps that our team develops there can be many CSS & Script files and the head of your HTML can end up looking rather cumbersome. I built a little script that will load all of your files by passing them to the method as an Array. However, I have the loadCSS() in its own script file and I just invoke and pass in the Array in via a script tag in the HTML. Code is in monolithic format to make it easier to view.
window.onload = function() {//Use $(document).ready() if using jQuery
var cssArray = ["Style01.css", "Style02.css", "Style03.css"];
loadCSS(cssArray, function () {
alert("Style sheets have been loaded.");
});
//Note: You can do a similar process for the JS files.
//Load HTML when CSS is finished - Shown below
loadHTML();
}
function loadCSS(array, callback) {
var cssArray = array;
for (var i = 0; i < cssArray.length; i++)
{
document.write("<link rel='stylesheet' type='text/css' href='styles/" + cssArray[i] + "' />");
//console.log(cssArray[i] + " style sheet has been loaded.");
//Detects when for loop is finished evaluating the Array
if (i == cssArray.length - 1) {
return callback();
}
}
//loadHTML() can also be invoked here to ensure CSS files have been loaded.
}
If you are attempting to build out some HTML dynamically then you could try something like this after the CSS files are loaded.
function loadHTML() {
//Create Main Table
var mainTable = document.createElement("table");
mainTable.id = "mainTable";
mainTable.cellPadding = 0;
mainTable.cellSpacing = 0;
mainTable.border = 0;
//Create Body
var mainBody = document.createElement("tbody");
//Create Table Row
var mainTR = document.createElement("tr");
mainTR.style.height = "50px";
mainTR.className = ""; //Insert class from one of the style sheets
//Create Main Cell
var mainTD = document.createElement("td");
mainTD.id = "mainTD";
//mainTD.style.width = "";
mainTD.style.textAlign = "left";
mainTD.style.padding = "5px 10px 5px 10px";
mainTD.className = ""; //Insert class from one of the style sheets
mainTD.innerHTML = "Test Text";
mainTR.appendChild(mainTD);
mainBody.appendChild(mainTR);
mainTable.appendChild(mainBody);
document.body.appendChild(mainTable);
}
If you have any questions please feel free to ask. Although there are already some good examples posted, hopefully this can help.
what about :
$(document).ready(function() {
$("body").hide();
});
then, in the downloaded css files :
body { diaplay:block; }
Use loadCSS to load your CSS. and inside onload method put your code you want to execute after all css load.
var counter = 0;
function onload(){
counter--;
setTimeout(function(){ // insuring if loaded immediately
if(counter == 0){
// your code here //******** CODEREPLACE ************/
alert('all css files loaded!');
}
});
}
function loadCSS(href){
counter++;
l = document.createElement('link');
l.href = href;
l.onreadystatechange = function () { // For IE
if (this.readyState == 'loaded'){
onload.call( this );
}
};
l.rel = 'stylesheet';
l.type='text/css';
l.onload = onload;
document.getElementsByTagName('head')[0].appendChild(l);
}
loadCSS('http://www.google.co.in/search?q=load+css+files+dynamically&aq=f&oq=load+css+files+dynamically&sugexp=chrome,mod=1&sourceid=chrome&ie=UTF-8');
ive installed typekit on my site, the usual two lines of js just after the opening head tag but its extremely slow / unresponsive to load in the fonts, this is completly remedied by refreshing the page, after that the typekit font load in perfectly and really quickly. But from a users point of view they will never know to do that, so they will be served the default fonts.
I have the typekit js as the very first thing under the opening head tag before the metatags and before loading in jquery, jquery-ui and other scripts.
Has any one else had trouble with this ?
what seemed to work for me was to load the script in an asynchronous pattern - as specified on the typekit blog, ive copied it in bellow
Standard asynchronous pattern
This first pattern is the most basic. It’s based on patterns written about by web performance experts like Steve Souders and used in other JavaScript embed codes like Google Analytics.
<script type="text/javascript">
TypekitConfig = {
kitId: 'abc1def'
};
(function() {
var tk = document.createElement('script');
tk.src = '//use.typekit.com/' + TypekitConfig.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (rs && rs != 'complete' && rs != 'loaded') return;
try { Typekit.load(TypekitConfig); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();
</script>
This pattern uses a single inline tag to dynamically add a new script element to the page, which loads the kit without blocking further rendering. An event listener is attached that calls Typekit.load() once the script has finished loading.
How to use it:
Place this snippet at the top of the so the download starts as soon as possible.
Edit the highlighted TypekitConfig object and replace the default with your own Kit ID.
You can add JavaScript font event callbacks to the TypekitConfig object.
Advantages:
Loads the kit asynchronously (doesn’t block further page rendering while it loads).
Disadvantages:
Adds more bytes to your html page than the standard Typekit embed code.
Causes an initial FOUT in all browsers that can’t be controlled or hidden with font events.
I'm looking for a bookmarklet to disable the tinymce visual editor. This is to say, some code that could be pasted into the address bar to disable the editor (and also bookmarked).
Anyone have any ideas?
The page I want to use it on is using an older version of TinyMce, I think the same version that is used on this page: http://www.imathas.com/editordemo/demo.html
Just to reiterate, I want to remove the TinyMce editor and leave the textarea.
If you would like to see the functionality I am talking about, you could also visit this example page: http://www.matracas.org/sentido/tinymce/examples/full.html and click on the enable / disable buttons below the editor.
The problem here is that the syntax relies on knowing what editor id to put into the .get() function.
tinyMCE.get('elm1').hide();
tinyMCE.get('elm1').show();
The bookmarklet would ideally just use tinMCE's show / hide functionality, but it would work for all editors on a page.
Here you go!
javascript:(function(){var arr=Object.keys(tinyMCE.editors);for(var i=0;i<arr.length;i++){try{tinyMCE.editors[arr[i]].remove();}catch(e){}}})()
More visibly pleasing, but same code:
javascript:
(function(){
var arr=Object.keys(tinyMCE.editors);
for(var i=0;i<arr.length;i++){
try{
tinyMCE.editors[arr[i]].remove();
}
catch(e){
}
}
}
)()
I start all my bookmarklets with jQuery, although this may work better as a greasemonkey script depending on what you're trying to do.
javascript:
function loadScript(url, callback){
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = url;
var done = false;
script.onload = script.onreadystatechange = function() {
if( !done && ( !this.readyState
|| this.readyState == "loaded"
|| this.readyState == "complete") )
{
done = true;
callback();
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
head.appendChild(script);
}
loadScript("http://code.jquery.com/jquery-latest.js", function(){
jQuery('.mceEditor').remove(); }
I have added a TinyMCE remover to my bookmarklet collection:
http://richardbronosky.github.com/Perfect-Bookmarklets/tinymce.html
It has one major advantage over the others I have seen. It restores the content of the textarea back to what was in the source. I don't know if others have experienced this, but we have a web admin to our CMS and TinyMCE, when removed leaves the code altered. I have resolved this.
Here is the code:
for(var i=0;i<tinymce.editors.length;i++){
var tmpId=tinymce.editors[i].id;
var tmpVal=document.getElementById(tmpId).value;
tinyMCE.execCommand("mceRemoveControl",true,tmpId);
document.getElementById(tmpId).value=tmpVal
}
Also on github:
https://github.com/RichardBronosky/Perfect-Bookmarklets/blob/master/tinymce.html