Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Extended Css engine Build Status

Module for applying CSS styles with extended selection properties.

Extended capabilities

Pseudo-class :has()

Draft CSS 4.0 specification describes pseudo-class :has. Unfortunately, it is not yet supported by browsers.

Syntax

:has(selector)

Backward compatible syntax:

[-ext-has="selector"]

Supported synonyms for better compatibility: :-abp-has, :if.

Pseudo-class :has() selects the elements that includes the elements that fit to selector.

Examples

Selecting all div elements, which contain an element with the banner class:

<!-- HTML code -->
<div>Do not select this div</div>
<div>Select this div<span class="banner"></span></div>

Selector:

div:has(.banner)

Backward compatible syntax:

div[-ext-has=".banner"]

Pseudo-class :if-not()

This pseudo-class is basically a shortcut for :not(:has()). It is supported by ExtendedCss for better compatibility with some filters subscriptions, but it is not recommended to use it in AdGuard filters. The rationale is that one day browsers will add :has native support, but it will never happen to this pseudo-class.

Pseudo-class :contains()

This pseudo-class principle is very simple: it allows to select the elements that contain specified text or which content matches a specified regular expression. Regex flags are supported. Please note, that this pseudo-class uses textContent element property for matching (and not the innerHTML).

Syntax

// matching by plain text
:contains(text)

// matching by a regular expression
:contains(/regex/i)

Backward compatible syntax:

// matching by plain text
[-ext-contains="text"]

// matching by a regular expression
[-ext-contains="/regex/"]

Supported synonyms for better compatibility: :-abp-contains, :has-text.

Examples

Selecting all div elements, which contain text banner:

<!-- HTML code -->
<div>Do not select this div</div>
<div id="selected">Select this div (banner)</div>
<div>Do not select this div <div class="banner"></div></div>

Selector:

// matching by plain text
div:contains(banner)

// matching by a regular expression
div:contains(/this .* banner/)

// also with regex flags
div:contains(/this .* banner/gi)

Backward compatible syntax:

// matching by plain text
div[-ext-contains="banner"]

// matching by a regular expression
div[-ext-contains="/this .* banner/"]

Please note that in this example only a div with id=selected will be selected, because the next element does not contain any text; banner is a part of code, not a text.

Pseudo-class :matches-css()

These pseudo-classes allow to select an element by its current style property. The work of this pseudo-class is based on using the window.getComputedStyle function.

Syntax

/* element style matching */
selector:matches-css(property-name ":" pattern)

/* ::before pseudo-element style matching */
selector:matches-css-before(property-name ":" pattern)

/* ::after pseudo-element style matching */
selector:matches-css-after(property-name ":" pattern)

Backward compatible syntax:

selector[-ext-matches-css="property-name ":" pattern"]
selector[-ext-matches-css-after="property-name ":" pattern"]
selector[-ext-matches-css-before="property-name ":" pattern"]
  • property-name — a name of CSS property to check the element for
  • pattern — a value pattern that is using the same simple wildcard matching as in the basic url filtering rules OR a regular expression. For this type of matching, AdGuard always does matching in a case insensitive manner. In the case of a regular expression, the pattern looks like /regex/.

For non-regex patterns, (,),[,] must be unescaped, because we require escaping them in the filtering rules. For example, :matches-css(background-image:url(data:*)).

For regex patterns, " and \ should be escaped, because we manually escape those in extended-css-selector.js. For example: :matches-css(background-image: /^url\\(\\"data\\:\\image.+/).

Examples

Selecting all div elements which contain pseudo-class ::before with specified content:

<!-- HTML code -->
<style type="text/css">
    #to-be-blocked::before {
        content: "Block me"
    }
</style>
<div id="to-be-blocked" class="banner"></div>
<div id="not-to-be-blocked" class="banner"></div>

Selector:

// Simple matching
div.banner:matches-css-before(content: block me)

// Regular expressions
div.banner:matches-css-before(content: /block me/)

Backward compatible syntax:

// Simple matching
div.banner[-ext-matches-css-before="content: block me"]

