Global styling vs local styling in VueJS - css

I'm building a project with .vue files which make it possible to write the CSS (SASS), JS and HTML in the same file.
I've decided to have some global components written in SASS on a assets/styles/app.scss file which will load my grid, variables and mixins.
On top of that, I want to be able to write some local SASS rules depending the component / page I'm on, seems pretty logical to want both in a project ...
Locally it looks like this:
<template>
</template>
<script>
</script>
<style lang="scss">
#import "assets/styles/app";
.my-style {
color: $my-variable;
}
</style>
It actually works, for instance I can use $my-variable in my local .vue file or any mixin I want. The problem is a VueJS project will grow and components will go together to display a page.
I noticed the global styling was loaded on each component, and the same rule is present in 5x, 10x when I open my chrome developer tool. This is still a very small project; all my styles are basically duplicated and loaded by the browser each time I add a component to the same page.
How do you avoid to load multiple times the global styles, while being able to use global SASS code in each components?
I've never worked with local mixed with global styling before, I preferred to just abstract totally the styling into a separated structure, but this is way more convenient to code with everything local in the same place.
What am I doing wrong here?
Detail: I'm on NuxtJS but I believe this issue is more related to VueJS overall.

Basically, every time you do an #import in your components it appends another copy to the main CSS file that Webpack generates.
Assuming you have the Webpack SCSS loader properly configured (which I believe you do since it compiles), you should be able to import the SCSS file once in your app.vue and the SCSS compiler will find it when it appends all other CSS.
For example, getting global fonts and mixins:
<style lang="scss">
#import url('https://fonts.googleapis.com/css?family=Lato:300,400,400i,700,900&subset=latin-ext');
#import "#/scss/mixins.scss";
</style>
Then create your CSS for each component inside the component's <style> section. Just make sure you add the lang="scss" so it all compiles.
You might also want to look into scss-resource-loader for Webpack. I think this is in the newest CLI builds, not sure about Nuxt.

in App.vue
<style lang="scss">
#import "assets/styles/common.scss";
</style>
OR
import compiled sass to css file in main.js
import './assets/styles/common.css';

Related

Vue 3 CSS files overlapping on component switch

I've imported some CSS files with
<style scoped>#import "../assets/XYZ.css";</style>
in different components. Now whenever I switch components the CSS from the other component is loading as well. Let's say I switch from Home.Vue to Blog.Vue, then Home.Vue's CSS file will be imported into Blog.Vue too. Whenever I refresh, everything seems to be fixed. Adding scoped doesn't seem to work for me.
I am using vue-router to switch between components.
This is my relevant code:
main.js
import './assets/main.css';
^ This is a css file to be used across my website on every component
Home.Vue
<style scoped>#import "../assets/home.css";</style>
Blog.Vue
<style scoped>#import "../assets/blog.css";</style>

Sass #extend to consider imported css during build

I have a global CSS file that contains all generic CSS.
I want to be able to extend all the classes present in this global CSS file in any of my SCSS files.
Right now it throws an error .xyz class does not exist and build fails. I tried importing this file but still build fails.
Adding !options next to class is one way for the build to pass but is there any other better way?
Bit more context for Vue users. I use VueCli3. I use <style lang="scss"> for writing SCSS and want to use extend here. Vue documentation suggesting adding prependData for adding variables. I imported the global CSS in a SCSS file and imported that file in the prependData but Vue build still fails.
It sounds like you want to globally include a CSS file with content that the SCSS blocks in each component can read. (Variables, style definitions, etc).
#extend works like a variable, meaning SCSS needs the definition style to be available as part of its compilation. So that means getting "SCSS Global Variables" working should solve your Extend problem too.
In that case, you need to tweak how Webpack deals with your components. You can do it manually as described here. Or my preference is to use a Vue Cli plugin called vue-cli-plugin-sass-resources-loader. Make sure that your component <style> section contains lang="SCSS" though I assume you're already doing that.
Using #import CSS file into SCSS file not possible to #extend any class.
But you can follow below steps for extends class from your pure css code.
Convert .css file into .scss.
import that global.scss file into another .scss file.
Then after you can use #extend for extend class in new file.
If your file have more then 1k line of code then it will get trouble for extend class.

