I use Symfony + Webpack Encore and try to split styles into "layout" and "page-based", but only to make development more comfortable: I still want to compile one css file for them (in fact, there is a limited number of such css files, each one for block of pages, but for easier understanding let's assume only one is necessary). So I do like this:
_global.scss
// ... bootstrap variables redefenition here
#import "~bootstrap/scss/bootstrap";
// ... common functions, mixins, font-face definitions here
.my_style1 {
padding-left: 12px;
padding-right: 12px;
}
.my_style2 {
#include make-container-max-widths();
}
app.css
#import "_global"
// other styles here
During the compilation (require('../css/app.scss'); only in my app.js) styles are ordered: [ global, bootstrap, app ] and I don't understand why. I mean, if you use them as:
<div class="container my-style1"></div>
container's padding will override defined in my-style1.
The most strange thing is that in dev app.css they are ordered as expected (my-style is lower than container), but in prod not (container is lower than my-style). When you work in dev (and Chrome display non-compiled styles, you also see that _grid.scss overrides _global.scss)
Sorry for this quick self-answer, I've really spent a lot of time before asking, but after it found the solution quickly. Hope, can save smb's time.
You should simply add other styles to app.js. This way they will recompile on any file change (in previous example they recompile only on app.scss change) and the order will become correct:
app.js
require('_global.scss');
require('app.scss');
Related
In my Nuxt app I load all my SASS thus:
css: [
'~assets/scss/main.scss'
],
It works perfectly, except when I'm trying to use some SASS variable from within a component.
<style lang="scss">
.container {
background-color: $white;
}
</style>
In this case I get this error message:
SassError: Undefinied variable: $white
Yet, all of the SCSS contained in the SASS file where the variable is defined works throughout the app.
It is as if the app as a whole knew these files, but each individual component doesn't.
What's going on?
Most of the other answers don't take into account that Nuxt.js hides all the Webpack setup and forces you to do everything through nuxt.config.js.
My guess is that Webpack isn't compiling all the SCSS declarations together and therefore can't find the variable.
It's been a few months since I had this issue so things may have changed but here goes...
Make sure you have the correct Node packages installed (Nuxt DID NOT do this by default for me) npm i -D node-sass sass-loader
Add your CSS & SCSS files to the css: [] section of nuxt.config.js Order matters here so make sure things like variables are added before things that use them if you have separate files.
If you're using layouts (I think that's the default Nuxt setup) make sure that layouts/default.vue has a <style lang="sass"></style> block in it. If I remember correctly this can be empty but had to exist. I only have one layout but it may need to exist in all of them.
If all that seems like too much of a pain, there's a Nuxt Plugin that takes most of the work/management out of that process. Nuxt Style Resources Module
The confusing part is that:
styles from scss files CAN be loaded like this
//nuxt.config.js
css: [
'~assets/scss/main.scss'
],
//global scss file
$varcolor: black
h1{background: $varcolor}
BUT
the variables inside CAN NOT be used inside a component
//inside component
.component {background: $varcolor} // DOES NOT WORK
I also suggest the use of the nuxt style resource module:
https://github.com/nuxt-community/style-resources-module
new founded solution, checked and it's work. Founded here
add #nuxtjs/style-resources
export default {
css: [
'vendor.min.css'
],
modules: [
'#nuxtjs/style-resources'
],
//You will have to add this new object if it doesn't exist already
styleResources: {
scss: ['./assets/scss/main.scss'] // here I use only main scss with globally styles (variables, base etc)
},
}
it's strange, but if u change tilda (~) to dot(.), it's help for someone
from css: [ '~assets/scss/main.scss' ] to css: [ './assets/scss/main.scss' ]
this solution finded here
Us should either load the scss in your component
<style lang="sass">
#import 'path/to/your/_variable.scss'; // Using this should get you the variables
.my-color {
color: $primary-color;
}
Or adding the following to you to your vue.config.js
module.exports = {
css: {
loaderOptions: {
sass: {
data: `#import "#/pathto/variables.scss";`
}
}
}
};
Ref:
SassError: Undefinied variable: $white
Each <style lang="scss"> is compiled individually. You need to #import the file which defines $white into your component before the parser knows what $white means.
This is why most frameworks keep their variables in a _variables.scss file which is imported in all the other SCSS files/contexts.
The _variables.scss is not even loaded in the page, because in most cases it doesn't actually contain any rules. It only contains variable definitions which are imported into other .scss files, which output .css.
Ref:
Yet, all of the SCSS contained in the SASS file where the variable is defined works throughout the app.
If you import an SCSS file in your vue.config.js the output will be an ordinary <style> tag. Its contents will be generated at compile/build time and will result into some CSS (which apply to the entire document).
Unless specifically imported into the component SCSS, (using an #import command), the compiler will not know what $white means.
There is an important distinction to make between compilation context and browser context. Compilation happens at compile time (most likely in node-sass). Browser context is the actual browser, which only understands the CSS resulted from compilation.
How does Vue only apply style rules to the parent and not to the children with the same class? That's achieved by scoping.
It means applying a custom data-v-{key} attribute to all selectors in the generated <style> tag and to all elements the style should apply to.
See this example and inspect it using your web console: https://codesandbox.io/s/vue-template-ge2hb
It produces this markup:
As you can see, the scoped CSS has an extra [data-v-763db97b] added to the selector, which means it only applies to elements having that data attribute.
I have a weird issue with Vue.js CLI production bundling where I cannot quite pinpoint the root cause and I appreciate some help.
I have a Vue CLI 3 application with the following (relevant extract) in my main.js:
// Bootstrap
import "#/assets/bootstrap/bootstrap.scss";
import "bootstrap-vue/dist/bootstrap-vue.css";
import BootstrapVue from "bootstrap-vue";
Vue.use(BootstrapVue);
// Toastr
import Toastr from "vue-toastr";
import "vue-toastr/dist/vue-toastr.css";
Vue.use(Toastr, {
defaultPosition: "toast-bottom-right"
});
Running this in my dev environment (npm run serve) CSS works fine.
When I run this after the production complilation (npm run build) some classes... are not applied and I cannot reason why. Given that the only difference I can see is the bundling process, I'm incline to look for an issue in that direction.
I customized the bundling as follow (relevant extract) in my vue.config.js:
cacheGroups: {
icons: {
name: "icons",
test: /[\\/]node_modules[\\/](#fortawesome)[\\/]/,
chunks: "all",
priority: 3
},
vendors: {
name: "vendors",
test: /[\\/]node_modules[\\/]/,
chunks: "all",
priority: 1
}
}
And, as result, my CSS bundled are correctly created as follows:
a vendor chunk that includes the Toaster CSS.
This includes a 'toaster' class and a 'toaster-info' class (this latest has just a background-color)
a app chink that include my custom built bootstrap CSS.
As much as the bootstrap files are in the node_modules folder and, as such, they should go in the previous chink, they get in here because I'm compiling them as import in a the SASS file above that actually comes from by code.
This includes a 'toaster' class again.
Now, what I can see is that:
both chunks appear to be loaded by the browser
the markup correctly uses the 'toastr toastr-info'
only the 'toaster' class from app (bootstrap) is applied
the 'toaster' and 'toaster-info' class are totally ignored by the browser and the background color from 'toaster-info' is not applied
I tested this with several browsers to exclude any specific browser weirdness.
Browser computed styles shows that the classes are "excluded" for some reason I don't understand (with "excluded" meaning are in the style tree but strikethrough).
Can anyone help me understand why this is happening?
Thank you.
This is purely a CSS problem.
Since your app and vendor CSS defines a .toast class style, whatever is loaded last is given the highest specificity.
I'm assuming all you're trying to do is change the default .toast background colour to white (instead of black) but you want to leave the more specific classes like .toast-info, .toast-success, etc as they are.
To do so (without altering the vendor files), you can change your .toast definition to...
.toast:not(.toast-info),
.toast:not(.toast-success),
.toast:not(.toast-warning),
.toast:not(.toast-error) {
background-color: rgba(255, 255, 255, .85);
}
If you're using a pre-processor like Sass (which I think you are), this can be written more succinctly.
Ideally, the vendor files should have defined their styles like...
.toast {
background-color: #030303;
}
.toast.toast-success {
background-color: #51a351;
}
which would give the "info", "success", etc styles a higher specificity than the .toast class but it doesn't look like they do. Perhaps you could create a pull-request π
I'm wondering if there's a grunt plugin that can compare two files and remove duplicates from one of them.
Example: if both blog.css and main.css contain the rule .button { color: red; } I'd like to remove that rule from blog.css. (main.css should always remain unchaged)
Background:
I've got two LESS-bundles, main.less and blog.less, which I compile into main.css and blog.css
The idea is that my site should load main.css on every page. On blog pages I'll load both both main.css and blog.css.
The problem is that these LESS-files share a few "utility"-files (with variables, mixins and some common classes like .button)
So I end up with blog.css containing duplicates of some rules which are already defined in main.css, and I'd like to get rid of those duplicates to reduce file size.
Found it
https://www.npmjs.com/package/grunt-csscss
csscss: {
dist: {
src: ['css/x.css', 'css/y.css']
}
}
Allthough in my case the solution was actually much simpler. Turns out LESS now has import ("reference") which will import a file to use as a dependency only, without outputting any of it's css.
So now I can use import ("reference") commonstuff.less in blog.less and thus none of the styles from commonstuff.less will be output to blog.css! :)
I am using css modules for my project, and I have a file positioning.css which has some useful classes that I want to import. e.g. .right, .left
What is the best approach for this using CSS Modules?
At the moment I can see 2 options, but they are not all that great:
composition in the component's style
.right {
composes: right from '../styles/positioning.css';
}
or
multiple css module imports in the component
import positioning from '../styles/positioning.css'
import styles from './myComponent.css';
Object.assign(styles, positioning)
class Menu extends Component {
render() {
return (
<div styleName='menu'>
<div styleName='left'>this is left</div>
<div styleName='right'>this is right</div>
</div>
);
}
};
export default CSSModules(Menu, styles);
I have manage to get this working:
// css file
#value class-to-compose from "file-where-class-is-defined.css";
.someclass {
composes: class-to-compose;
// other styles
}
One approach is to collect all app level css variables and calculations at the top level into app.css
#import "./theme/layout.css";
#import "./theme/colors.css";
...
Then reference app.css using
#import "../../app.css";
This way you can manage #import scope inside one file at the root level.
I'll go with the first proposition. (the result is quiet the same)
both proposition have quiet the same result
If someday you have to edit your Menu css, you'll just have to edit your Menu css and not your component.
You let CSSModules take decisions. (more futur proof?)
You could import the css files that you use frequently into a broader CSS file that you import on specific pages, this is taking the second approach but making it cleaner, especially if you have a lot of common core css files that you import on pretty much all pages.
I would advise you to go with [Sass] [1]. Sass allows for the usage of partials (i.e. distributed / scoped css sheets).
You write scoped (to the components you want) css and import all your partials into your main.css then.
Couple of other advantages:
you can do theming by having one partial that defines your them via variables, which you import first and then all your partials can use these variables.
having the css on a scoped level (at least to me) felt more "reactish" where components are supposed to be stand alone, but it also wasn't inline styling, which I find ugly and weird (I don't like to clutter down my .js files with styles)
[1] http://sass-lang.com/
I find this one line very helpful with importing:
#import 'file.css';
You could set these as globals and update their names to be a tad more semantic, like BootStraps pull-right.
If you declare them as
:global(.right) {
/* ... */
}
You can then just use them in your app by preferably importing globals early on in the entry point.
You should take a look at the option by vue.js component (scoped/overall)
You can choose a precompile css language like SASS, which can use #extend ...etc to reuse the common property, like below:
%common {
width: 100%;
height: inherit;
}
.my-class {
#extend %common;
}
I'm relatively new to SASS and bootstrap. I use bootstrap with SASS and struggle a little bit with a concept.
I always used CSS like this: one base CSS-file with the basic layout (eq. base.css). Every template includes additionally a different CSS-file (eq. sitemap.css, team.css, news.css). This CSS-files only contain the parts of the respective templates. So I can overwrite the definitions in the previous files.
In SASS everything is compiled in one file. In combination with bootstrap I actually struggle with the concept I used until now.
Every time I want to add a new CSS-file to the existing definitions, I get an error because I have to reinclude the complete bootstrap structure. But if I reinclude it, the whole bootstrap code gets written into the additional files (eq. sitemap.css, team.css, news.css) too. If I include both files in my HTML-tree, the bootstrap definitions (like the whole normalize block) gets defined two or more times.
I have this setup:
- css
|-- source
| |-- base.scss
| |-- team.scss
| |-- vendors
| | |-- bootstrap...
β-- output
|-- base.css
β-- team.css
In base.scss I include the bootstrap stuff. I do also need the bootstrap stuff in team.scss, but not all the main stuff like the normalize things.
How do I achieve that? Is that even possible or do I have to switch my css needs by adding a css-class to the body tag (like body.team)? But then I have to carry the whole CSS stuff of every page in one file. Isn't this crab?
Edit to clear things up a bit:
This is in base.scss:
#import "settings/vars";
#import "vendors/bootstrap";
...
header {
#extend .container;
...
.contentbox {
margin-top: $mainGap;
}
...
}
...
and this is in team.scss:
header .contentbox {
#extend .sr-only;
}
It's absolutely clear that "#extend .sr-only;" doesn't work in team.scss because of the absence of bootstrap. But if I include bootstrap with
#import "vendors/bootstrap";
in the first line of team.scss, I would automatically add all the standard 16kb bootstrap things to team.css as well. However, these definitions are already in base.css. So I would have a preventable overhead.
I think I know there is no way to say: "Hey bootstrap. I already included you in base.scss. So you don't have to write the whole main definition of yourself into team.scss again. But I need you because I like you as an usable framework. So please provide me the functions and variables anyway.". But perhaps?
What I do in this case is to compile base.scss with Bootstrap and all the base code and my customized _variables.scss. Then if I want to add team.scss I just import the mixins and the custom variables that I will need to use from Bootstrap. Sounds great!
but...
Since .sr-only and other are just provided as classes instead SASS mixins, you can't #include it, like you could do with the .transition mixin for example.
So, for the moment if you are using SASS, you have 2 options:
Import the Bootstrap module with the class you want to extend/reuse
//contain the .sr-only definition
#import "vendors/bootstrap/_scaffolding";
#import "vendors/bootstrap/_variables";
header .contentbox {
#extend .sr-only;
}
Copy/Paste the class from the Bootstrap source and extend it:
#import "vendors/bootstrap/_variables";
// Copy/Paste the .sr-only class to reuse, very un-DRY
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
border: 0;
}
header .contentbox {
#extend .sr-only;
}
What you're searching for is named a partial in Sass I guess:
If you have a SCSS or Sass file that you want to import but donβt want to compile to a CSS file, you can add an underscore to the beginning of the filename. This will tell Sass not to compile it to a normal CSS file. You can then import these files without using the underscore.
For example, you might have _colors.scss. Then no _colors.css file would be created, and you can do
#import "colors";
and _colors.scss would be imported.
FYI, in LESS it'd be an import option: #import (reference) "colors"