question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use rem instead of px units

See original GitHub issue
  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

In order to get fully fluent responsive experiences in the MUI components I setup all “sizing properties” to apply em unit if naked number is used as a value for them.

Current Behavior 😯

  1. I passed my custom settings to defaultUnit plugin in JSS with accordance to documentation 1
  2. Then I feed StylesProvider with such customized preset: 2
  3. Theme option for htmlFontSize I set to 10.
  4. And my reset CSS has 3

As a result, some of the properties in the default theme (which are originally implemented with unitless values) are becoming oversized. Exemplary original styles implementation chunk of code: 4

This is happening because the implicit output unit (while using numbers only) for “sizes like properties” e.g. padding, margin is preassumed as px.

So when I have margin: 16 it becomes 16em in my scenario. Which produces 160px overblown margins, paddings, and so on in the default theme. Like for example: This enforces a lot of tedious override procedures in the theme, like: 5

Expected Behavior 🤔

For the originally set unitless values in the default theme I would expect one of scenario (starting from most appreciated):

  1. The values are recalculated to the respective defaultUnit settings in the JSS. So when I set defaultUnit to em for some CSS properties, the original implementation should recalculate all the unitless values based on htmlFontSize property in theme. Something like:
if (customDefaultUnit === 'em') unitlessProps.map(prop => (prop / theme.htmlFontSize);

It’s a pseudo code to get the basic concept. This scenario would create full responsive (proportional sizing) across all the styling in the default theme. 2. Default unitless props are becoming hardcoded to pixel-units in case if defaultUnit plugin is changed. This would make some theme props output as pixel-sized, which would create an inconsistent sizing pattern. But at least it would not break the theme while customizing the defaultUnit JSS preset. 3. Make the unitless concept of theming out of the theming, and make everything pixel-based. Very grim scenario but at least consistent and not brittle.

Steps to Reproduce 🕹

I hope the above explanation is enough. I will provide a working example if necessary.

Context 🔦

CSS theme that uses only proportional sizing (em, rem %) in order to get the best responsive UI experiences and simplify the process of customizing styles.

Currently, part of the API support this task like font sizing but some of the props (as described above) produce fixed pixel values which output as an inconsistent theme (some values are em and some px). This enforces many tedious overrides in theme in order to get proper responsive “fluid” results.

I don’t know if this type of issue “the Bug” (I guess it is something between the Bug and request to Change functionality) applies to the described scenario. So please amend accordingly. I might, of course, miss some documentation and do things just wrong. So please direct in the better implementation suggestions.

Your Environment 🌎

Tech Version
Material-UI v4.9.14
React v16.13.1
Browser [“last 1 version”, “> 0.5%”, “not dead”]
TypeScript v3.8.3

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:8
  • Comments:24 (12 by maintainers)

github_iconTop GitHub Comments

7reactions
mifrejcommented, May 19, 2020

Most browsers today have the base font-size set to 16px. Respecting that (which would make the most sense) we can utilize the remCalc helper to then use for all the sizing values in styles.

So exemplary I took the Button component and went through the styles to adapt it.

diff --git a/packages/material-ui/src/Button/Button.js b/packages/material-ui/src/Button/Button.js
index fe392b926..d514a0910 100644
--- a/packages/material-ui/src/Button/Button.js
+++ b/packages/material-ui/src/Button/Button.js
@@ -6,13 +6,17 @@ import { fade } from '../styles/colorManipulator';
 import ButtonBase from '../ButtonBase';
 import capitalize from '../utils/capitalize';

-export const styles = (theme) => ({
+export const styles = (theme) => {
+  /*
+    @base should be taken from `htmlFontSize` if treated as root rem font-size
+  */
+  const remCalc = (size, base = 16) => `${size / base}rem`;
+  return {
   /* Styles applied to the root element. */
   root: {
     ...theme.typography.button,
     boxSizing: 'border-box',
-    minWidth: 64,
-    padding: '6px 16px',
+    padding: `${remCalc(6)} ${remCalc(16)}`,
     borderRadius: theme.shape.borderRadius,
     color: theme.palette.text.primary,
     transition: theme.transitions.create(['background-color', 'box-shadow', 'border'], {
@@ -42,7 +46,7 @@ export const styles = (theme) => ({
   },
   /* Styles applied to the root element if `variant="text"`. */
   text: {
-    padding: '6px 8px',
+    padding: `${remCalc(6)} ${remCalc(8)}`,
   },
   /* Styles applied to the root element if `variant="text"` and `color="primary"`. */
   textPrimary: {
@@ -68,8 +72,8 @@ export const styles = (theme) => ({
   },
   /* Styles applied to the root element if `variant="outlined"`. */
   outlined: {
-    padding: '5px 15px',
-    border: `1px solid ${
+    padding: `${remCalc(5)} ${remCalc(15)}`,
+    border: `1px solid ${ // for border width px are ok most of the time as we most likely don't want to scale borders (exception)
       theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'
     }`,
     '&$disabled': {
@@ -224,10 +228,10 @@ export const styles = (theme) => ({
   /* Styles applied to the startIcon element if supplied. */

I didn’t use the existing theme helper pxToRem as it has some coef factor I don’t get, but I guess we could keep such helper in theme and propagate htmlFontSize prop as the base argument for all sizes in styles.

These adaptations would need to be applied throughout all existing components and then used for future ones.

When now I look at it it wouldn’t be actually that painful to do. Would it?

6reactions
tkodevcommented, Sep 27, 2021

I think rem should not be the default value for spacings, margins, widths, etc, because of a few things:

  • accessibility users often have their font size set differently than the default 14-16 px, this is NOT the same as page zoom and we shouldn’t treat it as such. https://medium.com/@sascha.wolff/dont-use-rem-em-for-paddings-margins-and-more-94e19026b000
  • using material ui to build injected dom elements, such as browser extensions will tie these element’s visuals to the page’s default font size. This is not ideal. While they can use things like shadow-dom, it’s not always something that’s possible, depending on the application.
Read more comments on GitHub >

github_iconTop Results From Across the Web

Why designers should move from px to rem (and how to do ...
The beauty of it is that by using rem units for defining font-size, you keep the harmony and hierarchy of your type scale...
Read more >
Should I use px or rem value units in my CSS? - Stack Overflow
I recommend using rem units for fonts, if only because it makes it easier for you, the developer, to change sizes. It's true...
Read more >
To increase A11Y, use rem instead of px | by Samir T - Medium
Browser font size is set to 16px by default, which means that 1 rem is equal to 16px, so every size is calculated...
Read more >
Back to Basic: Should we use Rem, Em or Pixel?
Using Rem and Em units is better than using px. When we use px, it means that we hardcode the... Tagged with beginners,...
Read more >
The Surprising Truth About Pixels and Accessibility
In most cases, I think it makes more sense to use rems. This preserves the button's proportions, its aesthetics. And it reduces the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found