Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if HTML element has pseudo element?

Is there a way to determine that given HTML element has pseudo element (::before / ::after) applied to it without calling

window.getComputedStyle(element, ":before/:after");

EDITED: the answer is NO

The problem with getComputedStyle is in performance. I need to validate every single element on the page whether it has a pseudo element or not - that's why performance is very critical. I tried to access cssRules from document.styleSheets to find selectors with ::before or ::after at the end, remove it and find elements matched with the rest of selector, but this solution has its own issues:

  • styleSheets from different domain are not accessible
  • there could be thousands of cssRules to check (again performance)

I also tried to compare element's sizes and offsets with and without pseudo elements but nothing worked. Even if there is no accurate method I would be happy to find a way to cut an amount of elements to check at least by 30%.


When I'm sure that element has a pseudo element I can finally call getComputedStyle to investigate pseudo element style and change it. This part perfectly works.


EDITED: I have no control over a source page. Page styles could be dynamicly uploaded from different domains. Assume my code as a content script or library which for example has to change all pseudo elements foregrounds to some color calculated based on other CSS properties of that pseudo element.

So main problem that changes are based on other CSS properties and you can not set the same style for all pseudo elements without actually retrieving computed style of the pseudo element and calculating changes.

For example you have youtube.com page and you need to find all pseudo elements and

  • If this pseudo element has background image then scale the element
  • If this pseudo element has only a text then change it color to red
  • etc...
like image 944
Pavel Agarkov Avatar asked Oct 23 '16 18:10

Pavel Agarkov


1 Answers

What exactly is causing problems with your existing solution?

This method of walking through elements:

var allElements = document.getElementsByTagName("*");
for (var i = allElements.length; i--;) {
  //var usedStyle = window.getComputedStyle(allElements[i], ":before/:after");    
  ...
}

is about thousands of elements per 1ms.

And call of getComputedStyle shall not be too slow as it fetches data that is already calculated at the moment of call (on rendered document).

So all this shall really work fast enough. Yes, it is O(N) task in principle but gets run once, right?

like image 59
c-smile Avatar answered Oct 05 '22 08:10

c-smile