Summary: | Streaming HTML only works in iframe elements. Safari waits to buffer all HTML before rendering. | ||
---|---|---|---|
Product: | WebKit | Reporter: | Nathan Knowler <nathan> |
Component: | Layout and Rendering | Assignee: | Nobody <webkit-unassigned> |
Status: | NEW --- | ||
Severity: | Normal | CC: | bfulgham, konnor5456, mike, rik, simon.fraser, webkit-bug-importer, zalan |
Priority: | P2 | Keywords: | InRadar |
Version: | Safari 17 | ||
Hardware: | Mac (Apple Silicon) | ||
OS: | macOS 13 | ||
Attachments: |
Description
Nathan Knowler
2023-11-27 09:03:32 PST
Created attachment 468770 [details]
Source code of the hosted Deno server which streaming to the Declarative Shadow DOM.
To add to this, the problem is very specific. Safari seems to need about 512bytes of HTML to start streaming, otherwise it will remain buffered as noted here: https://lamplightdev.com/blog/2024/01/10/streaming-html-out-of-order-without-javascript/ *BUT* the problem is even more speific than "512 bytes", Safari seems to want 512 bytes of displayable HTML. That is, any element in the `<head>` is ignored, any element that is default hidden IE: `<script>`, `<template>`, HTML comments, etc are all ignored. Even `<canvas>` with text in it is ignored. The "easiest" way of triggering HTML streaming seems to be with a height / width of 0 div, with no overflow. Like this: ```html <body> <div style="height: 0; width: 0; overflow: hidden;" hidden> {{ 512 bytes of data }} </div> <!-- stream the rest --> </body> ``` This seems to be Safari / WebKit specific and is a pretty big gotcha. Sorry, `<div hidden>` actually causes it to still buffer. So you need to use aria-hidden instead. ```html <body> <div style="height: 0; width: 0; overflow: hidden;" aria-hidden="true"> {{ 512 bytes of data }} </div> <!-- stream the rest --> </body> ``` As it turns out, the first element in the body doesn't seem to count. So its even worse than that. The above code will not stop buffering. But it will work if you inject it into the shadowroot of the body. Here's the secret incantation Joel Drapper came up with to skirt Safari's HTML streaming. To note, Safari expects 512 characters, and not 512 bytes, so there's 512 escape sequences for zero width white space. ```html <!DOCTYPE html> <html> <head></head> <body> <template shadowrootmode="open"> <span aria-hidden="true" style="-webkit-user-select: none; user-select: none;"> ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ </span> </template> </body> </html> ``` |