DEV Community

Keng Hong
Keng Hong

Posted on

REMs and pixels - enjoy the best of both worlds

In the frontend teams I have worked in, it is not uncommon for team members to be debating over the use of REMs versus pixels(px) as units of measurement in our CSS.

TL;DR:

  • REMs allow for font-sizes across the application to scale according to the user's default browser setting
  • However, mockups from designers are typically delivered in pixels and we as developers are accustomed to pixels.

Turns out there is actually an easy solution to this debacle. We can use a PostCSS plugin to convert pixels to REMs in our application build files. Here is an example of how it can be done.

First, we need to set up a starter project with webpack.

mkdir starter
cd starter
npm init -y
npm install webpack webpack-cli --save-dev
mkdir src
touch src/index.js src/style.css webpack.config.js postcss.config.js

Your file structure should look like this at this point.

starter
│───src
│   │───index.js
│   └───style.css
│
│───node_modules       
│───package-lock.json   
│───package.json
│───webpack.config.js 
└───postcss.config.js 

Let's add some trival JS and CSS codes.

/** src/index.js **/
import "./style.css";

function component() {
  const element = document.createElement("div");
  element.classList.add("hello");
  element.textContent = "HELLO!";
  return element;
}

document.body.appendChild(component());
/** src/style.css **/
.hello {
  font-size: 16px;
  width: 16px;
  color: red;
}

Now let's add the relevant dev dependancies. We would go into detail what each dependancy does below.

npm install --save-dev css-loader style-loader postcss-loader postcss-pxtorem

css-loader The css-loader interprets @import and url() like import/require() and will resolve them.
style-loader Inject CSS into the DOM.
postcss-loader Loader for webpack to process CSS with PostCSS
postcss-pxtorem A plugin for PostCSS that generates rem units from pixel units.

We need to update both webpack.config.js and postcss.config.js respectively too.

/** webpack.config.js **/
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
    ],
  },
};
/** postcss.config.js **/
module.exports = {
  plugins: [require("postcss-pxtorem")],
};

Finally, update package.json to add script to build using webpack.

/** package.json **/
...
"scripts": {
  "build": "webpack"
}
...

Run npm run build and you should see a build file dist/bundle.js. If you were to inspect dist/bundle.js, you would see all pixels notations have been converted to REMs. And there you have it, the debate of pixels versus REMs addressed.

The demo source code can be found here.

Top comments (0)