In order to construct the render-tree, the browser requires both DOM and CSSOM. CSSOM can only be constructed, once the CSS is downloaded. In essence, once the CSS is downloaded the page should be rendered alright. But, why do we see Flash Of Unstyled Content(FOUC) on the page? In what time window does the browser show unstyled content?
Please help me understand this.
Ref:
https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css
I still don’t agree with the accepted answer, because according to the critical rendering path nothing could be painted on a screen under normal circumstances until the render tree (DOM + CSSOM) is build.
I find that this Google article is somewhat confusing at the first glance but it becomes less contradictory if we take a look carefully at the following statement:
“What would happen if we try to render a typical page without blocking rendering on CSS?”. (Then NY Times FOUC as example of behaviour without blocking rendering follows.)
The thing is historically FOUC happened for different reasons in different browsers versions and on different circumstances.
For example according to this ancient article we could encounter FOUC in web kit if some JS attempted to access properties that have layout/style information.
Web Kit has the opposite behavior and will continue parsing a page
even after a style sheet directive has been encountered so that style
sheet and script loads can be parallelized. That way everything can be
ready for display much earlier.
The problem with this behavior is what to do when a script attempts to
access a property that involves having accurate layout/style
information to answer. Shipping Safari’s current behavior when this
happens is as follows: it will go ahead and lay out what it’s got even
though it doesn’t have the style sheet yet. It will also display it.
This means you see FOUC whenever a script tries to access properties
like scrollHeight or offsetWidth before the style sheet has loaded.
Therefore when we say “FOUC happens” there should be explications on
what circumstances and in what browser it happens, because it doesn’t
“just” happens everywhere.
The basic reason for FOUC is -> new/different styles are getting applied after elements were already painted on screen.
Now comes the question -> can FOUC happens when page is loading and page markup itself includes <link> tag for external css, at high level it appears this should not happen as css is render blocking and there should be no case where any element can get rendered without its computed styles, but it(FOUC) happens on page load in certain conditions.
Main reason for that is dom tree construction is incremental i.e. without having the full html markup browser can render partial html whatever is downloaded till the given point of time.
To understand that lets take example of following html -
<!DOCTYPE html>
<html lang="en">
<body>
<100 html tags block 1 />
<link href="css1" />
<100 html tags block 2 />
<link href="css2" />
<100 html tags block 3 />
<link href="css3" />
</body>
</html>
First 100 tags are converted to dom and with help of existing cssom(which was construed from user agent stylesheets) forms render tree, which will be painted and will be visible to user.
After that parsing will be blocked till css1 is downloaded and new cssom is created with useragent+css1 styles.
And with new render tree(formed via old dom + new cssom) html block 1 will be updated(FOUC)
Then html block 2 is similarly processed as it gets downloaded after that.
Now same things as step 3 is repeated with block 2 and block 3
And same goes on till the end of document
Credits - https://medium.com/jspoint/how-the-browser-renders-a-web-page-dom-cssom-and-rendering-df10531c9969
This should help.
DOM is constructed
If we are still waiting for the CSSOM to be constructed, then we see FOUC
CSSOM is constructed
DOM and CSSOM are coalesced into the Render Tree which renders the DOM with CSS (styled content)
So the browser shows FOUC when waiting for CSS. Once the CSS is loaded, the DOM and CSSOM are merged into one tree, called the Render Tree and this is styled content.
The very fact that HTML is rendered unstyled is clear evidence that the HTML can render in the browser separately from the render tree, thus causing FOUC.
According to the Google article, the NY times site shows FOUC until the CSSOM is constructed and then the render tree is rendered. This demonstrates that rendering the render tree is different from rendering the DOM tree. The DOM tree is rendered, but unloaded CSS blocks the render tree from being rendered (note the difference). This is why the FOUC shows before the CSS is unblocked and the render tree shows.
In my opinion, this is the most comprehensive talk about this subject out there, from David Baron, Chief Engineer at Mozilla: https://vimeo.com/103108124
Related
There is very old thread where people state that you should never include CSS in body, however MDN states that is is allowed. So is it considered good or bad practice to include CSS in the middle of the page?
For example, let's take a structure like this:
<html>
<head>
<link href="global.css" rel="stylesheet">
</head>
<body>
<h1>Some title</h1>
<p>Some content</p>
<img src="some-image.jpg" />
<link href="specific-component.css" rel="stylesheet">
<div>
Specific component that requires the style
</div>
<p>Other content</p>
</body>
</html>
What are disadvantages of including specific-component-style.css mid page comparing to including it to head section?
How page will be rendered with it? Will it be:
Start loading global.css, some-image.jpg, specific-component.css (in this order).
After global.css is loaded start rendering page until specific-component.css <link> element.
Finish loading specific-component.css
Render the rest of the page.
Or will it be:
Wait for both global.css and specific-component.css finish loading and only then start rendering the page.
What if there are 20 images before specific-component.css, will browsers prioritize CSS file or not?
There are two major disadvantages:
you lose maintainability of code
if that CSS affects any element before it, you might experience FOUC.
Theoretically, there's also a minor performance loss, but it's negligible: rendering is paused when a new stylesheet resource is met. A clear difference should be made between "render blocking" and script execution or DOM building blocking. The browser will continue to do whatever else it can and will block any script requesting repaint(), until the resource resolves, at which point, CSSOM is rebuilt, all existing DOM elements are checked against the new CSSOM and all pause scripts are continued.
If your <style> refers to an exception only met in that particular view/component/page, it makes sense to add it there, before the element affected by the rules. But if you make a habbit out of it, sooner or later you'll wish you had all your styles in one place; your project will become harder to maintain.
On general principles, you should not do it.
It also greatly depends on the scale of your project. On small projects it's irrelevant. In huge projects, involving large teams, it's completely forbidden, as nobody will remember your exception. So it's sometimes valid ground for losing your position or at least your standing. ツ
Last, but not least, especially if you're not regarded as an expert, it's something that can be interpreted against your interest by people assessing your work (as in, people knowing less than you might see it as a sign of you not doing your job properly).
With that being said, the browser doesn't care. If it validates, it's applied and rendered.
Another minor technical issue (in the case of <style> tags, not <link>s) is that inline CSS is never cached. It gets loaded each time, together with the markup, while regular CSS in loaded stylesheets does not eat up bandwidth anymore. But, again, if we're talking a few lines of code, it's irrelevant.
Safari and Edge will render content before the <link>, then continue rendering once the linked CSS has fetched.
Firefox will render content before and after the <link>, then update the page once the linked CSS has fetched. You can make it behave more like Safari/Edge using <link … ><script> </script> (the space between the script tags is necessary.
Chrome will block rendering as soon as it discovers the <link>, meaning it may also block content before the link element. The plan is to align with Safari & Edge https://bugs.chromium.org/p/chromium/issues/detail?id=481122.
If you find that your CSS is fetching too late, you can use <link rel="preload" as="style" href="…"> to load it sooner.
If you give img{width:100px;} in global.css And img{width:150px;} in specific-component.css, In this case work specific-component.css because he render after global.css and it overwrite of global.css.
If you give img{width:100px !important;} in global.css And img{width:150px;} in specific-component.css, In this case work global.css because we set img width important in global.css and it don't overwrite by specific-component.css.
And If you give important in both, then work specific-component.css.
And css engine always compile first specific-component.css.(look in inspect element)
In my opinion this depends on how you work. If you load a complete page (whether it's manual HTML, or generated through CMS like Wordpress) - it is recommended that the style will load before the body, to allow the rendering to be smoother and faster.
HOWEVER, since the use of component libraries like React and Vue (for example) is becoming more and more popular, it's acceptable to connect the CSS to the component, and not load component-sepcific CSS with the general style (this should generally allow faster loading time, especially in one page sites that have dnamically changing elements.
As per rendering order, by default, CSS/JS is the highest priority to load, and after that you get media elements (images, videos, audio etc.). Check this link or this to read more about priorities in the browser.
In Google Chrome’s Developer Tools, I see a #shadow-root right under <html lang="en"> tag. what does it do and what is it used for? I don’t see it in Firefox nor in IE; only in Chrome, is this a special feature?
If I open it, it shows <head> and <body> and a link beside named reveal, by clicking, it points to the <head> and <body>, nothing else.
This is a special indicator that a Shadow DOM exists. These have existed for years, but developers have never been given APIs into it until recently. Chrome has had this functionality for a while, other browsers are still catching up. It can be toggled in the DevTools Settings under the "Elements" section. Uncheck the "Show User Agent Shadow DOM". This will at least hide away any Shadow DOMs created internally (like select elements.) I am unsure right away if it affects user-created ones, such as custom elements.
These come up in things like iframes as well, where you have a separate DOM tree nested inside of another.
The Shadow DOM is simply saying that some part of the page, has its own DOM within it. Styles and scripting can be scoped within that element so what runs in it only executes in that boundary.
This is one of the primary pieces needed for Web Components to work. Which is a new technology allowing developers to build their own encapsulated components that developers can use just like any other HTML element.
As an example of Shadow DOM, when you have a <video> tag on a web page, its shown as just one tag in the main DOM, but if you enable Shadow DOM, you will be able to see the video player's HTML(player DOM).
This is explained aptly in this article, http://webcomponents.org/articles/introduction-to-shadow-dom/
In the case of web components, there is a fundamental problem that makes widgets built out of HTML and JavaScript hard to use.
Problem: The DOM tree inside a widget isn’t encapsulated from the rest of the page. This lack of encapsulation means your document stylesheet might accidentally apply to parts inside the widget; your JavaScript might accidentally modify parts inside the widget; your IDs might overlap with IDs inside the widget and so on.
Shadow DOM addresses the DOM tree encapsulation problem.
For example, if you had markup like this:
<button>Hello, world!</button>
<script>
var host = document.querySelector('button');
var root = host.createShadowRoot();
root.textContent = 'こんにちは、影の世界!';
</script>
then instead of
Hello, world!
your page looks like
こんにちは、影の世界!
Not only that, if JavaScript on the page asks what the button’s textContent is, it isn’t going to get “こんにちは、影の世界!”, but “Hello, world!” because the DOM subtree under the shadow root is encapsulated.
NOTE: I have picked up above content from https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/ as it helped me understand shadow DOM a little better than answers already here. I have added relevant content here so that it helps others but do take a look at the link for detailed discussion on same.
Google suggests to use very important CSS inline in head and other CSS inside <noscript><link rel="stylesheet" href="small.css"></noscript>.
This raises few questions in my mind:
How to prioritize CSS in two files. Everything for that page looks important. Display, font etc. If I move it to bottom then how it helps page render. Wont it cause repaint, etc?
Is that CSS is required after Document ready event? Got it from here.
How 'CSS can' go inside <noscript></noscript>, which is for script? Will it work when JavaScript is enabled? Is it browsers compatible?
Reference
Based on my reading of the link given in the question:
Choose which CSS declarations are inlined based on eliminating the Flash-of-Unstyled-Content effect. So, ensure that all page elements are the correct size and colour. (Of course, this will be impossible if you use web-fonts.)
Since the CSS which is not inlined is deferrable, you can load it whenever makes sense. Loading it on DOMContentReady, in my opinion, goes against the point of this optimisation: launching new HTTP requests before the document is completely loaded will potentially slow the rest of the page load. Also, see my next point:
The example shows the CSS in a noscript tag as a fallback. Below the example, the page states
The original small.css is loaded after onload of the page.
i.e. using javascript.
If I could add my own personal opinion to this piece:
this optimisation seems especially harmful to code readability: style sheets don't belong in noscript tags and, as pointed out in the comments, it doesn't pass validation.
It will break any potential future enhancements to HTTP (or other protocol) requests, since the network transaction is hard-coded through javascript.
Finally, under what circumstances would you get a performance gain? Perhaps if your page loads a lot of initially-hidden content; however I would hope that the browser itself is able to optimise the page load better than this hack can.
Take this with a grain of salt, however. I would hesitate to say that Google doesn't know what they're doing.
Edit: note on flash-of-unstyled-content (abbreviated FOUC)
Say you a block of text spanning multiple lines, and includes some text with custom styling, say <span class="my-class">. Now, say that your CSS will set .my-class { font-weight:bold }. If that CSS is not part of the inline style sheet, .my-class will suddenly become bold after the deferred loading has finished. The text block may reflow, and might also change size if it requires an extra line.
So, rather than a flash of totally-unstyled content, you have a flash of partly-styled content.
For this reason you should be careful when considering what CSS is deferred. A safe approach would be to only defer CSS which is used to display content which is itself deferred, for example hidden elements which are displayed after user interaction.
I would like to know how the browser handles CSS rules that come after most (if not all) of the HTML. Will it have to reparse the whole page due to the new rules or does it use some other kind of technique to handle this type of situation? Thanks.
There are many cases when a repaint must occur, and in many occurences in a page lifetime the DOM is changed.
But once the page is parsed, there is no reason to parse it again, all changes are made on the in memory DOM.
This being said, you should put the CSS links in the HEAD because
it lets the browser start their download faster
it complies with HTML4 norm ("it may only appear in the HEAD section of a document")
it lets the browser start the rendering sooner
it lets your colleagues and your future yourself not be surprised when maintaining the code
Relayout and repaint, perhaps. (That is, if it has already started rendering it and the styles loaded require different display.)
Reparse, no. Style sheets are purely presentational; they do not affect the parsing.
Assuming that the browser has already started rendering the page when it sees the additional CSS (there are quite a few browser-specific triggers for this behavior) and assuming that the new rules result in CSS property changes for at least one element, the browser will simply mark that element as one that needs redrawing.
This will result in any visible changes to the page being shown the next time the browser repaints part of its window.
It's important to keep in mind that modern browsers do all of this asynchronously and schedule events like applying new CSS, recalculating layout and painting to the screen mostly (but not totally) independently of each other.
Let's say we have an HTML page with a single stylesheet <link>. How does the browser take the rules in this stylesheet and apply it to the HTML? I'm not asking about how to make it faster, I want to know how the rendering itself is handled.
Does it apply each rule one-by-one as it parses the stylesheet and render the result progressively? Or, are the CSS file's contents completely downloaded, then fully evaluated, and then applied to the HTML all at once? Or something else?
I ask this after posting an answer earlier on a question about CSS rule order affecting rendering speed, with the assumption that the styles were rendered as the stylesheet loaded, so the first rules would be applied before the last ones, and not all at once. I'm not sure where I picked up the idea, it's just something I have always thought.
I tried a demo on my server that looked like this:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link rel="stylesheet" href="test.css" />
</head>
<body></body>
</html>
test.css contents:
html { background:green }
/* thousands of lines of irrelevant CSS to make the download slow */
html { background:red }
Testing in Firefox 5, I expected to see green at first, then turn to red. It didn't happen. I tried with two separate stylesheets with conflicting rules and got the same results. After many combinations, the only way I got it to work was an inline <style> block in the <head>, with the conflicting rules coming from a <link> in the <body> (the body itself was completely empty except for the link tag). Even using an inline style attribute on the <html> tag, and then loading this stylesheet did not create the flicker that I expected.
Are repaints affected in any way by the CSS, or is the final output applied all at once after the entire stylesheet is downloaded and it's rules computed to what the final output should be? Do CSS files download in paralel with the HTML itself or block it (like script tags do)? How does this actually work?
I am not looking for optimization tips, I'm looking for authoritative references on the subject, so that I can cite them in the future. It's been very difficult to search for this information without turning up tons of unrelated material. Summary:
Is all CSS content downloaded before any of it is applied? (reference please)
How is this affected by things like #import, multiple <link>s, inline style attributes, <style> blocks in the head, and different rendering engines?
Does the download of CSS content block the downloading of the HTML document itself?
How does the browser take the rules in this stylesheet and apply it to the HTML?
Typically this is done in a streaming fashion. The browser reads the HTML tags as a stream, and applies what rules it can to the elements it has seen so far. (Obviously this is a simplification.)
An interesting related Q&A: Use CSS selectors to collect HTML elements from a streaming parser (e.g. SAX stream) (a diversion while I search for the article I have in mind).
Ah, here it is: Why we don't have a parent selector.
We often think of our pages as these full and complete documents full of elements and content. However, browsers are designed to handle documents like a stream. They begin to receive the document from the server and can render the document before it has completely downloaded. Each node is evaluated and rendered to the viewport as it is received.
Take a look at the body of an example document:
<body>
<div id="content">
<div class="module intro">
<p>Lorem Ipsum</p>
</div>
<div class="module">
<p>Lorem Ipsum</p>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum <span>Test</span></p>
</div>
</div>
</body>
The browser starts at the top and sees a body element. At this point,
it thinks it's empty. It hasn't evaluated anything else. The browser
will determine what the computed styles are and apply them to the
element. What is the font, the color, the line height? After it
figures this out, it paints it to the screen.
Next, it sees a div element with an ID of content. Again, at this
point, it thinks it's empty. It hasn't evaluated anything else. The
browser figures out the styles and then the div gets painted. The
browser will determine if it needs to repaint the body—did the element
get wider or taller? (I suspect there are other considerations but
width and height changes are the most common effects child elements
have on their parents.)
This process continues on until it reaches the end of the document.
CSS gets evaluated from right to left.
To determine whether a CSS rule applies to a particular element, it
starts from the right of the rule and works it's way left.
If you have a rule like body div#content p { color: #003366; } then
for every element—as it gets rendered to the page—it'll first ask if
it's a paragraph element. If it is, it'll work its way up the DOM and
ask if it's a div with an ID of content. If it finds what it's looking
for, it'll continue its way up the DOM until it reaches the body.
By working right to left, the browser can determine whether a rule
applies to this particular element that it is trying to paint to the
viewport much faster. To determine which rule is more or less
performant, you need to figure out how many nodes need to be evaluated
to determine whether a style can be applied to an element.
So why was the stylesheet content not applied progressively (green first, then red)?
I think the answer is that external stylesheets are parsed as they are downloaded, but not applied until the entire stylesheet has been parsed. Surely, in parsing a stylesheet, the browser optimizes away unnecessary and redundant CSS rules.
I don't have any proof to back that up right now, but that explanation sounds reasonable to me and agrees with what you're seeing, both with external and inline styles.
The first and most important thing to understand is that browsers cannot begin painting a page until all CSS is downloaded. (Keep in mind, the W3C spec says that CSS links are only allowed in the head, so when you start linking to stylesheets in the body tag as you did, different browsers will handle this situation differently.)
Now, a web page is read as a stream, and CSS rules are applied to HTML elements as they get fed into the page. To quote the Google article linked below:
As the browser parses HTML, it constructs an internal document tree representing all the elements to be displayed. It then matches elements to styles specified in various stylesheets, according to the standard CSS cascade, inheritance, and ordering rules.
So to now address your questions:
Does it apply each rule one-by-one as it parses the stylesheet and render the result progressively? Or, are the CSS file's contents completely downloaded, then fully evaluated, and then applied to the HTML all at once? Or something else?
Downloads all CSS, then begins painting the document from the top-down.
Testing in Firefox 5, I expected to see green at first, then turn to red. It didn't happen. I tried with two separate stylesheets with conflicting rules and got the same results.
This is because the CSS is all downloaded first, then when it encountered your element it only applied the red style, because of how the cascade works.
After many combinations, the only way I got it to work was an inline <style> block in the <head>, with the conflicting rules coming from a <link> in the <body>
While I cannot say exactly why this happened, I imagine the browser did not look for CSS in the body tag, began painting, encountered the body CSS, then repainted.
Are repaints affected in any way by the CSS?
I would honestly be more worried about JS caused repaints. But if you have a very large DOM, it makes sense to structure your CSS in such a way that you are not causing reflows due to odd positioning. #Matt gave you some good links covering that issue
Some good resources:
http://www.dayofjs.com/videos/22158462/web-browsers_alex-russel
Alex Russell goes into great detail about 36 minutes in about how webkit parses CSS, how reflows and repaints work, and what triggers them.
http://code.google.com/speed/page-speed/docs/rendering.html
This is a basic article on how to optimize CSS rendering
I am not sure about the marked answer. I doubt it's correctness.
As per this link from Google Developers the browser first downloads the HTML file and when it sees a CSS file linked to external resource it starts downloading the CSS file while it simultaneously creates the DOM structure for the given HTML file as CSS is not going to affect the DOM. Note that it doesn't apply any styles to the document when the browser is downloading the CSS file.
After downloading the CSS file (assume there is no script files) and if the DOM construction is complete, the browser starts mapping the CSS properties to those nodes in the DOM tree. After this it creates another tree called Render tree which builds all the objects which should be displayed, as rectangle boxes. Only after completing the render tree it starts painting on to the screen.
To summarize:
The browser downloads the CSS file completely.
The browser doesn't apply any styles to the page when it is downloading. Only after the donwload is complete it starts mapping the rules.
The rules are applied only during the render tree construction stage.
Downloading the CSS file doesn't block HTML download. You have to note that the browser
First downloads all the html files and then style and script files are downloaded.
You can use the chrome's Developer console to check these. Use the timeline tab to see all this.
A sample of the timeline image is shown here. The link i posted at the beginning of this answer explains everything.