Angular 2 - Duplicated <style> blocks everywhere

I am using the latest Angular(4) with Angular CLI. I followed the advice found on SO for setting up global scss that is available to components.
Angular-CLI global scss vairables
My structure looks like this
/
styles.scss
/styles
variables.scss
mixins.scss
common.scss
/app
/component1
component1.scss
/component2
component2.scss
The main styles.scss file has the following code
#import './styles/variables.scss';
#import './styles/mixins.scss';
#import './styles/common.scss';
And in my components, I start each component scss file with the statement of
#import '~styles.scss';
I thought that this was the correct way to bring global variables/mixins/common into my component's scss. However, when I started to have components within components, I began to notice that Webpack was actually creating one block per component in the page, and each one of them had all of the global scss written out in them. So there would be one block for component1, with ALL of the variables,mixins,common stuff at the top, and then another block right below that one for the other component2 in the page, with all that information again.
Besides this being extremely inefficient, it means that the global styles are overwritting themselves (can see that in chrome debug) once for each time they are loaded.
Some direction would be very much appreciated.
The <style> tags are normal angular behaviour. Each components SCSS gets written into a <style> element, so there is nothing wrong with that.
The style.scss is for global styles that do not need encapsulation. It also gets written into a <style> element, if you imported it in your angular.json:
"styles": [
    "styles.css"
],
What you are getting wrong is the question you linked (which is still not accepted).
You shouldn't import your already imported styles.scss (apart from variables or mixins) into your components, because this will lead to increasing bundle sizes, as you import the code over and over (which is also the reason for the GitHub issue you mentioned).
You can use the mixins, variables and common.scss simply by including them directly in your components SCSS, just as you need them.
This is basic sass behaviour, you should never import things that result in css several times (sass files imported into component should typically only contain variables, mixins and functions). If you need your import to happen only once, add it to the default styles file.
Look here

Keeping CSS out of JS in Angular 2/Angular-CLI

