Can I include scoped css without Vue Loader? - vue.js

For a project where Vue is dropped in, is using style or similar available to components?
Vue.component('vue-sup', {
template: '<div>Sup</div>',
style: '* { color: blue; }'
})
I tried adding the styles inside the template like:
<div>
<style>
.here{}
</style>
<div>Sup</div>
</div>
which didn't work because the template parser detected a tag with side effects

Vue's implementation of scoped css is entirely a feature of vue-loader, and thus only works with compilation. Scoped css momentarily made a debut into Html 5 but saw almost no adoption and was dropped entirely as far as I know. There is the anticipation that "Shadow DOM" may be supported broadly and could be use to add scoped css, but adoption is not there yet either.
So at this point you can add unique classes or ids obviously to a parent container and scope your css that way, but is understandably not what you are asking for nor is it always practical.
The best alternative is a pollyfill. There are several that are available. Here is one by Sam Thorogood and another by Thomas Park but if you do a quick search you will likely discover more.

I came across the same problem and I'm able to insert styling inside Vue template
by creating a component that will dynamically insert a <style> tag on the DOM. This might be impractical like #skribe said but it allows me to have separate CSS from JS without using .vue extension.
You can take a look at this

Related

Exclude Bootstrap styling from certain routes in Vue.js

I have a single-page vue 2 app made with the cli-tool. Most of my routes use Bootswatch (Bootstrap) styling. But one shouldn't at all. This is only a problem because the Bootstrap affects the body and html styles and generally messes with the other styling. The route shouldn't use Bootstrap gets affected even when I #import the Bootstrap in a scoped <style> only to the routes that should use it. This happends if I first visit the Bootsrap routes and then to the isolated one. How should I go about doing this so that one of my routes is completely isolated when it comes to styling? If it's impossible or very impractical, suggest other ways of doing this. If this weren't a single-page-app this would be easy. But I'd prefer it be one.
I succeeded in encapsulating bootstrap import within a class called 'bootstrap-inside' and assigning it to the #app (Index route for example) div that is supposed to be styled with Bootstrap.
.bootstrap-inside {
#import '~bootstrap/scss/bootstrap.scss';
}
From now on, if you want to use bootstrap, you just have to use .bootstrap-inside in your component/view/layout.
I would suggest creating a view layout for your no-bootstrap pages and set your route to extends that layout (i can give you the solution for this too if you want).
I can mention this answer of another thread about limiting the scope of bootstrap styling in case you go through unexpected bootstrap behavior.
The easiest solution I know for this is to manually reset every css property for a given selector.
You could add an id / class to the root element of your page, and explicitly reset all css properties for all its childs. It would override the default bootstrap styles, but not remplacing its classes though.
Here's a class that would reset every css property: reset css for a div #15901030
It's not super convenient but it should work!

My vuetify CSS does not take effect on my project

I am new in vue and vuetify and I read all the documentations in the internet but I still don't know how to inject CSS from vuetify CSS. I have researched some possible solutions, tried to implement what I searched but I realized that the solutions I have found was for Vue 3.9 and below. I am currently using vue 4.0.5 and vue cli 4.0.5. I badly need a solution to this because I am already spending hours looking for workarounds.
I had the same experience in my latest project. Vuetify has some quirks in it that make CSS styling a little different. In general, using <style scoped> will not cause any changes with Vuetify, but using the global scoping <style> will. For some properties, you'll only notice changes if you use the !important tag.
You'll need to make sure you're wrapping everything and using loaders properly to get your CSS working as you intend. Details regarding that are here in detail:
Vuetify - CSS not working (taking effect) inside component

Including partials in components results in duplicate css

