Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ai/webp-in-css

PostCSS plugin and tiny JS script (131 bytes) to use WebP in CSS background
https://github.com/ai/webp-in-css

Last synced: about 4 hours ago
JSON representation

PostCSS plugin and tiny JS script (131 bytes) to use WebP in CSS background

Awesome Lists containing this project

README

        

# WebP in CSS

WebP logo

[PostCSS] plugin and tiny JS script (175 bytes) to use [WebP] in CSS `background`.

This tool will make your images [25% smaller] for Chrome, Firefox, and Edge.
Safari will download the bigger JPEG/PNG image.

You add `require('webp-in-css/polyfill')` to your JS bundle and write CSS like:

```css
.logo {
width: 30px;
height: 30px;
background: url(/logo.png);
}
```

The script will set `webp` or `no-webp` class on ``
and PostCSS plugin will generate:

```css
.logo {
width: 30px;
height: 30px;
background: url(/logo.webp) no-repeat;
}
body.webp .logo {
background-image: url(/logo.webp);
}
body.no-webp .logo, body.no-js .logo {
background-image: url(/logo.png);
}
```

If you want to use `addNoJs` option, you need manually set `no-js` class on ``.
Polyfill will remove this class, if JS is enabled in the browser. Polyfill should
be inserted in the ``, without `async` or `defer` attributes, before css.
`addNoJs` option is enabled by default.

[25% smaller]: https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results
[PostCSS]: https://github.com/postcss/postcss
[WebP]: https://en.wikipedia.org/wiki/WebP


Sponsored by Evil Martians

## Usage

**Step 1:** Install tool:

```sh
npm install --save-dev postcss webp-in-css
```

**Step 2:** convert all your JPEG/PNG images to WebP by [Squoosh].
Set checkbox on `Lossless` for PNG images and remove it for JPEG.

We recommend `Reduce palette` for most of the PNG images.

Save WebP images in the same places of JPEG/PNG images:
`img/bg.png` → `img/bg.webp`.

**Step 3:** use `` to insert WebP images in HTML:

```diff html
- Screenshot
+
+
+ Screenshot
+
```

**Step 4:** add JS script to your client-side JS bundle:

```diff js
+ import 'webp-in-css/polyfill'
```

Since JS script is very small (142 bytes), the best way for landings
is to inline it to HTML:

```diff html


+ <%= readFile('node_modules/webp-in-css/polyfill.js') %>
```

Note, that you need to put `` inside `<body>`, not `<head>`.

**Step 5:** check do you use PostCSS already in your bundler.
You can check `postcss.config.js` in the project root,
`"postcss"` section in `package.json` or `postcss` in bundle config.

If you don’t have it already, add PostCSS to your bundle:

* For webpack see [postcss-loader] docs.
* For Parcel create `postcss.config.js` file.
It already has PostCSS support.
* For Gulp check [gulp-postcss] docs.

**Step 6:** Add `webp-in-css/plugin` to PostCSS plugins:

```diff js
module.exports = {
plugins: [
+ require('webp-in-css/plugin'),
require('autoprefixer')
]
}
```

If you use CSS Modules in webpack add `modules: true` option:

```diff js
module.exports = {
plugins: [
- require('webp-in-css/plugin'),
+ require('webp-in-css/plugin')({ modules: true }),
require('autoprefixer')
]
}
```

We also recommend to put all images from CSS to preload content:

```diff html
+ <link rel="preload" as="image" type="image/webp" href="/logo.webp">
<script><%= readFile('node_modules/webp-in-css/polyfill.js') %>

```

[postcss-loader]: https://github.com/postcss/postcss-loader#usage
[gulp-postcss]: https://github.com/postcss/gulp-postcss
[Squoosh]: https://squoosh.app/

## PostCSS Options

```js
module.exports = {
plugins: [
require('webp-in-css/plugin')({ /* options */ }),
]
}
```

* `modules` boolean: wrap classes to `:global()` to support CSS Modules.
`false` by default.
* `webpClass` string: class name for browser with WebP support.
* `noWebpClass` string: class name for browser without WebP support.
* `addNoJs` boolean: add `no-js` class to selector.
`true` by default.
* `noJsClass` string: class name for browser without JS support.
* `check` function: should return boolean if we need to change declaration,
default:

```js
decl => /\.(jpe?g|png)(?!(\.webp|.*[&?]format=webp))/i.test(decl.value)
```
* `rename` function: get a new file name from old name,
like `(oldName: string) => string`,
then `url(./image.png)` → `url(./image.png.webp)`.
Often you will need to change `check` option too.

```js
check: decl => /\.jpg/.test(decl.value) && !decl.value.includes("as=webp"),
rename: url => url.replace(".jpg", ".jpg?as=webp")
```