<video> element not displaying in Safari (most of the time)

https://beta.observablehq.com/@eeeps/video-element-test

The markup is straightforward, and it works consistently in Chrome and Firefox. I have gotten it to appear sometimes after refreshes in Safari, but haven’t been able to do so consistently or determine why.

Given the expected DOM and no errors in the console, my guess is: Safari bug, maybe? Any workarounds?

Possibly related: responsive images don’t show up in Safari, either?!

I’m working on an Observable about responsive images; this is inconvienent.

Yes, this is a bug in Safari; specifically, it appears to be a bug with Safari’s support for the template element, which is used by Observable’s html built-in to generate a document fragment from the string of HTML source. This bug affects both video elements and responsive images.

One way to avoid the template element is to create the content programmatically:

{
  const video = document.createElement("video");
  video.src = "https://eric-cloudinary-res.cloudinary.com/video/upload/v1476106959/breakpoints-generator-v2/g_autox5.mp4";
  video.autoplay = true;
  video.loop = true;
  video.width = 320;
  video.height = 240;
  return video;
}

Or more simply:

Object.assign(DOM.element("video"), {
  src: "https://eric-cloudinary-res.cloudinary.com/video/upload/v1476106959/breakpoints-generator-v2/g_autox5.mp4",
  autoplay: true,
  loop: true,
  width: 320,
  height: 240
})

You can also use this technique to parse HTML without using the html built-in:

Object.assign(DOM.element("div"), {innerHTML: `<video src="https://eric-cloudinary-res.cloudinary.com/video/upload/v1476106959/breakpoints-generator-v2/g_autox5.mp4" autoplay loop width=320 height=240></video>`})

I think we can use range.createContextualFragment instead of template elements across the board, but I need to confirm that won’t break anything else before we deploy. Update: using range.createContextualFragment universally isn’t a viable option, unfortunately, because it breaks parsing of HTML fragments. For example, <tr><td>hello</td></tr> doesn’t produce an HTMLTableRowElement, it produces a Text node.

1 Like

Thanks again for the bug report, Eric.

We’ve found a work around for our html templating in Safari (using document.importNode()), and both of your examples — the <video> tag embed and the responsive image example — are working properly in Safari now.

Cheers!

1 Like

Great!

I was just about to post that I thought I’d figured out a slightly simpler version of Mike’s original workaround… even better to know that that won’t be necessary.

Thanks so much.