How to use Next.js' built-in CSS
The amount of work that goes into styling is a crucial aspect of development. The first language that comes to mind while aiming to alter the presentation of our web content is CSS.
CSS stands for Cascading Style Sheets and is a powerful rule-based language for establishing both the aesthetic and structure side of content.
Next.js, being a web development framework, is not a stranger to CSS. Therefore, we can easily incorporate styling in this framework.
Next.js and CSS
Fortunately for us, Next.js provides its users with 5 ways to use CSS within a Next project.
Global CSS: A CSS file that allows us to apply specified CSS globally.
Tailwind CSS: A CSS framework that provides rapid designs by utility classes.
CSS Modules: Local scope CSS classes that solve name concerns and conflicts.
CSS in JS: A new way of embedding CSS within Javascript's components.
Sass: A CSS extension built on top of CSS with a wide range of capabilities.
Among these, Global CSS, CSS Modules, and CSS in JS are three ways that do not require external entities such as Tailwind, etc. We'll be covering these three concepts primarily.
Global CSS
Remember the CSS that we generally add in simple HTML / CSS / JS applications? That is exactly what we're talking about here!
Global CSS refers to CSS styles that can be applied to any component globally anywhere within the application. With this, our main aim is to define styles in a centralized way. A centralized way means the separation of the CSS stylesheet and the rest of the application.
Note: A consistent visual appearance can be achieved through this method.
Code Sample
styles.css file
body{font-size: 20px;margin: 10px;padding: 15px;height: 100vh;}.btn{background-color: white;}
Lines 1–6: We define a
font-sizeof 20 pixels,marginandpaddingof 10 and 15 pixels respectively, and the total height of our main body to be 100% of the view heightvh.Lines 8–10: We add styles to our custom
btnclass. Awhitebackground-coloris assigned to it.
MyButton file
import '../styles.css';export function MyButton() {return(<buttontype = 'button'className = 'btn'>Join Educative here!</button>)}
MyButton2 file
import '../styles.css';export function MyButton2() {return(<buttontype = 'button'className = 'btn'>Check our Educative Courses!</button>)}
Line 1: The first and foremost task we perform is to import the global CSS file in both of our button files. Now, each class mentioned there is accessible in these files.
Lines 3–13: We can now add the
btnclass in any file by simply assigning theclassNamea value ofbtn. The styles applied to thebodywill be visible in both components as well.
Benefits of global CSS
Ease of use due to familiarity
Consistent styling
Application wide usage
CSS modules
Now let's suppose we want to alter our global CSS concept a bit and add modularity to it. We can choose to do this when we aim to practice separation of concerns and solving naming conflicts is pivotal.
Note: Each CSS class we define in a module is scoped only locally to the page it is imported in.
CSS module usage is an approach that gives us the opportunity to write local scope CSS classes, where each content component is bound to a different style component.
Code Sample
MyButton.module.css file
.submitBtn {font-size: 15px;border: 1px solid black;background-color: green;}
Lines 1–5: We define a
font-sizeof 15 pixels, aborderwith a width of 1 pixel,solidlines, andblackcolor. Thebackground-colorof our button is keptgreen.
MyButton file
import styles from './MyButton.module.css';export function MyButton() {return(<buttontype = 'button'className = {styles.submitBtn}>Join Educative here!</button>)}
Line 1: Since we're dealing with modular styling now, we will import the styles specific to the
MyButtonmodule. These are defined inMyButton.module.css. We further use an alias namestylesfor the import so that no naming conflicts occur.Lines 3–13: The
submitBtnin the CSS file is distinguished by using the keywordstyles.submitBtn.
Note: If a class of the same name as 'submitBtn' belongs to another module, say
styles2, usingstyles2.submitBtnwill not lead to any naming concern.
Benefits of CSS modules
Preventing style or name issues
Scoped styling
Better reusability and maintainability
Why don’t CSS modules have naming conflicts?
CSS in JavaScript (JS)
CSS in JS is an approach through which we can involve CSS styling within a JavaScript component. This helps us accomplish dynamic or scoped styling. Instead of separating our styles and component code, we can merge the two and get the best of both worlds.
By dynamic styling, we mean the ability to dynamically generate styles based on the props or state of our application.
Note: These styles can also be changed based on interactions or events.
Code Sample
MyComponent file
function MyComponent() {return (<div><h2>Hello, Next.js!</h2><p>This is some scoped text</p><style jsx>{`h2 {color: green;}div {background: yellow;}@media (max-width: 750px) {div {background: blue;}}`}</style><style jsx global>{`body {background: blue;}`}</style></div>);}export default MyComponent;
Lines 6–7: A few fundamental HTML tags such as a level two heading
h2that says "Hello, Next.js" and a paragraphpthat says "This is some scoped text" are rendered on our page.Lines 9–29: To add a few aesthetics to our content, we can now make use of styling. This way introduces CSS within JavaScript components. For this purpose, we can opt for two further methods.
We enclose our local styling i.e. the styling only applied to the elements of this component within a
<style jsx>tag and then write CSS as it is within the tags. In the example, the styles defined forh2anddivare scoped to the enclosingMyComponentcomponent.Another feature provided by CSS in JS is the
<style jsx global>tag. This is brilliant for also adding styles to the whole HTML and applying them to the whole application. In the example, thebodystyle is defined usingjsx global, which means it will apply to the entire body of the rendered HTML, regardless of the component hierarchy.
Line 31: We export the component so that it can be rendered in other components.
Enabling or disabling Javascript
Users also have the option to disable JavaScript in production. In this case, the styling through CSS still gets loaded.
Benefits of CSS in JS
Dynamic styling
Scoped styling
JavaScript integration
Recap
We have now understood the dynamics of CSS in Next.js, and we highly encourage you to try it out! Lastly, to summarize, we have put forth a condensed view of some notable points for each method.
Key comparisons in built-in CSS options
CSS Modules | Global CSS | CSS in JS | |
Definition | Locally scoped CSS classes. | Applied globally throughout the app. | Embed CSS directly in JavaScript components. |
Pros | Prevents naming conflicts. Improved maintainability. Easy to manage and organize styles. | Familiar for traditional CSS developers. Easy to use and understand. Simple setup and usage. | Dynamic and scoped styling. Ability to use JavaScript features like variables and mixins. Component-based styling with encapsulation. |
Cons | Requires importing and using class names. | Can lead to larger CSS bundles. | Potential performance overhead . |
Learning curve | Extra learning curve for newer users. | Less learning curve but difficult to manage styles as app grows. | Learning curve for new people to CSS in JS solutions. |
Usage | Component-level styling with encapsulation. | Global styles and application-wide styles. | Dynamic styling and complex styling requirements. |
Syntaz | Import styles from './styles.module.css'; | import '../global.css'; | <style jsx> or <style jsx global> |
Pop Quiz on Next.js Styling!
Where is Tailwind an optimal choice?
In naming conflicts
In global scope
In dynamic scope
Quick designs through class names
Free Resources