Convert Tailwind 3 default screens from px to rem

Improve the desktop experience for users who prefer larger text
Wood engraving of an antique telescope on an elaborate lamp stand-like stand, at horizontal, pointing to the right. It is captioned, “An apparatus adapted to the reflecting telescope for shewing the transit of Venus.”
Astronomy: a large reflecting telescope, and projection of the transit of Venus. Engraving. Public Domain Mark. Source: Wellcome Collection.

Defaulting to rem (or other responsive) values in height and width media queries is more accessible than defaulting to px (or other static) values.

The language we typically use for design variants shown on smaller and larger viewports focuses on device size: “mobile layout”, “media min-width”. For most [citation needed] designs, we can instead think of these responsive designs as responding to how many default font-size characters fit on one full-width line. Larger viewports can fit more default font-size text on a full-width line. But viewport size isn’t the only thing that affects how many characters fit on a line: browser zoom level and user-customized default font size do too. In most cases [citation needed], it’s desirable to apply “mobile” styles on desktop when zoomed in or when increasing the default font size. (Josh Comeau’s article The Surprising Truth About Pixels and Accessibility has a case study example.) px-value height and width media queries may respond to browser zoom and to user-customized default font size, but rem-value ones do so more reliably.

v4 Note

Tailwind v4, in beta as of this writing, uses rem breakpoints by default.

Tailwind CSS 3’s default screen values —its responsive breakpoint values— are all px sizes. I convert them to rems.

The keys stay the same, so you can drop this into an existing project without breaking things.

Here’s my solution. It supports min-width size values, object values with a min key and/or a max key, and object values with a raw key; and like default Tailwind it generates max-width screen complements for the min-width size value screens. You can try it out in this fiddle.

tailwind.config.js
js
const defaultTheme = require("tailwindcss/defaultTheme");

const rootFontSizePx = 16;

/**
 * pxToRem
 * Given a size in pixels, returns a size rems
 *
 * @param {Number} px Size to convert to rems, in unitless pixels
 * @param {Number} rootPx Size rems are relative to, in unitless pixels
 * @returns
 */
function pxToRem(px, rootPx = rootFontSizePx) {
  const rem = `${px / rootPx}rem`;

  return rem;
}

/**
 * Given a Tailwind screens configuration, return the equivalent with all pixel values converted to rems.
 * @param {object} screens Screen configuration.
 * @returns {object}
 */
function remifyScreens(screens) {
  return Object.entries(screens).reduce((acc, [key, value]) => {
    if (typeof value === "object") {
      const keys = Object.keys(value);

      if (keys.find((k) => !["min", "max"].includes(k))) {
        acc[key] = value;
        return acc;
      }

      const remScreens = remifyScreens(value);

      acc[key] = remScreens;

      if (keys.length === 1 && keys[0] === "min") {
        acc[`min-${key}`] = { raw: `not all and (max-width: ${remScreens})` };
      }

      return acc;
    }

    const remScreen = pxToRem(value);

    acc[key] = remScreen;
    acc[`max-${key}`] = { raw: `not all and (min-width: ${remScreen})` };

    return acc;
  }, {});
}

module.exports = {
  theme: {
    screens: () => {
      const pxScreens = defaultTheme.screens;

      // if needed, redefine defaults here, for example
      pxScreens["2xl"] = "1400px";

      return remifyScreens({
        ...pxScreens,

        // additional media queries, if any, go here
        "update-slow": { raw: "(update: slow)" },
      });
    },
  },
};

Articles You Might Enjoy

Or Go To All Articles