// Regular expressions
div.banner[-ext-matches-css-before="content: /block me/"]

Pseudo-class :matches-attr()

This pseudo-class allows to select an element by its attributes, especially if they are randomized.

Syntax

selector:matches-attr("name"[="value"])
  • name — attribute name OR regular expression for attribute name
  • value — optional, attribute value OR regular expression for attribute value

For regex patterns, " and \ should be escaped.

Examples

<!-- HTML code -->
<div id="targer1" class="matches-attr" ad-link="ssdgsg-banner_240x400"></div>

<div id="targer2" class="has matches-attr">
  <div data-sdfghlhw="adbanner"></div>
</div>

<div id="targer3-host" class="matches-attr has contains">
  <div id="not-targer3" wsdfg-unit012="click">
    <span>socials</span>
  </div>
  <div id="targer3" hrewq-unit094="click">
    <span>ads</span>
  </div>
</div>

<div id="targer4" class="matches-attr upward">
  <div >
    <inner-afhhw class="nyf5tx3" nt4f5be90delay="1000"></inner-afhhw>
  </div>
</div>
// for div#targer1
div:matches-attr("ad-link")

// for div#targer2
div:has(> div:matches-attr("/data-/"="adbanner"))

// for div#targer3
div:matches-attr("/-unit/"="/click/"):has(> span:contains(ads))

// for div#targer4
*[class]:matches-attr("/.{5,}delay$/"="/^[0-9]*$/"):upward(2)

Pseudo-class :matches-property()

This pseudo-class allows to select an element by its properties.

Syntax

selector:matches-property("name"[="value"])
  • name — property name OR regular expression for property name
  • value — optional, property value OR regular expression for property value

For regex patterns, " and \ should be escaped.

name supports regexp for property in chain, e.g. prop./^unit[\\d]{4}$/.type

Examples

divProperties = {
    id: 1,
    check: {
        track: true,
        unit_2ksdf1: true,
    },
    memoizedProps: {
        key: null,
        tag: 12,
        _owner: {
            effectTag: 1,
            src: 'ad.com',
        },
    },
};
// element with such properties can be matched by any of such rules:

div:matches-property("check.track")

div:matches-property("check./^unit_.{4,6}$/")

div:matches-property("memoizedProps.key"="null")

div:matches-property("memoizedProps._owner.src"="/ad/")
For filters maintainers

To check properties of specific element, do:

  1. Select the element on the page.
  2. Go to Console tab and run console.dir($0).

Pseudo-class :xpath()

This pseudo-class allows to select an element by evaluating a XPath expression.

Limited to work properly only at the end of selector, except of pseudo-class :remove().

The :xpath(...) pseudo is different than other pseudo-classes. Whereas all other operators are used to filter down a resultset of elements, the :xpath(...) operator can be used both to create a new resultset or filter down an existing one. For this reason, subject selector is optional. For example, an :xpath(...) operator could be used to create a new resultset consisting of all ancestors elements of a subject element, something not otherwise possible with either plain CSS selectors or other procedural operators.

Normally, a pseudo-class is applied to nodes selected by a selector. However, :xpath is special as the selector can be ommited. For any other pseudo-class that would mean "apply to ALL DOM nodes", but in case of :xpath it just means "apply me to the document", and that significantly slows elements selecting. That's why we convert #?#:xpath(...) rules for looking inside the body tag. Rules like #?#*:xpath(...) can still be used but we highly recommend you avoid it and specify the selector.

Syntax

[selector]:xpath(expression)
  • selector- optional, a plain CSS selector, or a Sizzle compatible selector
  • expression — a valid XPath expression

Examples

