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.

[theming] @font-face at-rule broken in styleOverrides

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.

Current Behavior 😯

When specifying multiple @font-face at-rules via an array in MuiCssBaseline.styleOverrides, a single @font-face block is output rather than multiple @font-face declarations. The final rule thus takes precedence, ignoring all previous rules.

Expected Behavior 🤔

Specifying multiple @font-face at-rules should result in multiple @font-face declarations, allowing us to specify multiple faces for different font variants.

Steps to Reproduce 🕹

This is tough to build on CodeSandbox since it involves theming and it’s hard to get that set up on there to render correctly. But you should be able to reproduce with the dummy code below in ANY theme in your local environment.

Steps:

  1. Build any theme using createMuiTheme
  2. Specify @font-face with several values in MuiCssBaseline.styleOverrides as designated below:
const theme = createMuiTheme({
  MuiCssBaseline: {
    styleOverrides: {
      "@font-face": [
        {
          fontFamily: "Inter",
          fontStyle: "normal",
          fontDisplay: "swap",
          fontWeight: 300,
          src:
            "url('/fonts/inter/Inter-Light.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Light.woff?v=3.15') format('woff')"
        },
        {
          fontFamily: "Inter",
          fontStyle: "italic",
          fontDisplay: "swap",
          fontWeight: 300,
          src:
            "url('/fonts/inter/Inter-LightItalic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-LightItalic.woff?v=3.15') format('woff')"
        },
        {
          fontFamily: "Inter",
          fontStyle: "normal",
          fontDisplay: "swap",
          fontWeight: 400,
          src:
            "url('/fonts/inter/Inter-Regular.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Regular.woff?v=3.15') format('woff')"
        },
        {
          fontFamily: "Inter",
          fontStyle: "italic",
          fontDisplay: "swap",
          fontWeight: 400,
          src:
            "url('/fonts/inter/Inter-Italic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Italic.woff?v=3.15') format('woff')"
        },
      ]
    }
  }
});
  1. Use the CssBaseline component inside your ThemeProvider:
<ThemeProvider theme={theme}>
  <CssBaseline />
  {/* eslint-disable-next-line react/jsx-props-no-spreading */}
  <Component {...pageProps} />
</ThemeProvider>
  1. Observe that the corresponding injected <style> tag contains the following:
<style data-emotion="css-global" data-s="">
@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:300;src:url('/fonts/inter/Inter-Light.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Light.woff?v=3.15') format('woff');font-family:Inter;font-style:italic;font-display:swap;font-weight:300;src:url('/fonts/inter/Inter-LightItalic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-LightItalic.woff?v=3.15') format('woff');font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url('/fonts/inter/Inter-Regular.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Regular.woff?v=3.15') format('woff');font-family:Inter;font-style:italic;font-display:swap;font-weight:400;src:url('/fonts/inter/Inter-Italic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Italic.woff?v=3.15') format('woff');}
</style>

Notice that there’s only a single @font-face at-rule containing each rule rather than a @font-face at-rule for EACH object specified. This results in every font rendering using whatever the last rule is (in this case, italic).

What SHOULD happen is this:

<style data-emotion="css-global" data-s="">
@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:300;src:url('/fonts/inter/Inter-Light.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Light.woff?v=3.15') format('woff');}
@font-face{font-family:Inter;font-style:italic;font-display:swap;font-weight:300;src:url('/fonts/inter/Inter-LightItalic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-LightItalic.woff?v=3.15') format('woff');}
@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url('/fonts/inter/Inter-Regular.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Regular.woff?v=3.15') format('woff');}
@font-face{font-family:Inter;font-style:italic;font-display:swap;font-weight:400;src:url('/fonts/inter/Inter-Italic.woff2?v=3.15') format('woff2'),url('/fonts/inter/Inter-Italic.woff?v=3.15') format('woff');}
</style>

Context 🔦

Trying to define multiple @font-face declarations in order to render multiple font variations of a single typeface.

Your Environment 🌎

`npx @material-ui/envinfo`
  System:
    OS: macOS 11.2
  Binaries:
    Node: 14.4.0 - /usr/local/bin/node
    Yarn: Not Found
    npm: 6.14.11 - /usr/local/bin/npm
  Browsers:
    Chrome: 88.0.4324.150
    Edge: Not Found
    Firefox: 84.0.2
    Safari: 14.0.3
  npmPackages:
    @emotion/react: ^11.1.5 => 11.1.5 
    @emotion/styled: ^11.1.5 => 11.1.5 
    @material-ui/core: ^5.0.0-alpha.25 => 5.0.0-alpha.25 
    @material-ui/icons: ^5.0.0-alpha.24 => 5.0.0-alpha.24 
    @material-ui/styled-engine:  5.0.0-alpha.25 
    @material-ui/styles:  5.0.0-alpha.25 
    @material-ui/system:  5.0.0-alpha.25 
    @material-ui/types:  5.1.7 
    @material-ui/unstyled:  5.0.0-alpha.25 
    @material-ui/utils:  5.0.0-alpha.25 
    @types/react: ^17.0.2 => 17.0.2 
    react: ^17.0.1 => 17.0.1 
    react-dom: ^17.0.1 => 17.0.1 
    typescript: ^4.1.5 => 4.1.5 

Using with Next.js though that shouldn’t matter. 😃

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:5
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

19reactions
daniel-rabecommented, Nov 19, 2021