By default, Angular 2 compiles the CSS into JavaScript, especially when using WebPack as in Angular-CLI. I would rather this not happen for a couple of reasons.
The first reason is that when I'm developing, I find it really helps to be able to see in the developer tools exactly what style sheet a specific style rule was coming from and what line number it was on. The second reason is that I think compiling CSS into the code kind of misses the point of good CSS, which is that you can apply a different style sheet and have an entirely different look and feel with the same markup.
Is there a flag somewhere that I can set to leave the CSS in .css files, where IMO it belongs?
This is the whole point of encapsulated components.
A component should have it's own styles encapsulated with it so it can be shipped with the styles.
Imagine you want to publish one of your components to be used by others, shouldn't it have its own styles with it ?
That means Angular needs a way to link those css to the component , thus seperates them into chunks and injects them into head tag.
To solve your problem though , you have couple of options :
1- Not using the Emulated Encapsulation :
Components by default have a property called encapsulation which is set to Emulated , you need to change it to None:
#Component({
encapsulation:ViewEncapsulation.None
})
Then , you can put all you css in the head tag your self like you'd do with a normal html page.
2- If the problem is theme ing , you can make your component themeable .
You can have a theme attribute for your component and then based on that change the styleing :
#Component({
selector:'my-component',
styles:[
`
:host{
[theme="blue"]{
change what ever you want :
h1{
color:blue;
}
}
}
`
]
})
And then , using this component would be like :
<my-component [attr.theme]='"blue"'></my-component> // would be blue theme
<my-component></my-component> // would be default
Go to your base Html file(where the root module, main app is injected) and link the CSS stylesheets in your header section.
Webpack will not include it in it's compiled/combined css file which is injected into the page. The css file will still be included at run time in the browser.
<html>
<head>
<base href="/">
<meta charset="utf-8">
<title>dummy</title>
<meta name="viewport" content="width=device-width">
//was not injected/modified by webpack
<link rel="apple-touch-icon" sizes="57x57" href="app/images/apple-icon-57x57.png">
//webpack's injected this below from other components's imported/inline css rules
<link href="index-c2cacb5fa3dfbca6116f4e4e63d5c3c7.css" rel="stylesheet"></head>
With angular-cli 1.6.5 you can do this:
ng serve --extract-css
You will still have the style-encapsulation features, but devtools will now point to the component css source file.
I use the angular-cli as well (v1.0.0-beta.22). When I am ready to build for production I run the following command:
ng build -prod -aot
This generates all my production-ready files (bundled, tree-shaken and minified etc). Of particular note is that it will generate two versions of the style sheets.
One in js:
styles.b2328beb0372c051d06d.bundle.js
And another version is plain css:
styles.4cec2bc5d44c66b4929ab2bb9c4d8efa.bundle.css
I run some post-processing on the css file with gulp and use the css version for my production build. I am not sure if the same holds true for lazy loading (where the cli will produced different chunks), but it works for sure when lazy loading is not being used (I haven't launched a production-ready project yet with lazy loading).
I also tried a build with JiT compilation:
ng build -prod
It also produced the raw/minified version of the css style sheet.
Now, I know for sure the folowing does NOT work:
ng build
This will produce all the css embedded within js file, styles.bundle.js.
Since you want to use the raw css file during development, the only workaround I can think of is that you run ng build -prod in order to get the css file. Copy/paste this manually into your assets folder. Run "format" on the file to un-minify the file. Then do a normal build with a modified index.html file referencing your raw css file, and removing the styles.bundle.js script reference. Not pretty, but it might work.
Put a wrapper class in html example-
<div class="component-1-wrapper">
all yout html here inside component-1-wrapper
</div>
Structure your sass(scss) in the following way. Since your styles are wrapped inside component-1-wrapper, therefore it will apply only to component-1-wrapperclass
.component-1-wrapper{
// all the styles for component-1 here
.class-hello{
// styles
}
}
You can compile your css with sass and put all the css(seperated by modules) in seperate folder.Start the filenames by _, sass can import them:
You can refer your styles-main.scss in app.ts file
#component({
styleUrls:['styles/styles-main.scss']})
The style-sheets will be structured this way and individual component's class styles will be applied to particular component since there is a wrapper class in html
Hope it helps!!!!!!

Why do the styles appear embedded on inspect element in Angular 2

I downloaded a free HTML theme named dashgum from the internet. I'm implementing it for an Angular2 application using angular-cli. I converted the css files to .scss and pasted the code to the angular application. I then imported the files in the global styles file named styles.scss to apply the styles to the application like this:
#import url('./scss/bootstrap.scss');
#import url('./scss/font-awesome/css/font-awesome.scss');
#import url('./scss/zabuto_calender.scss');
#import url('./scss/gritter/css/jquery.gritter.scss');
#import url('./scss/lineicons/style.scss');
#import url('./scss/style.scss');
#import url('./scss/style-responsive.scss');
The problem that I'm facing during debugging is that all the styles appear as embedded styles in the browser like this (notice the style tag):
I want the style to appear as external styles while inspecting like in the theme. Please notice it in the following screenshot:
These are the default settings in Angular 2 as I made no apparent changes for the styles to appear embedded when inspecting. Is there any known way to change the settings in Angular 2 for the styles to appear as external styles when inspecting? The embedded styles make it harder for me to debug. Any help pointing out towards the solution would be appreciated.
My first advice (like official Angular CLI documentation says) is to put your global library inside .angular-cli.json like this:
...
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.min.css",
"styles.scss"
],
...
Then just run the app with the --extract-css parameter to see in the browser inspector the source files:
ng serve --extract-css
And you will have this:
I have learned that the styles imported in the global styles.scss file always appears embedded when inspecting in the browser. If we want the css to appear as external styles, we will have to use it in components.
Edit:
See toioski's answer above.

Resources