Support Ukraine 🇺🇦Help Ukrainian ArmyHumanitarian Assistance to Ukrainians

How to remove unused CSS inside <style> tags from an HTML file?

john

Oct 25 2020 at 11:33 GMT

I have an HTML file that has CSS distributed across several <style> tags.

A lot of the CSS included in the HTML is not used.

I would like to remove all unused CSS and leave only CSS that is actually used on the page.

How can I write a removeUnusedCss function in NodeJS that takes the content of the HTML file and returns the same content but with all unused CSS stripped away?

function removeUnusedCss(html) {
  // ...
}

1 Answer

Laverage

Oct 25 2020 at 12:22 GMT

There is an npm package called dropcss that takes the CSS and HTML as input, and returns only the CSS that is used:

const dropcss = require("dropcss");

const result = dropcss({ css, html });
const usedCss = result.css;

So, to remove all unused CSS from an HTML file with dropcss, we would need to do the following:

  1. Extract all CSS from the HTML.
  2. Pass the extracted CSS along with the HTML to dropcss.
  3. Insert the used CSS returned by dropcss into the HTML in place of the original CSS.

To extract the CSS from all the <style> tags, we need a simple HTML parser, such as node-html-parser.

We start by parsing the passed html using the parse function provided by node-html-parser and selecting all <style> tags.

const document = parse(html);

const styles = document.querySelectorAll("style");

We then check if there are no styles. If that's the case, we are done and so we return the HTML unchanged.

if (styles.length === 0) {
  return html;
}

Otherwise, we collect the CSS inside all <style> tags into a single string variable css.

const css = styles.map((style) => style.innerHTML).join("\n");

Now that we extracted the CSS, we can pass it to dropcss along with the HTML to get only the used CSS.

const usedCss = dropcss({ css, html }).css

We then get the last <style> tag by popping it from the styles array and remove all the remaining <style> tags from the document.

const lastStyle = styles.pop();

styles.forEach((style) => style.parentNode.removeChild(style));

Finally, we set the content of the last <style> tag that we left in the document to usedCss and return the document HTML.

lastStyle.set_content(usedCss);

return document.toString();

Here's the final removeUnusedCss function that does all the steps we just went through:

const { parse } = require("node-html-parser");
const dropcss = require("dropcss");

function removeUnusedCss(html) {
  const document = parse(html);

  const styles = document.querySelectorAll("style");

  if (styles.length === 0) {
    return html;
  }

  const css = styles.map((style) => style.innerHTML).join("\n");

  const usedCss = dropcss({ css, html }).css;

  const lastStyle = styles.pop();

  styles.forEach((style) => style.parentNode.removeChild(style));

  lastStyle.set_content(usedCss);

  return document.toString();
}

Don't forget to install the node-html-parser and dropcss dependencies:

npm install node-html-parser dropcss
claritician © 2022