Alternative to createGlobalStyle from styled-components that can also be importable

Viewed 1533

we are currently loading Fonts and few other global styles like this:

import { createGlobalStyle } from 'styled-components';

export default createGlobalStyle`
  @font-face {
     font-family: 'Name';
     font-style: normal;
     font-weight: 400;
     font-display: swap;
     src: url(https://fonts.gstatic.com/s/name/v12/iJWZBXyIfDnIV5PNhY1KTN7Z-Yh-B4iFU0U1Z4Y.woff2) format('woff2');
  }

  // more fonts..
}

And in every _app.tsx (from every project in repo) we just

import GlobalStyle from @our-company/ui;
// few other imports

const AppProviders = ({ children, messages, locale }: Props): JSX.Element => {
  return (
    <IntlProvider
      locale={locale || 'en-GB'}
      key={locale}
      messages={messages[locale]}
      defaultLocale="en-GB"
    >
      <GlobalStyle />
      <DsThemeProvider
        locale={locale}
      >
        {children}
      </DsThemeProvider>
    </IntlProvider>
  );
};

But we noticed unnecessary font reloads caused by this GlobalStyle when clicking, for example, in checkbox elements (tried putting this in a .css and just load it and never happens again).

Any idea how could export this styles as GlobalStyle name without using styled-components so we don't have to change all import from all apps in the project?

5 Answers

why you dont create main.css and import it on your index.css or app.css , its download and cache on users browser so you don't need to use global styled component anymore

It seems like you're looking for something like injectGlobal:

import { injectGlobal } from 'styled-components';

injectGlobal`
  /* your @font-face stuff here */
`

This seems like it would be a good fit for your situation, as it would be relatively easy to transition from the existing structure using createGlobalStyle to one that uses this.

In your case, the code would look like:

import { injectGlobal } from 'styled-components';

injectGlobal`
  @font-face {
     font-family: 'Name';
     font-style: normal;
     font-weight: 400;
     font-display: swap;
     src: url(https://fonts.gstatic.com/s/name/v12/iJWZBXyIfDnIV5PNhY1KTN7Z-Yh-B4iFU0U1Z4Y.woff2) format('woff2');
  }

  // more fonts..
}

If you wish to use a solution that is backwards-compatible with any code that is rendering <GlobalStyle />, you can include a null component as the default export as a stop-gap solution, alongside your injectGlobal code:

export default () => null;

Would this solve your problem?

You can also bind the style directly inside the JS file

var stylingObject = {
  div: {
    color: "red",
    border: "1px solid red"
  }, input: {
    margin: "2px",
    padding: "5px"
  }
}

function App() {
  return (
      <div style={stylingObject.div}>
        <input style={stylingObject.input} type="text" />
      </div>
  );
}

Originally I had hoped to import some CSS file with the fonts defined there and then just importing it so it would affect the entire page, obviously because the way react works such a thing isn't possible cause it would take place only in the imported component not in the one that did the import.

the reason createGlobalStyle from styled-components renders each time is also due to react's workings - when we set the style for a "component like" (or actual component) object, like every react component its not static and renders only when needed. Even if we make it render by force on page load its not the same one (cause on each page we render it separately) so keeping up with the current config doesn't seem to be possible by react's standard.

If we want to make the styles static or "more" static we would have to :

  • either import them in each page separately - making us do a major refactor
  • or use either createGlobalStyle (allowing us to use our already created styled-components component) or importing a main css file in the main application component like in the example below:

globalStyles.js

import { createGlobalStyle } from 'styled-components';
 
const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
    background: teal;
    font-family: Open-Sans, Helvetica, Sans-Serif;
  }
`;
 
export default GlobalStyle;

App.js

import React, { Fragment } from 'react';
import GlobalStyle from './theme/globalStyle';
import Content from './components/Content';
 
function App() {
  return (
    <Fragment>
      <GlobalStyle />
      <Content />
    </Fragment>
  );
}
 
export default App;

If you have a rather large global stylesheet like we did while migrating, you can use styled-components css method to leverage styled-components (css) IDE syntax highlighting & linting you can also do the following:

import React from 'react'
import { createGlobalStyle, css } from 'styled-components'

const Reset = css`
  * {
    box-sizing: border-box;
  }
`

const Accessibility = css`
  .hidden {
    display: none !important;
    visibility: hidden;
  }
`

const BaseStyles = createGlobalStyle`
  ${Reset};
  ${Accessibility};
`

export const GlobalStyles = () => (
  <>
    <BaseStyles />
  </>
)

Import GlobalStyles and render as sibling to {children}

Related