Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make Chrome return raw value of the CSS "content" property?

Considering the following JavaScript, CSS, and HTML codes:

console.log(getComputedStyle(document.querySelector('p'), '::after').getPropertyValue('content'));
p::after {
    content: "Hello" attr(data-after);
}
<p data-after=" World"></p>

Both Firefox and IE11 return the raw value defined in CSS: "Hello" attr(data-after), which is what I need.

But Chrome returns "Hello World", the parsed value.

When I use the Chrome DevTools to inspect the element, I can see it showing the following information in the "Styles" panel:

p::after {
    content: "Hello" attr(data-after);
}

So it looks like Chrome still has the ability to know the raw value.

Is there any JavaScript solution to make Chrome return the raw value defined in CSS like Firefox and IE11 do? Even Chrome's exclusive method is fine, as long as it can be used in JavaScript.


Situation Explained

In response to a member's question about the reason, here is the situation:

I'm trying to create a "polyfill" for CSS speak: never on pseudo-elements. The speak property is not being supported by any browser at the moment.

CSS pseudo-elements can be read by screen readers, and it's currently not possible to hide them easily from screen readers. The commonly approach to that issue is using HTML code such as <span aria-hidden="true">...</span> instead of the convenient CSS pseudo-elements and speak: never, and such an approach is inconvenient and disappointing, in my opinion.

So this polyfill is mainly about web accessibility.

How this polyfill works will be requiring CSS developers to write a bit of extra CSS code as an indicator, such as attr(speak-never):

p::after {
    content: "please make me inaudible" attr(speak-never);
    }

And then in JavaScript, the polyfill loops through every element on the page and checks if its pseudo-elements ::before and ::after's values of CSS content property contains attr(speak-never). If that indicator string is found, then the polyfill fix the pseudo-elements (by adding custom elements <before aria-hidden="true">...</before> and <after aria-hidden="true">...</after> programatically).

Now the problem is that Chrome cannot return the said attr(speak-never) in JavaScript. Although the polyfill can also work by requiring CSS developers to add one more indicator such as --speak: never for Chrome, it is better that the polyfill keeps CSS developers' works as simple as possible and does not require that extra --speak: never indicator.

So that's why this question was created.


Update

I had decided to use counter-reset: speak-never as the indicator instead because it can be read in JavaScript by all browsers.

like image 270
Ian Y. Avatar asked Mar 17 '19 06:03

Ian Y.


2 Answers

Not sure that adding something like attr(speak-never) is any cleaner than going through the HTML markup...

But this question points to an interesting thing: Chrome has started the implementation of CSSTypedOM, that we should have been able to use in order to find the original values set, as demonstrated in this answer.

However, to target pseudo-elements, it is planned that there will be a PseudoElement interface, and an extension to the Element one so that we can call Element.pseudo(::type) in order to target its pseudo-elements. But this part of the specs has not yet been implemented by Chrome, so there is actually currently no way to access the TypedValues of pseudo-elements in Chrome.

So this leaves us with parsing the stylesheets ourselves, with all the caveats that made the w3c develop a real API: no access to cross-origin stylesheets, no direct way to know if a rule is active on the element or if an other one has more importance and the like...

like image 190
Kaiido Avatar answered Oct 02 '22 15:10

Kaiido


You could lookup the rule via document.styleSheets. The property facilitates a list of stylesheets consisting of multiple rules consisting of multiple properties. You could then traverse the stylesheets and rules and extract the raw property value from there.

This is a basic approach that respects rules directly defined in <style> and <link> elements:

for (let sheet of document.styleSheets) {
    for (let rule of sheet.rules) {
        if (/:(before|after)$/.test(rule.selectorText)) {
            console.log(rule.style.content);
        }
    }
}

Note that @include-ed stylesheets or @media-queries are not handled here. They can be accessed by checking for rule.type being 3 or 5 respectively and traversing the styleSheet attribute of that rule. See the list of types.

like image 41
try-catch-finally Avatar answered Oct 02 '22 15:10

try-catch-finally