Best way to have global css in Vuejs - css

What is the best way to have a global css file in Vuejs for all components? (Default css like bg color, button styling, etc)
import a css file in the index.html
do #import in main component
put all the css in the main component (but that would be a huge file)

Import css in your index.html, but if you're using webpack you can just import your stylesheets in your main js config and all your components will get the css.
As comments below suggested if using webpack adding this to main.js works:
import './assets/css/main.css';

I found the best way is to create a new file in the assets folder, I created as global.css but you can name anything of your choice. Then, import this file global.css file in the main.js.
Note: Using this approach you can also create multiple files if you think the global.css is getting really large then simply import all those files in the main.js.
#\assets\global.css
/* move the buttons to the right */
.buttons-align-right {
justify-content: flex-end;
}
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './routes'
Vue.config.productionTip = false
// Importing the global css file
import "#/assets/global.css"
new Vue({
router,
render: h => h(App)
}).$mount('#app')

In App.vue you can add a style property to declare you CSS file:
<style>
#import './assets/css/global.css';
</style>

You can also do something like this: https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/
My folders are mostly structured like this:
- src
- assets
- _global.scss
- _colors.scss
- _fonts.scss
- _paragraphs
- index.scss // <-- import all other scss files.
This also works with normal css.

create a new css file in your assets folder for example : global.css
import "global.css" to main.js
import '#/assets/main.css';

There are to two ways, as I know, to achieve this.
Approach 1
Utilize vue.config.js configuration, less config can also be replaced with sass:
module.exports = {
css: {
loaderOptions: {
less: {
additionalData: `#import '#/style/common.less';`
}
}
}
}
Approach 2
In your .vue file, make your style looks like this:
<style lang="less">
#import (reference) "../../style/variables.less";
#app {
background: #bgColor;
}
</style>
Note: the (reference) flag is used to make variables defined in variables.less take effect. If you don't have variables, #import "../../style/variables.less"; is sufficient to do the trick.
For your reference, you can also take a look at this link:
https://github.com/tjcchen/vue-practice/tree/master/multipage-app

Sass announced their new module system. Why don't you use #use and #forward?
My approach is the best way to use scss with vite.
Use defineConfig to setup global scss (colors, mixin) and reuse in all component without import
css: {
preprocessorOptions: {
scss: {
additionalData: `#use "~/styles/main.scss" as *;`,
},
},
},
Here: code sandbox

create a vue.config.js file in your root directory
Create a styles folder inside your src folder and you can create your global style file here for example base.scss
to use scss install two dependencies
npm install node-loader sass-loader
Inside your vue.config.js paste code from below
module.exports = {
css: {
loaderOptions: {
sass: {
additionalData: `#import "#/styles/base.scss";`
}
}
}
};

Related

Next.JS: Using SASS variables from global scss

