|
| 1 | +<html> |
| 2 | + <head> |
| 3 | + <title>HTML5 Parsing</title> |
| 4 | + <link rel="Stylesheet" href="StyleSheet" /> |
| 5 | + </head> |
| 6 | + <body> |
| 7 | + <h1>HTML5 Parsing |
| 8 | + </h1> |
| 9 | + <blockquote> |
| 10 | + <p> |
| 11 | + The html is parsed using a real <b>HTML5 tokenizer</b> (from the |
| 12 | + <a href="https://github.com/jstedfast/HtmlKit">HtmlKit</a> library) instead of a hand-rolled |
| 13 | + scanner, so the pages below - all of which are <i>intentionally malformed</i> - render |
| 14 | + correctly instead of breaking the layout. Every example shows the raw (broken) html |
| 15 | + source followed by the actual <b>live rendering</b> of that exact same markup. |
| 16 | + </p> |
| 17 | + <hr /> |
| 18 | + <h2>Optional / omitted end tags |
| 19 | + </h2> |
| 20 | + <p> |
| 21 | + Real world html is full of tags whose closing tag was never written. The parser now |
| 22 | + follows the <a href="https://html.spec.whatwg.org/dev/dom.html#concept-element-tag-omission"> |
| 23 | + HTML5 end-tag omission rules</a> and automatically closes them at the right |
| 24 | + place, instead of nesting everything into one deep, broken tree. |
| 25 | + </p> |
| 26 | + <div class="comment">Source:</div> |
| 27 | + <pre><p>First paragraph, never closed |
| 28 | +<p>Second paragraph, never closed |
| 29 | +<p>Third paragraph, never closed</pre> |
| 30 | + <div class="comment">Live result:</div> |
| 31 | + <div class="example"> |
| 32 | + <p>First paragraph, never closed |
| 33 | + <p>Second paragraph, never closed |
| 34 | + <p>Third paragraph, never closed |
| 35 | + </div> |
| 36 | + <hr /> |
| 37 | + <h2>Tables with missing <tr>/<td> end tags |
| 38 | + </h2> |
| 39 | + <p> |
| 40 | + The same omission rules apply to table rows and cells, so a table written without a |
| 41 | + single closing <code></tr></code> or <code></td></code> still comes out as |
| 42 | + a proper grid. |
| 43 | + </p> |
| 44 | + <div class="comment">Source:</div> |
| 45 | + <pre><table border="1" cellpadding="4"> |
| 46 | +<tr><td>A<td>B |
| 47 | +<tr><td>C<td>D |
| 48 | +</table></pre> |
| 49 | + <div class="comment">Live result:</div> |
| 50 | + <div class="example"> |
| 51 | + <table border="1" cellpadding="4"> |
| 52 | + <tr><td>A<td>B |
| 53 | + <tr><td>C<td>D |
| 54 | + </table> |
| 55 | + </div> |
| 56 | + <hr /> |
| 57 | + <h2>Anonymous table boxes |
| 58 | + </h2> |
| 59 | + <p> |
| 60 | + Per the <a href="https://www.w3.org/TR/CSS2/tables.html#anonymous-boxes">CSS 2.1 anonymous |
| 61 | + table object rules</a>, a stray <code><td></code> with no <code><tr></code> |
| 62 | + (or even no <code><table></code>) around it is automatically wrapped in the missing |
| 63 | + row/table boxes, rather than producing a broken or invisible layout. |
| 64 | + </p> |
| 65 | + <div class="comment">Source:</div> |
| 66 | + <pre><table border="1"><td>Anonymous row generated around me</td></table></pre> |
| 67 | + <div class="comment">Live result:</div> |
| 68 | + <div class="example"> |
| 69 | + <table border="1"><td>Anonymous row generated around me</td></table> |
| 70 | + </div> |
| 71 | + <hr /> |
| 72 | + <h2>Comments containing ">" |
| 73 | + </h2> |
| 74 | + <p> |
| 75 | + A real tokenizer knows where a comment actually ends, so a stray <code>></code> character |
| 76 | + inside a comment no longer truncates it early or corrupts the rest of the page. |
| 77 | + </p> |
| 78 | + <div class="comment">Source:</div> |
| 79 | + <pre><!-- a comment that contains a > character right here --> |
| 80 | +<p>This paragraph renders normally right after it.</p></pre> |
| 81 | + <div class="comment">Live result:</div> |
| 82 | + <div class="example"> |
| 83 | + <!-- a comment that contains a > character right here --> |
| 84 | + <p>This paragraph renders normally right after it.</p> |
| 85 | + </div> |
| 86 | + <hr /> |
| 87 | + <h2><script> content is not mistaken for markup |
| 88 | + </h2> |
| 89 | + <p> |
| 90 | + <code><script></code> content is tokenized as raw text (this renderer does not execute |
| 91 | + script, so the code itself is not shown), which means <code><</code> and <code>></code> |
| 92 | + characters used for comparisons inside the script can no longer be misread as the start |
| 93 | + of a nested tag and swallow the rest of the document. |
| 94 | + </p> |
| 95 | + <div class="comment">Source:</div> |
| 96 | + <pre><script> |
| 97 | + if (1 < 2 && 3 > 2) { runDemo('<b>this looks like a tag but is just a string</b>'); } |
| 98 | +</script> |
| 99 | +<p>This paragraph still renders correctly right after the script block.</p></pre> |
| 100 | + <div class="comment">Live result:</div> |
| 101 | + <div class="example"> |
| 102 | + <script> |
| 103 | + if (1 < 2 && 3 > 2) { runDemo('<b>this looks like a tag but is just a string</b>'); } |
| 104 | + </script> |
| 105 | + <p>This paragraph still renders correctly right after the script block.</p> |
| 106 | + </div> |
| 107 | + <hr /> |
| 108 | + <h2><noscript> content is parsed as real markup |
| 109 | + </h2> |
| 110 | + <p> |
| 111 | + Per the HTML5 tokenizer spec, <code><noscript></code> content is normally tokenized |
| 112 | + as raw text too. Since this renderer never runs script, its <code><noscript></code> |
| 113 | + content is specifically re-parsed as nested html, so tags placed inside it render as real |
| 114 | + elements instead of showing up as literal text. |
| 115 | + </p> |
| 116 | + <div class="comment">Source:</div> |
| 117 | + <pre><noscript><p>This is <b>real, nested markup</b> inside noscript.</p></noscript></pre> |
| 118 | + <div class="comment">Live result:</div> |
| 119 | + <div class="example"> |
| 120 | + <noscript><p>This is <b>real, nested markup</b> inside noscript.</p></noscript> |
| 121 | + </div> |
| 122 | + </blockquote> |
| 123 | + </body> |
| 124 | +</html> |
0 commit comments