I'm trying to make use of the #extend of sass so that I don't mix markup and html together. As explained in this article.
In short, instead of writing
<div class="alert alert-primary>This is an alert!</div>
You'd instead write something like
<div class="banner">This is an alert!</div>
.banner {
#extend .alert;
#extend .alert-primary;
}
Such that styling and content stay nicely separated.
The problem: When using this with webpack (sass-loader) and components (e.g. Vue.js or Angular), I run into a problem where including a bootstrap partial will now result in the complete compilation of the entire bootstrap file into css.
This results into a class .btn[data-v-3614b62c] and another .btn[data-v-45ac961c] etc. for every component that uses the partial bootstrap/scss/_buttons.scss and that for all classes defined in that partial.
Even if I don't use it.
In the long run, this will be detrimental for the application since its size will increase rapidly and I image the browser will slow down with that many css classes to parse.
The question(s): How do I make sure sass doesn't duplicate the entire imported partial?
Can I enable some kind of tree shaking where it only includes the classes I use?
Do I have to change my file structure so that sass understands I only need certain classes inside the partial rather than everything?
Code example
This is a vue component using bootstrap
<template>
<form class="form">
<input type="text" class="input">
<button class="button-submit">Send</button>
<button class="button-cancel">Cancel</button>
</form>
</template>
<style lang="scss" scoped>
#import "node_modules/bootstrap/scss/functions";
#import "node_modules/bootstrap/scss/variables";
#import "node_modules/bootstrap/scss/mixins";
#import "node_modules/bootstrap/scss/root";
#import "node_modules/bootstrap/scss/buttons";
.form {
.button-submit {
#extend .btn;
#extend .btn-primary;
}
.button-cancel {
#extend .btn;
#extend .btn-danger;
}
}
</style>
This will result in the entire partial _buttons.scss to be compiled into css instead of only .form .button-submit and .form .button-cancel.
Live example
https://codesandbox.io/embed/musing-feynman-8w2kx.
To see the problem I have:
Right click on the example to the right and click Inspect
In the Elements tab, navigate to #document > html > head
At the bottom you'll have several style elements
Two of them will contain all the button css where only the [data-v-######] attribute is different and at the end are my couple of lines code.
Note that the same happens for production builds. The css is then simply bundled up in a single file, but duplicates are still around.
If you are #importing the same CSS rules into different components, then you will get the same rules duplicated across all modules. That's just how it works.
You should only be #importing modules that define abstract declarations like variables, mixins, functions, etc, not actual styles.
The only way you can de-duplicate the styles globally is if you use something like mini-css-extract-plugin to extract and combine all the CSS into a single file and then run it through something like cssnano which will discard duplicate rules (although with scoped CSS, this probably won't work).
Modules are typically built independently of other modules and there isn't a simple way to know if a rule has been declared already by a previous module. In development you may be using style-loader which operates on a per-module basis and injects styles into the webpage on demand; there's just no way it can work out which styles should be injected in case some particular style has already been injected by another component.
It just gets messy; keep it simple by not duplicating styles in the first place.
If you really want to use #extend, then make a separate .scss file which is the only module that #imports the bootstrap styles, and define all your extensions in there.

Best way to dynamically change theme of my Vue.js SPA?

So I think the title is enough explaination: I would like to dynamically theme my whole application. Maybe this means to change color of all divs when I press a specific button, or change the whole webapp's colors when a specific user logs in.
Just to give some insights on what I am currently working on I will say that I have built a Vue.js app that uses many libraries, including one called Element-ui which already has a theming option built onto it. The problem is that it's written in scss and I would like to change all the variable colors during the navigation. My project looks something like this:
<template>
... some HTML and components...
</template>
<script>
... some javascript ...
</script>
<style scoped>
... some style that is scoped to the current component only ...
</style>
I have many files like this one so making a "global function" for all of them doesn't seem practical to me. Also I import the main scss file just once in my main.js.
Is there anything I can do to create a dinamic theming for my webapp? Is using saas a good idea? Javascript maybe?
EDIT
I feel like I didn't explain it good enough so I want to add a simple example. If you visit the Element page you can see in the top right corner there is a color selector that, when a color changes, it changes also the whole website's accent colors like the buttons colors, the links colors etc.
Hope this can help understanding a bit better
EDIT
Right now I have settled on a very poor and, I think, badly optimized solution. The idea is that when the user changes theme, I just create a new css file and append it to the current document.
let sheet = document.createElement('style')
sheet.innerHTML = `*[class*="--primary"]{
background-color: ${colors[0]};
}
...`;
document.body.appendChild(sheet);
I truly think this is a very bad solution but right now I can't come up with nothing else that could work dinamically when the user changes a parameter. I would really want the process to be flawless: the user picks a color and the whole application just changes to that specific color, no prebuilt theme.css.
FINAL EDIT
I've finally found a solution, refer to the answer!
Finally, after a few long days I came up with a solution that I think is both easy to implement and very very lightweight.
CSS VARIABLES
Before searching up a lot, I didn't even know the existance of these kind of variables and they don't seem so used. Anyway, I hope this can help someone out there seeking my same answer:
<template
<app-main></app-main>
<app-sidebar></app-sidebar>
...
</template>
<style>
:root{
--primary-color: #C5C5C5!important;
--secondary-color: #6C7478!important;
--tertiary-color: #FFFFFF!important;
--success-color: #80b855!important;
--warning-color: #eaca44!important;
--error-color: #ef4d4d!important;
}
/* Theming */
header{
background-color: var(--primary-color);
}
div{
color: var(--tetriary-colory);
}
...
/* END */
</style>
<script>
import axios from 'axios' /* all your imports etc. */
export default{
data(){
},
methods: {
axios.post(`http://localhost:8080/foo`).then(function (response){
let bodyStyles = document.body.style;
bodyStyles.setProperty('--primary-color', response.colors[0]);
bodyStyles.setProperty('--tertiary-color', response.colors[1]);
...
}
}
}
</script>
As you can see, I just initialize a few useful CSS variables and when I need them (for example in that api post call) I just modify them using a simple bodyStyles.setProperty('propertyName') function.
I really enjoy this type of setup since I use it in my login page so when a user successfully logs-in I load from the database his own colors and set them up just like that.
Hoping this can help someone! Cheers!

How to enable syntax highlighting for embedded LESS styles in WebStorm?

I am using Vue.js for one of my frontend projects.
As you know, Vue comes with special syntax for components - each component can be declared in a single .vue file. That means, that you can define all related stuff in a single file like this:
<tamplate>
...component template goes here...
</template>
<script>
...component code goes here...
</script>
<style>
...component style goes here...
</style>
Of course vue support in various IDEs isn't perfect yet. Vue is relatively young framework, but I think it will be popular very soon. It looks so straightforward and predictable after Angular that I even decide to use it in all upcoming frontend projects, but it is, of course, another story.
Ok, WebStorm doesn't know anything about .vue files, but vue looks like html, so you can solve that problem easely - just add *.vue pattern to list of patterns for HTML file type (settings -> editor -> file types).
After that tweak everything works fine until you try to use non-css styles - for some reasons WebStorm fails to highlight embedded styles with type text/less and so on. I tried to solve it in a different ways:
<style type="text/css></style>
or
<style rel="stylesheet/less"></style>
...but without any success.
Fortunately vue-loader (that I am using with WebPack in order to build my project) supports another syntax of .vue files, which allows to declare template, code and style in a separate files. It is ok, but I think that single file per component is better (at least it's easier to manage). And now I am forced to declare my styles separately because I can't let WebStorm to highlight embedded LESS styles.
I tried to use WebStorm language injections, but without any success too (or I just miss something in my WebStorm configuration).
So, the final question is: how to enable syntax highlighting for embedded LESS styles in WebStorm 11?
Such support is not possible in WebStorm v11/PhpStorm v10 -- only CSS is available as injectable language.
However the next version (WebStorm v12/PhpStorm v11) already supports it -- just use appropriate rel="stylesheet/less" (in case of LESS) attribute on your <style> tag.
If you want to use another attribute or value to identify what language is meant to be used in your <style> tags or enable this for another (already supported by IDE) CSS-preprocessor (e.g. Sass/SCSS/etc) -- create custom injection rule at Settings/Preferences | Editor | Language Injections.
As of 2017.1 version some other improvements/changes were made -- see WEB-20921 : Add support for valid HTML syntax for including LESS/SCSS in <style> tags
ticket for details.