What is the purpose of the fontSize theme setting when all typography variants are `rem`?
Asked Answered
M

2

5

The documentation for Material UI Typography settings (https://mui.com/material-ui/customization/typography/) are confusing and don't really make sense:

MUI uses rem units for the font size. The browser element default font size is 16px, but browsers have an option to change this value, so rem units allow us to accommodate the user's settings, resulting in a better accessibility support. Users change font size settings for all kinds of reasons, from poor eyesight to choosing optimum settings for devices that can be vastly different in size and viewing distance.

To change the font-size of MUI you can provide a fontSize property. The default value is 14px.

So which is it? It uses REM or use the font-size as a base for the typography variants? If you look at the default theme (https://mui.com/material-ui/customization/default-theme/?expand-path=$.typography) all the variants are supposed to use rem -- and the documents even talk about customizing this value in htmlFontSize.

So I'm really struggling to understand the use/purpose for the fontSize theme setting?

Moser answered 1/5, 2022 at 15:16 Comment(0)
C
11

The typography.fontSize and typography.htmlFontSize values are expected to be in pixels but those pixel values do not get put directly onto the page. Instead, the material ui code will take the pixel value and calculate a corresponding rem value. That rem value is what gets put into the css class, and thus rendered by the browser. By using rems as the final value, the user's browser settings can change the final size

The equation they use for this calculation is show in the article:

computed = specification * (typography.fontSize / 14) * (html fontsize / typography.htmlFontSize)

Example 1: everything is set to its defaults, with typography.fontSize set to 14, typography.htmlFontSize set to 16, and typography.h3.fontSize set to "1.2rem". You then render a <Typography variant="h3">. In that case, the calculation would be:

computed = 1.2rem * (14 / 14) * (16 / 16)

This works out to having a size of 1.2rem, and that's what will be put into the css class.

Example 2: You now changed typography.fontSize to 12, typography.htmlFontSize to 18, and typography.h3.fontSize to "1.5rem". With those values, the calculation will be:

computed = 1.5rem * (12 / 14) * (16 / 18)

This works out to about 1.143 rem.

In practice, if you want to change all your fonts to be bigger or smaller, change typography.fontSize; each variant will scale based on that. If you want to change a specific variant to be bigger while leaving the rest the same, then modify typography.[variant].fontSize. I don't see a reason you would want to change typography.htmlFontSize, but that knob is available if you need it.

Conover answered 1/5, 2022 at 16:37 Comment(6)
But the theme object doesn't expect values in pixels. All of the default typography variants are designed in rem. REM is derived from the htmlFontSize value (in turn which is set on html element (if you so want to mess with that setting beyond the browser default.) -- I already know this. unfortunately it doesn't help answer what the point of the fontSize property is in the typography part of the theme.Moser
'The theme object expects values to be in pixels' - Where does this hold true or where is it stated?Moser
But the theme object doesn't expect values in pixels For typography.fontSize and typography.htmlFontSize it does. I should have been more clear that those are the values i was talking about. I've updated my answer with examples of the calculation.Conover
I saw the equation, but I didn't really get what they were trying to do. Now I'm just confused what they're trying to achieve with this. For me, this is bizarre. By all means use rem as a relative size, but this pixel value to fontSize is at best, confusing, and at worst, completely unnecessary. Why would they do this? It could just be HTML size * rem specification. Done?Moser
And thank you -- it helps me understand how it's used, but I'll be damned if it's not pointlessMoser
Think of typography.fontSize as being in charge of "what does 1rem mean?". So if you put a value of 16, then you're saying that anywhere that uses "1rem" should be 16 pixels high (assuming the user hasn't tweaked their browser settings), and anywhere that uses "2rem" should be 32 pixels high, etc.Conover
C
0

Code from node_modules@mui\material\styles\createTypography.js

const coef = fontSize / 14;
const pxToRem = pxToRem2 || (size => `${size / htmlFontSize * coef}rem`);

  const buildVariant = (fontWeight, size, lineHeight, letterSpacing, casing) => _extends({
    fontFamily,
    fontWeight,
    fontSize: pxToRem(size),
    // Unitless following https://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/
    lineHeight
  }, fontFamily === defaultFontFamily ? {
    letterSpacing: `${round(letterSpacing / size)}em`
  } : {}, casing, allVariants);

  const variants = {
    h1: buildVariant(fontWeightLight, 96, 1.167, -1.5),
    h2: buildVariant(fontWeightLight, 60, 1.2, -0.5),
    h3: buildVariant(fontWeightRegular, 48, 1.167, 0),
    h4: buildVariant(fontWeightRegular, 34, 1.235, 0.25),
    h5: buildVariant(fontWeightRegular, 24, 1.334, 0),
    h6: buildVariant(fontWeightMedium, 20, 1.6, 0.15),
    subtitle1: buildVariant(fontWeightRegular, 16, 1.75, 0.15),
    subtitle2: buildVariant(fontWeightMedium, 14, 1.57, 0.1),
    body1: buildVariant(fontWeightRegular, 16, 1.5, 0.15),
    body2: buildVariant(fontWeightRegular, 14, 1.43, 0.15),
    button: buildVariant(fontWeightMedium, 14, 1.75, 0.4, caseAllCaps),
    caption: buildVariant(fontWeightRegular, 12, 1.66, 0.4),
    overline: buildVariant(fontWeightRegular, 12, 2.66, 1, caseAllCaps)
  };

Px to rem mui function

this is what I found in the MUI module.

So, from the function buildVariant I can say it expected font sizes in pixels and converts them into rem values per variant.

to achieve your desired font size per variant you can add values in px using a custom function without changing htmlFontSize(16px).

const calcFontSize = (expectedBodyFontSize)=>{
    return (14/16)*expectedBodyFontSize
}

Whatever it returns you just have to assign it as font-size to create theme variable like below

const theme = createTheme({
  typography: {
    fontSize: calcFontSize(14),
  },
});

If you will check the body tag font size it will be of 14px.

Cahan answered 16/8, 2022 at 7:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.