How did CSS `content` property work for `img` element in WebKit?
Asked Answered
S

1

19

Long time ago there was a draft of CSS3 Generated Content spec which allowed the content property for any HTML element (not only ::before/::after pseudo-elements), without any formal restriction for empty or replaced elements. It was once supported by Opera Presto (1, 2) and, at least to some extent, by WebKit (3). By the end of 2011, WebKit's implementation of content for img element seemed to effectively convert it from an empty replaced element to non-replaced element like span (even its context menu changed, removing options like 'Save image as...'). It also made it possible to apply pseudo elements like img::before.

In the current Blink (Chrome etc.) implementation, seeting content property to img element has no visible effect. But the img element clearly has different structure depending on whether it loaded properly or is broken: if loaded, it is shown by the DOM Inspector as a simple empty element, but if broken, it exposes the internal Shadow DOM structure like this:

<div id="alttext-container" style="overflow: hidden; border: 1px solid silver; display: inline-block; box-sizing: border-box; padding: 1px;">
  <img id="alttext-image" width="16" height="16" align="left" style="margin: 0px; float: left; display: inline;">
  <div id="alttext" style="overflow: hidden; display: block;">Alt text</div>
</div>

Probably because the broken img is displayed with the help of the shadow divs, it's possible to apply pseudo elements to it in this case only (4).

Current WebKit doesn't support pseudo elements for img. But, interestingly, at least iOS 9.2.1 Safari starts to support them after setting the content property for that img (5).

Why does this property make such change? I guess that if an empty element gets any content (even generated), the browser has to provide something to display this content in, effectively replacing the empty element with some sort of a container (like Blink's shadow div id="alttext-container"), and this container can have pseudos. Am I wrong? And wasn't this behavior removed from the latest WebKit versions?

Shanika answered 19/3, 2016 at 19:28 Comment(6)
interestingly.. safari also shows the after elements and doesn't show the image even if its not broken..Nadabb
Yes, it seems that in Safari it's content property, not loaded/broken state, that changes the rendering model of the img element. That differs from Blink's behavior. By the way, did you test it in OS X Safari?Shanika
surprising, cant find it documented anywhere though..Nadabb
AFAIK, there is still no spec for the behavior of generated content for empty and/or replaced elements, so there can be no public documentation for this. Maybe someone who knows WebKit/Blink sources can help?Shanika
The new version of css-content-3 that was published a few months after you first asked this states that 1) replaced elements do not have ::before and ::after pseudos, but 2) by setting an element's content property, you can actually change whether that element is replaced or non-replaced. That means you can turn an img into a non-replaced element by setting its content to something other than a single image value, thereby allowing it to have ::before and ::after pseudos. But if you set its content to a single image value, it stays replaced.Kobarid
In the latest ED, the spec also kinda suggests what to do when the image is broken, but it makes no mention of shadow trees.Kobarid
I
1

I just recently noticed this. I was really frustrated with it. Glad to see somebody already mentioned it.

You guys seem much more knowledgeable on the topic than me. So, probably you already know these methods, but I will write my solution anyway, for juniors who will find this topic like myself.

I needed a method for broken image placeholders. I thought I could check files and give ".brokenimg" class names to tag in Back-end and change the image with CSS "content:". But It didn't work. (Tested in Chrome, Firefox, Opera, Edge, Samsung's Android Web Browser. All same.)

Then, I tried to change my script and use s instead of s. And tried this in CSS;

.brokenimg::before { content: url(picture.jpg); }

It almost worked but, But this is really limited and It wasn't what I needed.

So, solved my problem with JavaScript event;

<img onerror="this.src='broken.jpg'" src="image.jpg">

I know it is not the same thing. But in my case, it did exactly what I needed.

I guess we have to find ways like these for now.

Isochronize answered 15/12, 2018 at 22:54 Comment(1)
Yep, there have been proposals to CSS to have a feature just like the onerror attribute for broken images. Pretty interesting stuff, but no idea if that proposal will see the light of day!Kobarid

© 2022 - 2024 — McMap. All rights reserved.