I’m working on a project where we went from XHTML to HTML back to XHTML and there are some definite behavioral changes going back with regards to the page rendering before the CSS loads and scripts that read styles reading them before the CSS loads. Can anyone shed some light on why the following is happening and what can be done about it?
Basically, I have a page with the following structure:
<body>
<!-- Content from Source A -->
<link href="http://a.example.com/style.css" />
<header>...</header>
<!-- Content from Source B -->
<link href="http://b.example.com/style.css" />
<div>...</div>
<!-- Content from Source A -->
<footer>...</footer>
<script src="http://a.example.com/script.js">
/* e.g. */
alert($('header').offset().height);
</script>
</body>
When we were in HTML rendering mode, the page blocks rendering at expected points. When we hit the Source A CSS, rendering pauses (blank screen); when we hit the Source B CSS, rendering pauses (header is visible). When we hit the Source A JavaScript, rendering pauses (full page shown) and the script reads element styles from their rendered state. (In reality, of course, WebKit doesn’t stop parsing the DOM or executing JavaScript while the CSS loads, but it does halt execution at the first point where the script needs to read a style.)
When we are in XHTML mode, the page doesn’t halt rendering at all and will render the entire page completely unstyled. After that, it appears to process the scripts and stylesheets in the order loaded, or rather it executes the scripts in order but doesn’t wait for the stylesheet to load before executing a loaded script. This means that the page will render three times (unformatted, with one stylesheet, and with two stylesheets) and the script may infer completely inaccurate values for element sizes.
Can someone shed light on this? This is happening in all WebKit browsers I’ve tested, including Chrome 17, Mobile Safari 5, and Android Browser 2.1. Is there any way to ensure HTML render ordering without resorting to the text/html mime type?
WebKit uses libxml2 to handle XML, which sends the parsed XHTML back to WebCore and JavaScriptCore to do the CSS rendering and JavaScript execution.
Stylesheet and script tags link to what’s called an external entity in XML terminology. That means they are processed last. The XML spec says:
Since
standalone="yes"specifies that the XML document should be validated by a DTD, this triggers a different processing model.Link tags are handled differently than xml-stylesheet processing-instructions. The XML stylesheet spec says:
Try commenting out the script tags and converting the link tags xml-stylesheet instructions. Also, try adding standalone=”yes” to the XML declaration:
In addition, the use of special characters, entities, and XSLT can further complicate the picture, since the processing model differs between HTML and an XML dialect like XHTML:
References
libxml2 Paser Internals
blink-dev => Intent to Deprecate and Remove: XSLT
blink-dev => Security: libxml2 growBuffer integer overflow on 64-bit machines
blink-dev => Stack-buffer-overflow in xmlSerializeHexCharRef
Webkit Title Index