Observed behaviour

If a web page sets the display CSS property of an element using an !important rule applied via the element's style attribute, it takes precedence over element hiding filters applied by Adblock Plus, potentially preventing ads from being hidden.

That is because element hiding in Adblock Plus for Chrome (as well as on Safari and Microsoft Edge, but unlike on Firefox) is implemented using an author stylesheet, i.e. a regular <style> element which is injected into the (shadow) DOM.

Expected behaviour

Element hiding filters should take precedence over any styles applied by the web page, including those applied using the style attribute. Adblock Plus for Firefox currently achieves that by utilizing user stlesheets. This mechanism, however, is currently not supported by Chrome, see ​Chrome bug 632009.

This isn't something we can fix as long as we are using regular <style> tags for element hiding. We should check whether ​chrome.tabs.insertCSS does things better by now and inserts a real user stylesheet. But even if it does we'll still have to file a Chromium issue - InjectDetails should allow specifying a frame ID rather than "all frames" only.

But even if they don't add a frame option that allows us to inject user stylesheets into a specific frame, we could still use the current version of chrome.tabs.injectCSS() to inject CSS into the top level frame, while keep using content scripts to inject <style> elements into subframes. This should fix issues like this in most scenarios.

Summary
changed from chrome: hiding filters do not work at http://torrentz.eu/search?f=cow to Element hiding filters can be overridden by the element's style attribute

Since this circumvention method is becoming popular again, I reopened this issue and updated the description. Also I made the issue confidential, surprisingly this wasn't done back then, despite this providing an exploitable circumvention technique.

Currently, our plan is to see what's going to happen with ​Chrome bug 632009, in which we requested chrome.tabs.insertCSS() to use user stylesheets, so that we can migrate to that API, instead of injecting an author stylesheet, which will be even less effective once shadow DOM v0 gets removed from Chrome. Then again, due to the upcoming deprecation of shadow DOM v0, the Chromium team seem to consider prioritizing that issue now (also see #4713).

Alternatively, we could (theoretically) emulate element hiding filters, partially reimplementing CSS ourselves, so that we can operate on the nodes to be hidden rather than using a stylesheet. That is essentially what uBlock is doing. But this approach is a bit controversial, as the implementation tends to be quite complex and might potentially have a negative performance effect in particular on large pages and pages that change a lot dynamically. On the other hand it could also help reducing the memory usage, like it does in uBlock. But then again, we'd still mess with the DOM, in a merely slightly harder to circumvent way. Not to mention, that as more as we mess with the actual page content (e.g. through the DOM) as higher the legal risk we are facing. So this might only be a last resort, if at all.

Since ​implementation of Chrome bug 632009 is still in theoretical phase and this bug is open for more than 3 years already then I'd suggest to implement it as special case of custom styles (#756). Script which will apply inline style must check presence of display property in the style attribute and remove it if it going to apply the same property. The really tricky part is to make sure it _stays_ since some sites use MutationObserver to make sure display:block!important wasn't removed. So, it's important to wrap getAttribute/setAttribute in order to modify style before applying it to specific elements and return original string if site script want to check it. It might be tricky to keep it consistent with changes which came from style. ... properties. Also, it might be useful to wrap style property of the object into a Proxy or modify getter/setter for display property to return block for style.display like it's still there.

perhaps the reason is:
"#?# is telling ABP to use querySelectorAll internally rather than just a CSS rule"

No exactly. Procedural hide modified style property of element to "display: none !important" which have highest priority in Google Chrome. It also monitors changes in the style property and returns it back to that value if site attempted to change it. Basically it utilizes the same trick, just to hide rather to show.

On the Adblock Plus side, we are detecting the availability of this feature and taking advantage of it if available. This already works with the Adblock Plus development build running on Google Chrome Canary and Google Chrome Dev channel.

I am closing this issue now. If there are any bugs or other issues found related specifically to this topic, they should be reported separately.

If the changes to Chromium are rolled back for any reason (still possible!), I'll reopen this issue and work on it again.

I'm contacting in the context for deprecating Shadow DOM V0 for real for Chrome.

As you said earlier that this is the blocking issue of migrating ABP
out of Shadow DOM V0, and now the user stylesheet feature is implemented and
is shipping soon in stable (M66), and I thoght it means ABP will not use
Shadow DOM V0 at all, if the feature is detected.?

I tested with my local build (M67), and it seems Adblock plus is still using
the V0 Element.createShadowRoot() API.

We would like to hear your plan about removing the usage of V0 shadow in ABP.

Eventually we would like to remove the feature in April 2019 (one year from now),
and would like to start showing deprecation message soon. Does the timeline
work for you?

Yes, Adblock Plus (as of ​version 3.0.3) should no longer use Shadow DOM (neither v0 nor v1) on Chrome 66 and above. Are sou sure that you tested with Adblock Plus 3.0.3 (or alternatively with the current development build)? Also did you tweak your user agent string by any chance (since we cannot detect the availability of user stylesheets from the content script, we have rely on the user agent string in order to avoid injecting a shadow root on Chrome 66 and above)? Otherwise can you elaborate how exactly you concluded that createShadowRoot() is still being used?