@csstools/css-has-pseudo-experimental

EXPERIMENTAL : Style elements relative to other elements in CSS

Usage no npm install needed!

<script type="module">
  import csstoolsCssHasPseudoExperimental from 'https://cdn.skypack.dev/@csstools/css-has-pseudo-experimental';
</script>

README

EXPERIMENTAL : CSS Has Pseudo

NPM Version Discord

⚠️ Experimental version of CSS Has Pseudo

EXPERIMENTAL CSS Has Pseudo lets you style elements relative to other elements in CSS, following the Selectors Level 4 specification.

'Can I use' table

a:has(> img) {
  /* style links that contain an image */
}

h1:has(+ p) {
  /* style level 1 headings that are followed by a paragraph */
}

section:not(:has(h1, h2, h3, h4, h5, h6)) {
  /* style sections that don’t contain any heading elements */
}

body:has(:focus) {
  /* style the body if it contains a focused element */
}

Next, use your transformed CSS with this script:

<link rel="stylesheet" href="TRANSFORMED.css">
<script src="https://unpkg.com/@csstools/css-has-pseudo-experimental/dist/browser-global.js"></script>
<script>cssHasPseudo(document)</script>

⚠️ Please use a versioned url, like this : https://unpkg.com/@csstools/css-has-pseudo-experimental@0.1.0/dist/browser-global.js Without the version, you might unexpectedly get a new major version of the library with breaking changes.

⚠️ If you were using an older version via a CDN, please update the entire url. The old URL will no longer work.

That’s it. The script works in most browser versions, including Internet Explorer 11. With a Mutation Observer polyfill, the script will work down to Internet Explorer 9.

See README BROWSER for more information.

How it works

The PostCSS plugin clones rules containing :has, replacing them with an alternative [:has] selector.

body:has(:focus) {
  background-color: yellow;
}

section:not(:has(h1, h2, h3, h4, h5, h6)) {
  background-color: gray;
}

/* becomes */

[body\:has\(\:focus\)] {
    background-color: yellow;
}

body:has(:focus) {
    background-color: yellow;
}

[section\:not\(\:has\(h1\,\%20h2\,\%20h3\,\%20h4\,\%20h5\,\%20h6\)\)] {
    background-color: gray;
}

section:not(:has(h1, h2, h3, h4, h5, h6)) {
    background-color: gray;
}

Next, the JavaScript library adds a [:has] attribute to elements otherwise matching :has natively.

<body body:has(:focus)>
  <input value="This element is focused">
</body>

PostCSS Preset Env

When you use postcss-preset-env you must disable the regular plugin.

The experimental plugin must be added after any other plugin that modifies selectors.

plugins: [
  // other plugins
  postcssPresetEnv({
    features: {
      'css-has-pseudo': false
    }
  }),
  // other plugins
  cssHasPseudoExperimental(), // last
]