for multiple font-faces the fallbacks syntax works fine;

MuiCssBaseline: {
  styleOverrides: {
    '@font-face': {
      /* open-sans-300 - latin_cyrillic */
      fontFamily: '"Open Sans"',
      fontDisplay: 'swap',
      fontStyle: 'normal',
      fontWeight: 300,
      src: `local('Open Sans Light'), local('OpenSans-Light'),
            url(${normal300woff2}) format('woff2'),
            url(${normal300woff}) format('woff'),
            url(${normal300ttf}) format('truetype')`
    },
    fallbacks: [
        {
            /* open-sans-300italic - latin_cyrillic */
            '@font-face': {
                fontFamily: '"Open Sans"',
                fontDisplay: 'swap',
                fontStyle: 'italic',
                fontWeight: 300,
                src: `local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
                    url(${italic300woff2}) format('woff2'),
                    url(${italic300woff}) format('woff'),
                    url(${italic300ttf}) format('truetype')`
            }
        },
        {
            '@font-face': {
                /* open-sans-regular - latin_cyrillic */
                fontFamily: '"Open Sans"',
                fontDisplay: 'swap',
                fontStyle: 'normal',
                fontWeight: 400,
                src: `local('Open Sans Regular'), local('OpenSans-Regular'),
                    url(${normal400woff2}) format('woff2'),
                    url(${normal400woff}) format('woff'),
                    url(${normal400ttf}) format('truetype')`
            },
        }
    ]
}}
8reactions
oliviertassinaricommented, Feb 16, 2021

@ZLevine Thanks for opening the issue. There are multiple aspects to it:

  1. The JavaScript syntax can’t work with emotion and styled-components. The same key will override the other.
  2. The documentation needs to be updated to showcase the CSS approach.
  3. One solution is:
import * as React from 'react';
import { ThemeProvider, createMuiTheme, CssBaseline, Box } from '@material-ui/core';

const theme = createMuiTheme({
  typography: {
    fontFamily: 'Raleway, Arial',
  },
  components: {
    MuiCssBaseline: {
      styleOverrides: `
        @font-face {
          font-family: 'DroidSerif';
          src: url('https://rawgit.com/google/fonts/master/ufl/ubuntu/Ubuntu-Bold.ttf') format('truetype');
          font-weight: normal;
          font-style: normal;
        }

        @font-face {
          font-family: 'DroidSerif';
          src: url('https://rawgit.com/google/fonts/master/ufl/ubuntumono/UbuntuMono-Italic.ttf') format('truetype');
          font-weight: bold;
          font-style: normal;
        }
      `,
    },
  },
});

export default function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Box sx={{
        fontFamily: 'DroidSerif',
      }}>
        Hello
      </Box>
    </ThemeProvider>
  );
}
  1. CssBaseline doesn’t allow to mix CSS and JavaScript, it needs to be updated:
diff --git a/packages/material-ui/src/CssBaseline/CssBaseline.js b/packages/material-ui/src/CssBaseline/CssBaseline.js
index 4b5c9c8980..23475eb9b8 100644
--- a/packages/material-ui/src/CssBaseline/CssBaseline.js
+++ b/packages/material-ui/src/CssBaseline/CssBaseline.js
@@ -1,6 +1,5 @@
 import * as React from 'react';
 import PropTypes from 'prop-types';
-import { deepmerge } from '@material-ui/utils';
 import useThemeProps from '../styles/useThemeProps';
 import GlobalStyles from '../GlobalStyles';

@@ -25,7 +24,7 @@ export const body = (theme) => ({
 });

 export const styles = (theme) => {
-  const defaultStyles = {
+  let defaultStyles = {
     html,
     '*, *::before, *::after': {
       boxSizing: 'inherit',
@@ -46,7 +45,7 @@ export const styles = (theme) => {

   const themeOverrides = theme.components?.MuiCssBaseline?.styleOverrides;
   if (themeOverrides) {
-    return deepmerge(defaultStyles, themeOverrides);
+    defaultStyles = [defaultStyles, themeOverrides];
   }

   return defaultStyles;

This works with emotion and styled-components. Without the change, it only works with emotion once wrapped with import { css } from @material-ui/styled-engine;

  1. We need to do something about TypeScript, not sure why:
Capture d’écran 2021-02-16 à 19 49 58

cc @mnajdova

Read more comments on GitHub >

github_iconTop Results From Across the Web

css - React 18 - MUI - change font family - Stack Overflow
The best way to change the font family of entire project is using MUI's CSSBaseline. theme.ts:
Read more >
font-face - CSS: Cascading Style Sheets - MDN Web Docs
Chrome Edge @font‑face Full support. Chrome1. Toggle history Full support... OpenType CBDT and CBLC rendering Full support. Chrome66. Toggle history Full support... OpenType COLRv0 rendering Full...
Read more >
How To Define Custom Fonts in CSS with @font-face and font ...
The font-face at-rule gives a lot of flexibility to define custom fonts using CSS. Plus, the font-display property allows to control even ...
Read more >
MUI Theme styleOverrides - TSS - Setup
TSS Support MUI Global style overrides from createTheme out of the box. Previously in material-ui v4 it was: global theme overrides.
Read more >
font-face broken in child theme - WordPress Stack Exchange
The problem is not there in your @font-face it's actually in the functions.php where you enqueued the stylesheets.
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