How to isolate Vuetify global styles - css

I've started to use Vue.js with Vuetify within an old existing project. So I did not rewrite all frontend, I just imported Vue and replaced some parts.
And then I've noticed quite an unexpected behavior - Vuetify has global styles for common classes like .title and it effects the whole page, not only Vue part.
So, the questions is, how can I isolate vuetify styles inside Vue components?
UPD: As suggested #DigitalDrifter I tried to use stylus block-level import. So I removed
import 'vuetify/dist/vuetify.min.css'
from main.js and created a new .styl file (which was imported instead css) with the following content:
.vuetify-styles
#import '~vuetify/src/stylus/main'
And then added this class to the root component: <App class="vuetify-styles">
UPD2: After that you can get bug related to stylus compilation. More about it -> https://github.com/vuetifyjs/vuetify/issues/4864
UPD3: less also works fine for me.
# vuetify-styles.less
.vuetify-styles {
#import (less) '../../node_modules/vuetify/dist/vuetify.min.css';
}
And then just import it in your main.js
import './vuetify-styles.less'

Stylus supports block level imports.
If you've got the following:
// bar.styl
.bar
width 10px
// foo.styl
.foo
#import 'bar.styl'
The end result will be:
.foo .bar {
width: 10px;
}

Related

Can't access global SASS variables from my component

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.

How can I use a third party CSS library in an Angular component's CSS without duplicating the library?

I have a two components that both rely on effects from hover.css. Both components have SASS files that (simplified) look something like this:
#import '~hover.css/scss/hover';
.some-class a {
#include underline-from-left;
}
Additionally, I have the hover.css library included in my global styles in style.css:
#import '~hover.css/scss/hover';
.some-global-class {
#include some-other-mixin-from-hover;
}
This all works and compiles fine, except for the rather large fly in the ointment that I end up with full hover.css in my compiled application three times - once in styles.js and twice in main.js (once for each component). This is obviously not a sustainable pattern.
If I don't #import hover.css in my components though, Angular won't compile them because they reference a mixin that can't be found. I've tried deep linking just the effects I need from hover.css but that's a hornet's nest because those files have downstream dependencies on other parts of the hover library. This obviously isn't specific to hover, but any scenario in which you'd want to import and use a vendor library in an Angular component's CSS file without duplicating the library.
Any ideas?
What do you have on your hover.scss file? Is it only mixins or other CSS as well? If you only have mixins then you should be fine, if you have some CSS then it will get taken. For example:
This would not cause repetition:
#mixin underline-from-left {
text-decoration: underline;
}
If you have something like this, then the span block will be repeated as many times as you would import it:
#mixin underline-from-left {
text-decoration: underline;
}
span {
display: block;
}
Perhaps an idea is to separate mixins from actual CSS, and then import only the mixins file.

Not entirely sure where am I supposed to write my CSS in a Vue SPA

Up until now, I've always used a single CSS file when creating multiple page applications which would store all my CSS rules.
Now that I'm using Vue.js and components, I am not sure where to write my CSS.
I could write the CSS in the <style></style> tags of a component but to me this only makes sense if the CSS is only used for this specific component. This leaves me wondering where should I write CSS which I would like to be applied globally to everything.
Imagine I have some CSS which I want to be applied to everything like this snippet:
*, *:after, *:before {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-decoration: none;
}
Where would I write it?
Until a better solution I can offer two suggestions:
1. In App.vue file
If it's just a small amount of code, put it in your App.vue file
As you said:
"I could write the CSS in the tags of a component but to me this only makes sense if the CSS is only used for this specific component."
If you put CSS in the in the <style></style>in any .vue files that's part of your project it's going to be global.
<style></style> get's applied to the whole project unless you add scoped to the tag.
<style scoped>
body {
background: green; /* This won't effected your main <body> tag unless you actually have a `<body>` inside the `<template>` of that file */
}
</style>
2. Import a separate file containing only CSS (updated and easier)
From #Fabjan in the comments.
Just import the .css file in your main.js file:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './assets/lib/css/reset.css' // my own reset file
import './assets/lib/css/myMain.css' // global stylesheet
Make sure to put it before your run your app. new Vue({})
(3. My previous answer:)
You can create a styles.vue and add all your global styles there inside <styles></styles> without scoped. (this worked for me)
Then inside your main.js file you write:
import GlobalStyles from "./assets/lib/css/styles.vue"
Vue.use(GlobalStyles)
Make sure your styles.vue contains at least on tag inside for it to import properly.
<template>
<div class="empty">
</div>
</template>
<style>
body {
background: red;
/* The rest of your Global CSS code */
}
</style>
This feels really tacky but it worked for me now.
Hope it helps and I'd love some feedback or comments if people have better solutions.
Here is my solution to configure global scss with my project that using Nuxt.
Assume that you already have node sass and sass-loader installed.
In nuxt.config.js file add your SCSS path from static or assets folder
css: [
'#/assets/scss/main.scss'
]
Bonus: if you don't like this way maybe you can get a try nuxt-sass-resources-loader

using css modules, how can I import classes from a file

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;
}

Import css/scss file into a class

I have a problem. I'm using vaadin inside liferay. I've successfully written a fully responsive (yeah, tables too) theme for vaadin, based on bootstrap. Now I'm importing it to liferay. Everything went fine 'till I needed to upgrade Liferay, where their new responsive theme is using same classes name as bootstrap, but with different behaviour (sad, very sad face).
The solution I've thought so far is to apply a class to the vaadin compiled css, like:
.daVaadinTheme {
#import bootstrap.css;
}
so the content will be compiled like:
.daVaadinTheme h1.insideTheFile{
}
.daVaadinTheme h2.insideTheFile{
}
But, as you may figured out, is not obviously working.
Do you have any solution?
Read carefully! This is NOT a duplicate of the answer you've posted. I'm trying to import a CSS file inside a CSS/SCSS class of another file, like the example I've written above. My problem is not to simply import a CSS file inside another one...
SOLUTION: (kudos to Mathias Jørgensen)
using #import from another scss file:
in test.scss:
.daVaadinTheme{
#import "bootstrap.scss";
}
Name your inner file with an underscore, and ending in scss. .Yes, even if it's plain css, i.e. foo.css → _foo.scss
Have an outer File like so:
#main .content { // if that's, where you want them to rule only
#import 'foo';
}
Reasons:
import only works with scss
underscore-files are glady skipped by sass (also as in gulp.src(<some wildcards).sass())
if you have no influence in your repo about the css filename whatsoever. or it's a major pain on upgrades, consider using a symbolic link under an .scss extension...
You need move your code into mixin:
// botstrap.scss
#mixin bootstrap {
h1.insideTheFile{
}
h2.insideTheFile{
}
}
Then, you can import normal:
// test.scss
#import "bootstrap"; // No extension
#include bootstrap; // The name of "mixin"
or with context:
// test.scss
#import "bootstrap"; // No extension
.daVaadinTheme {
#include bootstrap; // The name of "mixin"
}
If you want to add certain styles to a class using sass/scss I think what you're looking for is
.myClass { #import bootstrap.css; }

Resources