// Filtering results from selector
div:xpath(//*[@class="test-xpath-class"])
div:has-text(/test-xpath-content/):xpath(../../..)

// Use xpath only to select elements
facebook.com##:xpath(//div[@id="stream_pagelet"]//div[starts-with(@id,"hyperfeed_story_id_")][.//h6//span/text()="People You May Know"])

Pseudo-class :nth-ancestor()

This pseudo-class allows to lookup the nth ancestor relative to the currently selected node.

Limited to work properly only at the end of selector, except of pseudo-class :remove().

It is a low-overhead equivalent to :xpath(..[/..]*).

Syntax

selector:nth-ancestor(n)
  • selector — a plain CSS selector, or a Sizzle compatible selector.
  • n — positive number >= 1 and < 256, distance from the currently selected node.

Examples

div.test:nth-ancestor(4)

div:has-text(/test/):nth-ancestor(2)

Pseudo-class :upward()

This pseudo-class allows to lookup the ancestor relative to the currently selected node.

Limited to work properly only at the end of selector, except of pseudo-class :remove().

Syntax

/* selector parameter */
subjectSelector:upward(targetSelector)

/* number parameter */
subjectSelector:upward(n)
  • subjectSelector — a plain CSS selector, or a Sizzle compatible selector
  • targetSelector — a valid plain CSS selector
  • n — positive number >= 1 and < 256, distance from the currently selected node

Examples

div.child:upward(div[id])
div:contains(test):upward(div[class^="parent-wrapper-")

div.test:upward(4)
div:has-text(/test/):upward(2)

Pseudo-class :remove() and pseudo-property remove

Sometimes, it is necessary to remove a matching element instead of hiding it or applying custom styles. In order to do it, you can use pseudo-class :remove() as well as pseudo-property remove.

Pseudo-class :remove() is limited to work properly only at the end of selector.

Syntax

! pseudo-class
selector:remove()

! pseudo-property
selector { remove: true; }
  • selector — a plain CSS selector, or a Sizzle compatible selector

Examples

div.inner:remove()
div:has(> div[ad-attr]):remove()
div:xpath(../..):remove()

div:contains(target text) { remove: true; }
div[class]:has(> a:not([id])) { remove: true; }

Please note, that all style properties will be ignored if :remove() pseudo-class or remove pseudo-property is used.

Selectors debug mode

Sometimes, you might need to check the performance of a given selector or a stylesheet. In order to do it without interacting with javascript directly, you can use a special debug style property. When ExtendedCss meets this property, it enables the "debug"-mode either for a single selector or for all selectors depending on the debug value.

Debugging a single selector

.banner { display: none; debug: true; }

Enabling global debug

.banner { display: none; debug: global; }

Usage

You can import, require or copy IIFE module with ExtendedCss into your code.

e.g.

import ExtendedCss from 'extended-css';

or

const ExtendedCss = require('extended-css');

IIFE module can be found by the following path ./dist/extended-css.js

After that you can use ExtendedCss as you wish:

(function() {
  var cssText = 'div.wrapper>div[-ext-has=".banner"] { display:none!important; }\n';
  cssText += 'div.wrapper>div[-ext-contains="some word"] { background:none!important; }';
  var extendedCss = new ExtendedCss({ cssText: cssText });
  extendedCss.apply();

  // Just an example of how to stop applying this extended CSS
  setTimeout(function() {
    extendedCss.dispose();
  }, 10 * 1000);
})();

Debugging extended selectors

To load ExtendedCss to a current page, copy and execute the following code in a browser console:

!function(E,x,t,C,s,s_){C=E.createElement(x),s=E.getElementsByTagName(x)[0],C.src=t,
C.onload=function(){alert('ExtCss loaded successfully')},s.parentNode.insertBefore(C,s)}
(document,'script','https://AdguardTeam.github.io/ExtendedCss/extended-css.min.js')

Alternative, install an "ExtendedCssDebugger" userscript: https://github.com/AdguardTeam/Userscripts/blob/master/extendedCssDebugger/extended-css.debugger.user.js

You can now use the ExtendedCss constructor in the global scope, and its method ExtendedCss.query as document.querySelectorAll.

var selectorText = "div.block[-ext-has='.header:matches-css-after(content: Anzeige)']";

ExtendedCss.query(selectorText) // returns an array of Elements matching selectorText

Projects using Extended Css

Test page

Link

About

A javascript library that allows using extended CSS selectors (:has, :contains, etc)

Topics

Resources

License

Packages

No packages published
You can’t perform that action at this time.