Ensure `<picture>` is not parsed as block-level element

Based on the spec on Raw HTML I would expect the following Markdown containing a raw HTML block

Hello <picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

to be rendered to the following HTML:

<p>Hello <picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture></p>

However, it instead gets rendered like this:

<p>Hello <picture></p>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

Sample playground

It looks like the picture element is mistakenly interpreted as a block-level element which are not permitted in p.

Is this an issue in the spec, or is there a detail in the spec that I’m missing? Otherwise, the only way to ensure an image is rendered inline with a paragraph using the picture element is by putting everything onto one line, i.e.:

Hello <picture><source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg"><img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg"></picture>

Is rendered like

<p>Hello <picture><source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg"><img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg"></picture></p>

However, this is not feasible in our scenario since we can’t guarantee it’ll all be in a single line.

2 Likes

Hmm. Sure feels like we should add <picture to the list of start conditions (4.6.1) ?

The whole picture thing is new to me tbh but with more and more websites adding dark theme support I see why we are going this way and would want to support passthrough of the picture tag in the spec. It’s getting to the point where we might even want to consider an easy way of extending the Image syntax to support image alternatives but enabling usage of the picture tag would be a good first step to see if this gets traction.

Interested in others thoughts on this, especially folks who remember writing the 4.6.1 exclusions… :eyes: @jgm @codinghorror

1 Like

The picture element can be used in phrasing (inline) content, and I think
that’s why we didn’t include it in the list.

1 Like

Since the start conditions in 4.6.1 denote block-level elements, right? That makes sense to me it wouldn’t be included there then.

We actually do look to inline content with the picture element, however if there is a newline between the picture element and its first child, i.e. a source, the inline flow of the picture element is broken by a rebalanced </p>:

Some text
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

will render as

<p>Some text
<picture></p>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

What’s the best way this kind of markup can be treated as a single inline element in the output?

I don’t know what renderer you’re using. With the reference
implementation cmark, we get what you want:

% cmark
<picture>
  <source media="(prefers-color-scheme: dark)"
srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun”
src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>
^D
<picture>
  <source media="(prefers-color-scheme: dark)"
srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun”
src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

Also with commonmark.js. Just be sure you have blank spaces
around it.

Sorry if I wasn’t particularly clear here about the environment. I’m using the reference implementation cmark. The issue occurs when

  • the <picture> element occurs inside a paragraph i.e. after some text and
  • there is a newline after the opening <picture> element

Take this example:

$ build/src/cmark --unsafe
Hello, picture! You should render inline <picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>
^D
<p>Hello, picture! You should render inline <picture></p>
  <source media="(prefers-color-scheme: dark)" srcset="https://i1.sndcdn.com/artworks-q4oGZz1o7CdhGpzu-NzH10w-t500x500.jpg">
  <img alt=“sun” src="https://i1.sndcdn.com/artworks-ebwV2wgyESPlfoGh-vleoIg-t500x500.jpg">
</picture>

You can see how the current paragraph ends after <picture> - it was only my assumption that <picture> would be interpreted wrongfully here as a block-level element; but given this conversation I’m now pretty sure it isn’t and shouldn’t.

I would expect it to work more like a traditional inline element, i.e.:

$ build/src/cmark --unsafe
Hello, span! You should render inline <span>
  <b>test</b>
</span>
^D
<p>Hello, span! You should render inline <span>
<b>test</b>
</span></p>

Here you can see how the entire HTML is considered part of the paragraph and thus the </p> is placed after </span>, despite there being a newline after <span>.

This rendering behavior also exists for the <video> element, so I think it should be feasible to achieve the same:

$ build/src/cmark --unsafe
Hi there, video! You should render inline <video controls width="250">
    <source src="/media/cc0-videos/flower.webm"
            type="video/webm">
    <source src="/media/cc0-videos/flower.mp4"
            type="video/mp4">
</video>
^D
<p>Hi there, video! You should render inline <video controls width="250">
<source src="/media/cc0-videos/flower.webm"
type="video/webm">
<source src="/media/cc0-videos/flower.mp4"
type="video/mp4">
</video></p>

Thanks, that helps. The issue is that <source triggers an HTML block – see
the spec under type 6 start conditions.

Maybe <source shouldn’t actually be in this list. It should never begin a raw HTML block, should it? It should only be part of a block headed by another element, like <picture>.

@jgm Yes, that’s the same conclusion I came to when looking into this behavior with @matthiaswenz.
Should we open a pull request with the proposed change to the spec or what do you suggest as the best way forward?

1 Like

Lukas Spieß via CommonMark Discussion
noreply@talk.commonmark.org writes:

Should we open a pull request with the proposed change to the spec or what do you suggest as the best way forward?

Yes, a PR would be good, I think.

2 Likes

Awesome! Thanks @jgm for your help in finding and @lumaxis for proposing the change!

1 Like