postcss-hover-media-feature

PostCSS plugin that extracts and wraps rules containing `:hover` pseudo-classes in `@media (hover: hover) {}` media queries

Usage no npm install needed!

<script type="module">
  import postcssHoverMediaFeature from 'https://cdn.skypack.dev/postcss-hover-media-feature';
</script>

README

PostCSS Hover Media Feature

NPM Version NPM Monthly Downloads Build Status

PostCSS plugin that extracts and wraps rules containing :hover pseudo-classes in @media (hover: hover) {} media queries.

Certain mobile browsers apply :hover styles on 'tap', which (in most cases) isn't desirable. By wrapping :hover styles with a Hover Media Feature Media Query these styles will only be applied on devices that support them.

.foo:hover {
  color: blue;
  text-decoration: underline;
}

/* becomes */

@media (hover: hover) {
  .foo:hover {
    color: blue;
    text-decoration: underline;
  }
}

Installation

Using npm:

> npm install --save-dev postcss postcss-hover-media-feature

Using Yarn:

> yarn add --dev postcss postcss-hover-media-feature

Usage

Check your project for an existing PostCSS config: postcss.config.js in the project root, "postcss" section in package.json or postcss in bundle config.

If you already use PostCSS, add the plugin to plugins list:

// postcss.config.js
module.exports = {
  plugins: [
+   require('postcss-hover-media-feature'),
    require('autoprefixer')
  ]
}

If you do not use PostCSS, add it according to official docs and set this plugin in settings.

Options

fallback

Type: Boolean Default: false

The fallback option provides a way to extend this functionality to browsers that don't themselves support the Hover Media Feature. It prefixes rules whose selectors contain the :hover pseudo-selector – only when this selector is also matched will the hover styles apply.

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-hover-media-feature')({
      fallback: true
    })
  ]
}
.foo:hover {
  color: blue;
  text-decoration: underline;
}

/* becomes */

html:not(.supports-touch) .foo:hover {
  color: blue;
  text-decoration: underline;
}

@media (hover: hover) {
  .foo:hover {
    color: blue;
    text-decoration: underline;
  }
}

fallbackSelector

Type: String Default: html:not(.supports-touch)

Only relevant when fallback: true.

Specifies the selector that is prepended with a descendent combinator to selectors containing :hover pseudo-class.

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-hover-media-feature')({
      fallback: true,
      fallbackSelector: '.supports-hover'
    })
  ]
}
.foo:hover {
  color: blue;
  text-decoration: underline;
}

/* becomes */

.supports-hover .foo:hover {
  color: blue;
  text-decoration: underline;
}

@media (hover: hover) {
  .foo:hover {
    color: blue;
    text-decoration: underline;
  }
}

rootSelectors

Type: Array[String] Default: []

Only relevant when fallback: true.

Accepts an array of selectors that match the :root element (i.e. <html>) so that fallbackSelector is chained rather than prepended with descendent combinator.

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-hover-media-feature')({
      fallback: true,
      rootSelectors: ['.t-dark']
    })
  ]
}
.t-dark .foo:hover {
  color: white;
}

/* becomes */

html:not(.supports-touch).t-dark .foo:hover {
  color: white;
}

@media (hover: hover) {
  .t-dark .foo:hover {
    color: blue;
  }
}