I am building an AJAX-based website where all of website content is being loaded through AJAX.
Some pages have CSS that's being loaded along with content (code follows). Once the HTML and CSS is loaded I run a few scripts to change some image positions, alter width, and so on.
The problem is that sometimes my javascript gets executed before CSS rules get applied. For example: if my div width should be 200px according to the css, sometimes javascript reads it as 1000px, so I get wrong calculations.
My research has not yielded a cross-browser solution to detect not only loaded images but loaded CSS and everything else.
I use jQuery's AJAX function to get the desired HTML (this part is working fine). After I get the HTML I apply it with jQuery's html function.
Once that's done I use this code to load required css:
css = document.createElement('link');
css.rel = 'stylesheet';
css.type = 'text/css';
css.media = "all";
css.href = url;
document.getElementsByTagName("head")[0].appendChild(css);
I could use a timeout function, but it would just be blind guessing, and I want to make sure my script runs when it needs to run. Any sugguestions?
EDIT I have included this image to make explanation clearer
Never tried before, but what about Stylesheet load events? In case IE won't fired the onload event, and you need to support it, onreadystatechange should works.
I'm glad to see I'm not the only one who has this problem.
I have some JavaScript which needs to be run AFTER the CSS styles are applied to the DOM.
I think what ZER0 suggested is a good solution, but I could not use the OnLoad event on my CSS <link> tag because I load a single concatenated/minified JS file at the end of the document, while my concatenated/minified CSS is at the top of the document.
My solution:
Put the essential CSS styles that the JavaScript depends on directly on the DOM using <style> tags.
This way, the styles get applied immediately when the DOM gets loaded. By the time JS is running, the DOM has the essential styles applied.
I think that you are over-complicating the problem. If you set all of your CSS up to only react to a certain parent class--eg: if you dynamically load the about page--all the CSS should look like .about .example {} .about h2 {} etc. The same would go for the contact page .contact img {}
Now, unless your CSS file is absolutely massive, if you include the one file at the top, you can pretty much guarantee that the CSS will be applied.
Related
I'm trying to hide an HTML element using Google Tag Manager, but I am wondering which method is faster, JavaScript or CSS.
I always assumed that inserting CSS itself, will hide the HTML element faster than using JavaScript to insert some inline CSS. However, I tested both and it feels that JavaScript actually hides element faster. However, I don't have numbers that prove my point. What's the logic behind?
JavaScript:
<script>
document.querySelector(".hello-world").style.display = "none";
</script>
CSS:
<style>
.hello-world{
display: none;
}
</style>
CSS is by far the best way to apply styling to any element on page load. This is because CSS can be applied after the stylesheet loads, which is generally before the DOM has been rendered, so you don't get a flicker of content appearing and disappearing.
This is in contrast to JS, which has to wait until the DOM has loaded which means the element will be visible before it's suddenly hidden (excepting cached scripts etc). This issue is known as a 'Flash of Unstyled Content', or FOUC.
As a side note, CSS is hardware accelerated, so if you have any animation you'd like to show, it's also good practice to try and create it using only CSS/SVG instead of JS.
I'm looking for a way to add some inline css to the body tag and another div in the page as the page loads to override some styles listed in the stylesheet which cannot be changed. The script itself forces the page to centre align but any onload event waits until the page has finished loading (with a left alignment) before centring it. I need the script to add this css as the page loads so the front end view is seemless.
I came across the DOMNodeInstered event but open to any ideas. I'm deploying the script through a tag manager so can only fire the script either in the head or in the body.
Really appreciate any help anyone can give.
If you dont want your style to be overriden, make sure you're setting the style as close to the element as possible, which is inline. Also make sure to add !important to it.
For example:
document.querySelector("body").style.backgroundColor = "red";
I've ran into some weird cases of positioning problems when lazy loading CSS in Chrome, e.g. the positioning of some elements (absolute, relative and cascaded) is off by sometimes huge margin.
Basically what I'm doing is leaving out the standard loading of the stylesheet via an link-Tag and instead placing a placeholder span-Tag for the sake of having an easy way to retrieve the URL later on at the end of the body-Tag. After the DOM loaded fully, I replace the span-Tag with a generated link-Tag like this:
loadCSS: function()
{
var el = jQuery('.is_css');
if(!el.length) return;
// Build link element
var linkEl = jQuery('<link />').attr({
media: 'all',
type: 'text/css',
rel: 'stylesheet',
href: el.data('src')
});
el.replaceWith(linkEl);
}
I can verify that the CSS is fully loaded as most of the elements are looking exactly as if I embed the CSS directly in the head-Tag. My guess is that Chrome doesn't correctly calculate positions in some circumstances for absolute or relative positioned elements when the CSS is loaded after the DOM has been loaded.
I would like to provide you with HTML / CSS Snippets, unfortunately it's out of scope to isolate the falsely rendered Elements. So instead I'm asking if anybody encountered similar problems that can cause this behaviour. Maybe there are some general hints on how to fix such problems.
Kind regards
Sutuma,
The methodology you are trying could have strong performance impact.
As a principle CSS need to be loaded before html DOM is rendered to have an effect. My guess is your html is rendered before CSS get loaded.
Here are the option you may try:
1. Load all css in html header tag
2. Reload your html page one css is content is downloaded.
3. You can use html templating with (require js + require css plugin) for lazy loading.
require js ,
require-css plugin
I am using the Google Webfont Loader to get my webfonts loaded with a callback and it is working fine.
Although, when a couple of components: Google +1 button, Twitter Search Widget and the Add This button is loaded, they add a new stylesheet to the DOM and makes the browser render the site again. This is causing the font-face to disappear and then show for each new stylesheet added to the dom.
I could hide the font entirely until the components are loaded but they tend to be pretty slow so that would leave me with a pretty bad user experience. About 1 sec of a headline-less site.
Andy tips on how to force font-face to not redraw or how to block dynamically loaded CSS from within Google, Twitter and FBs embed scripts?
Update: Demo here http://kristoferforsell.com/dev/fontexample/
This is currently an inherent issue with browsers and the #font-face property. The blink occurs when the font is loaded and the page updates to reflect the font. If you wish to remove the "blink" entirely, the only sure fire way is to include the font as a data URI in the style sheet. Of course, using the standard "safe" fonts will also remove the blink.
Data URIs allow you to actually embed the code for the font in the stylesheet so there's no blink when the page refreshes to show the desired font. Using data URIs, will obviously increase the file size (kb) of any style sheet.
An online converter to get base64 code can be found here
Usage for #font-face would be like so.....
#font-face {
font-family: "My Font";
src: url("data:font/opentype;base64,[ the base64 code here ]");
}
Not sure if it would fix your issue but you could use css to set the visibility of the elements to hidden until the font is loaded. Google's API provides wf-loading and wf-active classes which are added to the body to address this issue.
I always set up a separate stylesheet just for the #font-face rule, and within that put in the following rules, where replace is the class of the element that's being replaced, for you that would just be the p tag.
.wf-loading .replace { visibility: hidden;}
Yours would be
.wf-loading p { visibility: hidden;}
Then as soon as the webfont is loaded, JS puts the wf-active class on the body, and your text shows up. Let me know how that goes and if you have any issues then just drop me a line. It might also be worth doing some searching for "flash of unstyled content" or "flash of unstyled text" as this is a well known and well documented bug.
I can suggest a simple and dirty trick I have used myself to solve issues like this. If you implement this, from the user's side the effect will be that the entire page will load at once (with the correct Web Fonts), but after a delay. Once loaded, nothing will flicker or change.
Wrap your entire page contents in a div and set its visibility to hidden. Then use js to turn on the visibility once the whole page (stylesheets and all) is loaded.
Here's the code:
<head>
<script>
function show()
{document.getElementById('wrapper').style.visibility='visible';}
</script>
</head>
<body onload="show()">
<div id="wrapper">
...your entire page contents...
</div>
</body>
The onload ensures that the visibility is switched on only after the entire body has loaded. Although I haven't used Web Fonts, I use this trick to fade in the entire contents of this website with no changing or updating afterwards. But yes, there will be a delay before the entire page comes into view.
EDIT: I added Google Web Fonts to the site I linked. Still works fine. No font-face flickering.
This is a shot in the dark, as I've not tested it:
Could you create another html page with only those social networking buttons, and then load that into an iframe? Then only set the src to the iframe once the document is fully loaded, so it doesn't hold anything up.
In html:
<iframe id="socialMedia"></iframe>
In script:
$(document).ready(function() {
$('#socialMedia').src = "http://mysite.com/mysocialmediastrip.html";
});
Where mysocialmediastrip.html contains all the social media buttons. Setting the src will cause that iframe to reload and pull in that content, but IIRC, the rest of the page will be left alone -- all of the button rendering will have been done in mysocialmediastrip.html, not in your main page.
I totally understand what you are saying about the delay process, waiting while window loads before you actually show your goods. Abhranil provided a good solution but you can take his solution further. You can use jQuery's ajax to load your specific page content that's using the special font type. Why? because ajax comes with a special function called beforeSend(). Within the beforeSend function(), you can load a very cool gift animation that will display on your screen, before your main content is ready to viewed.
Use that moment to show some creativity towards your audience, before the main event!
The best and most simple answer is adding font-display: block when specifying a font face
#font-face {
font-display: block; /* Fix flickering */
}
You should also preload the font in the html file
<head>
<link rel="preload" as="font" href="/path_to_your_font.ttf">
<-- repeat for all typeface -->
</head>
I'm learning Javascript and CSS and have run into an issue where my CSS styles aren't being applied to markup that I'm dynamically generated from XML and writing to document after the page has loaded. I can only assume that the styles aren't being applied because I'm modifying the document after it's already been loaded. Is this correct? If this isn't the case, do you have any ideas as to why the styles aren't being applied?
This javascript code...
$(function()
{
//Dynamically generate markup
strMarkup = GenerateMarkupFromXML();
//Display the dynamically generated markup
document.write(strMarkup);
});
dynamically generates this simple markup...
<div id="accordion"><h3>Title1</h3><h3>Title2</h3></div>
but these styles don't ever seem to be applied and the <h3> tags just get displayed with the default browser style...
h3
{
background-color:#ccc;
color:#003300;
font-size:1.1em;
}
I should also note that when I paste the dynamically generated markup directly into the body, the styles are applied correctly.
Thanks in advance for all your help!
Yes... the styles will be applied to any dynamically added markup.
The document.write() portion of your code may be causing problems here. In general, you should only use document.write() inline as the document is loaded and parsed. If you call it on DomReady as you seem to be doing it will overwrite your entire page, which I guess is what's causing the problem. I haven't tested though.
I'm not that familiar with jQuery, but instead of the document.write() line try doing something along the lines of (untested):
$('body').append('<div id="accordion"><h3>Title1/h3><h3>Title2</h3></div>');
Yes, css applied automatically. Your example don't work because document.write is evil )
It rewrites whole document with your custom styles, I suggest. If you want to use document.write call it in appropriate section of document, not in head. Example:
<head>
<style>
h3
{
background-color:#ccc;
color:#003300;
font-size:1.1em;
}
</style>
</head>
<body>
<script>
document.write('<div id="accordion"><h3>Title1</h3><h3>Title2</h3></div>');
</script>
</body>
Yes, CSS styles are applied to markup that is added after the page loads.
It could be that you aren't actually generating the same code that you think you are. Try selecting the generated code and doing "View Selection Source" in Firefox. This shows you the generated source (i.e. not just the static content that was served when the page was loaded).
Edit
I think there is a problem with using document.write() in the document ready function.. seems to be causing some kind of infinite loop (for me in Firefox, the browser keeps spinning the loading icon on the tab, even though the file is on my local machine). The $('body').append(strMarkup); solution posted by Andy works, though, as does $('body').html(strMarkup);;