I have a Next.js Application with a main.scss global css file imported in the pages/_app.js file.
_app.js
import '../global-styles/main.scss'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
The styles from this file work.
I also have some modular scss files attached to components, using [component].module.scss.
I have written a variable in my variables.scss file, one of the files which I #import in main.scss,
variables.scss
$mobile: 750px;
main.scss
#import './fonts.scss';
#import './variables.scss';
#import './global.scss';
However, when I try to use this variable in one my modular css, I get an error
./module-styles/navbar.module.scss (./node_modules/css-loader/dist/cjs.js??ref--5-oneOf-3-1!./node_modules/postcss-loader/src??__nextjs_postcss!./node_modules/resolve-url-loader??ref--5-oneOf-3-3!./node_modules/sass-loader/dist/cjs.js??ref--5-oneOf-3-4!./module-styles/navbar.module.scss)
SassError: Undefined variable: "$mobile".
on line 19 of /Users/Parv/Documents/reactx/module-styles/navbar.module.scss
>> #media (max-width: $mobile) {
---------------------------^
My question is, why aren't my global variables which I declare in my main.scss coming through?
the easier way is to add a file with variable import and add alias to tsconfig
sassOptions: {
includePaths: ['./src'],
prependData: `#import "~#styles/variable.scss";`,
}
Update:
In file next.config.js need add this code (you need to create it if there is no such file)
module.exports = (phase, {defaultConfig}) => {
if ('sassOptions' in defaultConfig) {
defaultConfig['sassOptions'] = {
includePaths: ['./src'],
prependData: `#import "~#styles/variables.scss";`,
}
}
return defaultConfig;
}
In file tsconfig.json need add alias
"baseUrl": ".",
"paths": {
...
"#styles/*": [
"src/styles/*"
],
...
Then create file with styles on path: src/styles/variable.scss in variable.scss you can import other scss file
It is not related to Next.js, but to the way sass-loader works.
Each import of scss file from js file is treated as an isolated sass env, therefore, there is no such thing "global variables".
This behaviour requires you to import the variables.scss file from each scss file that uses one of the variables.
Side note, It is important that these common scss files (such your variables.scss) will not contain "regular" css, because if so, they will be duplicated many times (the amount of imports).
Just add this to your next.config.js file and restart
const path = require('path')
module.exports = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
prependData: `#import "main.scss";`
}
}
Apparently you can only import variables from a module file, not a global file.
Import variables.scss into your module's SCSS file, then import your variables from your module:
variables.scss:
$my-color = #123456;
:export {
myColor: $my-color;
}
page.module.scss:
#import './variables.scss';
page.jsx:
import color from './page.module.scss'
console.log(color.myColor); // '#123456'
This worked for me.
I solve it by adding my global variables to next.config.js. It is not a good solution but it works.
module.exports = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
prependData: `
$primary-font-regular: 'Gotham';
$primary-font-medium: 'Gotham';
$default-font-size: 16px;
$h1: 5.208vw;
$h4: 1.458vw;
$primary-color: #000000;
$gray: #CCCCCC;
`,
},
};
You can follow this link for the answer: https://github.com/vercel/next.js/pull/12277

Next.js Global CSS cannot be imported from files other than your Custom <App>

