next.js
next.js copied to clipboard
Compiler does not place css @imports in own style tags the way babel used to.
What version of Next.js are you using?
12.0.7
What version of Node.js are you using?
14.18.1
What browser are you using?
chrome
What operating system are you using?
mac0s
How are you deploying your application?
vercel
Describe the Bug
I just got bit in the upgrade.
In nextjs v10, this is considered valid:
* {
font-family: "Abril Fatface";
}
@import url('https://fonts.googleapis.com/css2?family=Abril+Fatface&display=block');
This works because each @import statement is wrapped in its own style tag.
In nextjs v12, @import statements are not wrapped in their own style tag.
Expected Behavior
I expect each @import statement is wrapped in its own style tag.
To Reproduce
In nextjs v12, add this to global.css
* {
font-family: "Abril Fatface";
}
@import url('https://fonts.googleapis.com/css2?family=Abril+Fatface&display=block');
The move to SWC does not affect .css files, can you provide a full reproduction?
I've made a repo at https://github.com/scottccoates/nextjs-12-css-test.
To reproduce:
cd next-10npm run dev- Observe the sparkly font
- Stop the process
cd ../next-12npm run dev- The sparkly font is now gone
Observe the global.css in both folders. They are identical. But it does not work on Next v12. This is because in prior versions, @import statements (found in global.css) are "hoisted" into their own script tags.
I can confirm this as an issue, but as Tim said, it's not related to SWC. (I tried adding a .babelrc file, and this still reproduces)
I could narrow it down to this change: https://github.com/vercel/next.js/compare/v11.1.3-canary.99...v11.1.3-canary.100
Most likely this PR #30165
Prior this, the generated CSS looked like this:
@import url(https://fonts.googleapis.com/css2?family=Emilys+Candy&display=block);
body,html {
padding: 0;
margin: 0;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif
}
a {
color: inherit;
text-decoration: none
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-family: Emilys Candy
}
But after, it was left untouched:
body,html {
padding: 0;
margin: 0;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif
}
a {
color: inherit;
text-decoration: none
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-family: Emilys Candy
}
@import url("https://fonts.googleapis.com/css2?family=Emilys+Candy&display=block");
#30567 and #30569 might be related
Interesting find, @balazsorban44, about the changed behavior with @import being hoisted to the top of the compiled file. Using the repro repo I was able to confirm that the font importing still works if:
- The import is placed in the CSS before the font is referenced.
- The SASS compiler is used to compile global as an
scssfile instead of acssone (sass apparently does the import-to-top hoisting itself).
Per #30567:
Loading the font with next dev works but not with next build (next start).
I can confirm that importing fonts works in dev but not with next build. Generated styles in production are not valid.
Interesting @scottccoates - it appeared to work for me with a production build in the cases I listed above. Do you mean it doesn't work in only the case of having @import below the font's usage in a plain .css file? Or does it fail for you in scss files and/or even if the import is above the font's usage?
@zackdotcomputer We somehow hit the daily limit for deploys on vercel. I will have to wait but I'll get back to you asap.
@zackdotcomputer I just realized I can run next build to view what the bundled css files will look like in production (it will be named something like .next/static/css/5a1c6eae982d3adb11d2.css).
After installing sass and changing my global.css to global.scss, it is still not working the way I expect.
Do you mean it doesn't work in only the case of having @import below the font's usage in a plain .css file? Or does it fail for you in scss files and/or even if the import is above the font's usage?
It fails regardless of where the @import statement occurs. I have this at the top of my global.scss file:
@import url('https://fonts.googleapis.com/css2?family=Work+Sans&display=block');
@import url('https://fonts.googleapis.com/css2?family=Yeseva%20One&display=block');
Yet after running next build, my bundled css file does not hoist these imports to the top.
If I go back to next 10 and run next build, I can see these fonts are hoisted to the top of my bundled css file.
See the screenshots for more detail.
Next 10

Next 12

Update on previous comment:
I was importing bootstrap first in my _app.js file, that was causing my issue:
import 'bootstrap/dist/css/bootstrap.min.css';
import '../styles/global.scss';
If i switch the import order, making the global css file first, it works, even without scss.
Confirming that @scottccoates mentioned above.
I had Tailwind definitions at the top of the file and then a font Google Font import afterwards like this
/* ./styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap");
Moving the imports as the top first thing on the file, solved the problem
/* ./styles/globals.css */
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
I also confirm this working correctly on Next 11
Hope this is useful.
Nah, moving @import ... around doesn't fix anything for me.
My CSS files used to have @imports at the top as seen here: https://guildplanner.pro/_next/static/css/4b3115bd6e9f5f53cd0c.css
But with NextJs 12, those leading @imports are gone now.
Same problem with @import on the top
I can confirm that this issue is still occurring with nextjs 12.1.0 production mode. Does anyone know any alternative way to load google fonts while using swcMinify?
Edit: The issue does not seem to be related to swc, and occurs even with swcMinify = false in nextjs 12+ versions; I worked around it in the following way:
- remove @import google fonts from the scss files
- new imports.css file that contains all the @import statements, which is imported first in _app.tsx This works with swc enabled too, production & dev versions.
For font loading, we recommend leveraging our built-in font optimization: https://nextjs.org/docs/basic-features/font-optimization
Thanks @balazsorban44 - while it would still be great to get this working with CSS/SCSS inline imports, it's good to know that link tags in head not only should work as an alternative but also give some optimization.
Inside of your purely JS/TS Next app, the guidance is to use @import in a separate stylesheet and then place a CSS import into the /pages/_app.js file:
https://nextjs.org/docs/basic-features/built-in-css-support#adding-a-global-stylesheet
I'm sure there is a technical reason for all of this but doing a CSS import into a JS app feels kind of bizarre to me. But it does fix this issue.
Really looks like the order of imports makes sense. Font @import started working after I have rearranged my scss imports.
My font imports weren't working (using Emotion's Global component) and it was because I had them with comments before each one, removing comments and leaving only the imports at the start of the css solved this issue.
This works:
const globalCSS = `
@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap');
(other global styles...)
`;
and then:
<Global styles={css`${globalCSS}`} />
In my case, I was using the @import statement in the global.css file, and also I was using the tailwindcss for
styling.
I was able to fix this issue by defining the fonts in the _document.js file.
import { Head, Html, Main, NextScript } from 'next/document';
import React from 'react';
export default function document(): JSX.Element {
return (
<Html lang={'en_US'}>
<Head>
<link rel={'icon'} href={'/favicon.ico'} />
<link rel={'stylesheet'} href={"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap"} />
{/* You also can add JS files here */}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
Per #30567:
Loading the font with next dev works but not with next build (next start).
I can confirm that importing fonts works in dev but not with next build. Generated styles in production are not valid.
@balazsorban44 @zackdotcomputer Any update on a fix for the above in next 12. Im still facing the issue on production only, even with the correct import hierarchy.
- Started facing it on upgrading from v11.1.4 to v12.3.4.
- Im also importing fonts via typekit
Same issue here, moving global.css import to the top of _app.tsx solved it, but it seems very unreliable solution. I have opted to move font import as link tag in document.tsx.
I am using nextjs v13 with pages router.
Same issue here, I am using NextJS v14 with sass and app router @import url's position incorrect after build