My React App was working fine, using global CSS also.
I ran npm i next-images, added an image, edited the next.config.js, ran npm run dev, and now I'm getting this message
Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.js.
Read more: https://err.sh/next.js/css-global
I've checked the docs, but I find the instructions a little confusing as I am new to React.
Also, why would this error happen now? Do you think it has anything to do with the npm install?
I've tried to remove new files I've added along with their code, but this doesn't fix the problem. I've also tried what the Read more: suggests.
My highest tier component.
import Navbar from './Navbar';
import Head from 'next/head';
import '../global-styles/main.scss';
const Layout = (props) => (
<div>
<Head>
<title>Bitcoin Watcher</title>
</Head>
<Navbar />
<div className="marginsContainer">
{props.children}
</div>
</div>
);
export default Layout;
My next.config.js
// next.config.js
const withSass = require('#zeit/next-sass')
module.exports = withSass({
cssModules: true
})
My main.scss file
#import './fonts.scss';
#import './variables.scss';
#import './global.scss';
my global.scss
body {
margin: 0;
}
:global {
.marginsContainer {
width: 90%;
margin: auto;
}
}
The thing I find the weirdest is that this error came without changing anything to do with CSS, or Layout.js, and it was previously working?
I've moved my main.scss import to the pages/_app.js page, but the styles still aren't coming through. This is what the _app.js page looks like
import '../global-styles/main.scss'
export default function MyApp({ Component, props }) {
return <Component {...props} />
}
Use the built-in Next.js CSS loader (see here)
instead of legacy #zeit/next-sass.
Replace #zeit/next-sass package with sass.
Remove next.config.js. Or do not change CSS loading in it.
Move the global CSS as suggested in the error message.
Since Next.js 9.2 global CSS must be imported in Custom <App> component.
// pages/_app.js
import '../global-styles/main.scss'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
To add styles only to a specific component or page you can use built-in support of CSS modules. (see here)
For example, if you have a component Button.js you can create a Sass file button.module.scss and include it in the component.
Next.js stops complaining when your file has module in naming, e.g., changing import '../global-styles/main.scss'; to import '../global-styles/main.module.scss'; would fix the warning and you could have your styles in the global-styles, or for example, in your component.
No extra dependencies/configurations in next.config.js is required.
You can replace the opinionated (and overly-complex?) NextJs CSS loaders with your own. Here's a simple one for global css:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
reactStrictMode: true,
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Find and remove NextJS css rules.
const cssRulesIdx = config.module.rules.findIndex(r => r.oneOf)
if (cssRulesIdx === -1) {
throw new Error('Could not find NextJS CSS rule to overwrite.')
}
config.module.rules.splice(cssRulesIdx, 1)
// Add a simpler rule for global css anywhere.
config.plugins.push(
new MiniCssExtractPlugin({
experimentalUseImportModule: true,
filename: 'static/css/[contenthash].css',
chunkFilename: 'static/css/[contenthash].css',
})
)
config.module.rules.push({
test: /\.css$/i,
use: !isServer ? ['style-loader', 'css-loader'] : [MiniCssExtractPlugin.loader, 'css-loader'],
})
return config
},
}
Add this to your _app.js
import '../styles/globals.css'
For me the problem was because I had used two module.exports in my next.config.js file like this
const withPlugins = require('next-compose-plugins')
const sass = require('#zeit/next-sass')
const css = require('#zeit/next-css')
const nextConfig = {
webpack: function(config){
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[ext]'
}}
})
return config
}
}
module.exports = withPlugins([
[css],
[sass, {
cssModules: true
}]
], nextConfig)
module.exports = {
env: {
MONGO_URI = 'your uri'
}
}
. 1I modified it to change the export module like this.
const nextConfig = {
webpack: function(config){
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[ext]'
}}
})
return config
},
env: {
MONGO_URI: "your uri"
}
}
2then I deleted the second module.exports
This node package provides a perfect solution for it. You can find it here
Steps to fix it:
1. Add package:
npm install next-remove-imports
or
yarn add next-remove-imports
2. Add this wrapper variable inside your next.config.js
const removeImports = require('next-remove-imports')({
test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/,
matchImports: "\\.(less|css|scss|sass|styl)$"
});
All it is doing is re-enabling global styling import rule for tsx|ts|js|mjs|jsx files
3. Wrap your next config export with this next-remove-imports wrapper. Something like this:
module.exports = removeImports((nextConfig)
4. Now restart your react app and you will be able to import CSS files inside any ts|js|js|jsx|mjs file or component.
Try to include ".module" in your scss file name.
Change main.scss to main.module.scss
Example:
import styles from './todolist-profile-info.module.scss'
You did not need to do anything inside of next.config.js.
Let's assume you are using a global css like Bootstrap, meaning it contains css that is meant to be applied to your entire application and all the different pages inside of it.
Global css files have to be wired up to NextJS in a very particular fashion.
So inside of the pages/ directory you need to create _app.js.
It's critical that the file be named _app.js.
Then at the top of that file you would import Bootstrap css in the following manner:
import 'bootstrap/dist/css/bootstrap.css';
Then you would add the following:
export default ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
So what is going on in that code?
Well, behind the scenes, whenever you try to navigate to some distinct page with NextJS, NextJS will import your component from one of the different files inside your pages/ directory.
NextJS does not just take your component and show it on the screen.
Instead it wraps it up inside of its own custom default component and that is referred to inside of NextJS as the App.
What you are doing by defining the _app.js is to define your own custom app component.
So whenever you try to visit a route inside a browser or your root route, NextJS is going to import that given component and pass it into the AppComponent as the Component prop.
So Component there is equal to whatever components you have in the pages/ directory. And then pageProps is going to be the set of components that you are intending to pass to your files inside of pages/.
So long story short, this thing is like thin wrapper around the component that you are trying to show on the screen.
Why do you have to define this at all?
Well, if you ever want to include some global css to the project, Bootstrap being a global css for example, you can only import global css into the _app.js file.
It turns out that if you try to visit other components or other pages, NextJS does not load up or even parse those files.
So any css you may have imported inside there will not be included in the final HTML file.
So you have a global css that must be included on every single page, it has to be imported into the app file because it's the only file that is guaranteed to be loaded up every single time a user goes to your application.
Don't forget that in addition to importing the css inside of _app.js, you also have to run an npm install bootstrap in your terminal.
You can read more on this here:
https://nextjs.org/docs/messages/css-global
For me, i got this error because I had used improper naming for my project's parent folder, had used special characters in it,
like project#1,
after removing special chars, and changing the folder name to like project-1, the error got away.
In my case there was typo in navbar.module.css
I've written navbar.moduile.css
you must for every component css/scss write navbar.module.css/scss/sass.Next js doesnt compile navbar.css/scss/sass. If hope my answer helps you !.

Vuejs .vue file: dynamic less import

I have a Vue app composed of several standard .vue files like this:
<template>
<h1>My App</h1>
</template>
<script>
export default {
name: 'app',
data () {
return {
cssTheme: 'default-theme'
};
}
}
</script>
<style lang="less">
#import "assets/constants";
html, body {
color: #color-ui-text;
}
</style>
In my assets/constants.less file I have defined many css variables to be used by less (colours, fonts and so on).
I want to give my app a serie of graphical "themes" that can be changed dynamically.
Given the variable cssTheme that I can read / set / change from the interface (and set it to strings like "green-theme", "vintage-theme", "default-theme"), how can I import and apply on the fly the appropriate less file into the <style> part of the .vue file? For instance, the user selects the "green-theme" and I want to switch the default imported file #import "assets/constants"; to #import "assets/constants-green"; where, for example, #color-ui-text; is set to dark green instead of the standard black.
If you use vue cli, you can use something like this:
module.exports = {
css: {
loaderOptions: {
sass: {
data: `
#import "assets/constants";
`
}
}
}
};
It will automatically add #import "assets/constants"; in each sass file
Note: i use sass in example
more about this you can find here:
loaderoptions

CSS className isn't making any changes to Reactjs

I'm currently working with rails and reactjs. I'm having difficulties using css in my reactjs files. It seems like every time i try to use it, no change is being applied at all. In my App.jsx file I have this:
import React from "react";
import styles from "./styles.css";
export default class Register extends React.Component {
render() {
return (
<div className={styles.container}>
<h1> this text should appear to the right </h1>
</div>
);
}
}
And in my styles.css file I have this:
.container {
width:40%;
text-align:right;
}
For the record I am using webpack. Can anyone help me understand why the css isn't having any effect on my jsx components. I've looked all over for help but was unable to put the pieces together.
If it matters, this is how my "config/webpack/development.js" file looks like:
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
It depends on the webpack loader settings. If you are using css-loader as configured in react-scripts (as of 1.1.5), then the classNames are loaded using {modules: false} option, i.e. global styles, which can be referenced as strings in JSX code:
import "./styles.css";
... className="container" ...
Or you can load local styles using following CSS-file syntax:
:local .container {...
Or edit your webpack.config.js appropriately (see https://github.com/webpack-contrib/css-loader#scope for the official documentation of various options).
seems like you didn't enable an option { modules: true } for css-loader in webpack config
take a look
webpack-contrib/sass-loader#206
https://github.com/webpack-contrib/css-loader#options
Taken from: https://github.com/facebook/create-react-app/issues/1350

sass converting import to import url

New to sass and grunt. All my vendor related css files are in _vendor.scss.
#import "public/css/bower_components/bootstrap/dist/css/bootstrap.css";
this converted to
main.css
#import url(public/css/bower_components/bootstrap/dist/css/bootstrap.css);
i want it to be
#import "public/css/bower_components/bootstrap/dist/css/bootstrap.css";
instead of url how to do it .
cause next i want to use cssjoin to concatinate all import css into one file and cssmin using grunt.
folder structure
public ---> scss --->vendor-> _vendor.scss
public ---> css ---> bower_components --> ......
public ----> css ---> main.css
grunt tasks
sass: {
dist: {
files: {
'public/css/main.css': 'public/scss/main.scss'
}
}
},
autoprefixer: {
dist: {
options: {
map: true
},
files: {
'public/css/main.css': 'public/css/main.css'
}
}
},
watch: {
css: {
files: '**/*.scss',
tasks: ['sass', 'autoprefixer']
}
},
That's because apparently SASS treats CSS imports differently from SCSS imports. If you #import 'some/file.css', it will be compiled to #import url(some/file.css) because SASS wants to keep your original CSS import intact (while ironically altering it in a standard manner).
However, if you change the extension your CSS files to .scss and import them as such in your main file, the SASS compiler will do its thing and include their contents in place of the original import rule. It simply works because regular CSS syntax is also valid SCSS syntax, and it tricks the compiler into treating your import rule as an SCSS import.
Also, there seems to be no reasonably easy way to alter this behavior and apparently it's not going to change any time soon based on this ticket open since 2012 that's slowly filling up with workarounds for this exact problem.
Hope this helps!

Resources