VUE component ignoring CSS - css

I have the following VUE component:
<template>
<div>
<div class="bottom-footer">
{{msg}}
</div>
</div>
</template>
<script>
export default {
name: 'LayoutFooter',
data () {
return {
msg: 'my test'
}
},
mounted () {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.bottom-footer {
height: 200px;
background-color: #A7BFE8;
}
</scoped>
VUE is completely ignoring my scoped CSS. When page is rendered its simply not applied. There are no console errors. Ive tried removing the scoped attribute and its still ignored. Any ideas why VUE is doing this?

<style scoped>
.bottom-footer {
height: 200px;
background-color: #A7BFE8;
}
</style>
you need to close style

Related

Can you set custom height to a custom component in vue3?

If you have a custom component with a div in it can you set the custom height outside of the component file?
For example:
If I have a "BaseCard" component in my App.vue file can I set the height there? If not, is there any way to have multiple "BaseCard" components, all with different heights?
You could add a prop to the component and then a computed property which saves the height in a css variable.
So where you import the component:
<BaseCard :height="80vh"/>
And in the BaseCard.vue component:
<template>
<div id="base-card" :style="cssVars"></div>
</template>
<script>
export default {
props: ['height'],
computed: {
cssVars () {
return{
'--card-height': this.height,
}
}
}
<script>
<style scoped>
#base-card{
height: var(--card-height);
}
</style>

CSS variables use in Vue

Is it possible to use pure CSS variables with Vue without having to link any stylesheets or use SASS/PostCSS? Unsure why I'm unable to get this to work in its most basic form.
<template>
<div id="test">
TEST
</div>
</template>
<style scoped>
:root {
--var-txt-color: #c1d32f;
}
#test {
color: var(--var-txt-color);
}
</style>
I know you highlighted "without having to link any stylesheet", but I run into the same issue and there is a simple option - use just one external css file and include it in your App.vue, then you can access the variables anywhere else, in scoped styles as well.
variables.css
:root {
--font-family: "Roboto", "Helvetica", "Arial", sans-serif;
--primary-color: #333a4b;
}
App.vue
<style>
#import './assets/styles/variables.css';
</style>
LandingView.vue
<style scoped>
#landing-view {
font-family: var(--font-family);
font-weight: 300;
line-height: 1.5em;
color: var(--primary-color);
}
</style>
This won't work as expected because of scoped attribute for stylesheet. Example above compiles into:
[data-v-4cc5a608]:root {
--var-txt-color: #f00;
}
And, as you understand, it will not target actual :root element.
It can be solved by:
Not using scoped attribute for this stylesheet. Notice that it may cause styles conflict with other variables declarations for :root element.
Using current component's wrapping element as root. If we declare variables this way:
.test {
--var-txt-color: #c1d32f;
color: var(--var-txt-color);
}
.test-child-node {
background-color: var(--var-txt-color);
}
Then it will can reuse variables for other elements of the same component. But still, it won't be possible to use declared variables inside child components without removing scoped, if it is the case.
Why not just use this?
<style scoped>
* {
--var-txt-color: #c1d32f;
}
</style>
The generated CSS is:
*[data-v-d235d782] {
--var-txt-color: #c1d32f;
}
This has been working for me.
I just discovered that it looks like this also works, using the "deep selector"
>>> {
--var-txt-color: #c1d32f;
}
Generated CSS is:
[data-v-d235d782] {
--var-txt-color: #c1d32f;
}
I think I like this method more.
One workaround is to define them under a non-scoped style element like the following. However one thing to note here is, these variables will be exposed to other Vue components as well.
<style>
:root {
--var-txt-color: #c1d32f;
}
</style>
<style scoped>
#test {
color: var(--var-txt-color);
}
</style>
Late answer - Here is a working example with css vars derived from standard vue structures.
<template>
<div>
<component :is="'style'">
:root {
--color: {{ color }};
--text-decoration: {{ textDecoration }};
--font-size: {{ fontSize }};
}
</component>
<p>example</p>
</div>
</template>
<script>
export default {
props:{
color: {
type: String,
default: '#990000'
}
},
data: function () {
return {
textDecoration: 'underline'
}
},
computed: {
fontSize: function (){
return Math.round(Math.random() * (5 - 1) + 1) + 'em';
}
}
}
</script>
<style>
p{
color: var(--color);
text-decoration: var(--text-decoration);
font-size: var(--font-size);
}
</style>
Starting from the top...
Vue must have 1 root element, so I needed a div tag in order to include a sample p tag. However, you can just use the component-is-style tag and get rid of the div and p tags. Note the need for extra quotations "'style'".
The normal vue style tag can be scoped or not - as needed.
Well, now you can use CSS variable injection.
<template>
<div>
<div class="text">hello</div>
</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
font: {
weight: '800'
}
}
}
}
</script>
<style>
.text {
color: v-bind(color);
font-weight: v-bind('font.weight');
}
</style>
Those styles are also both reactive and scoped. There won't be any unintended inheritance issues. Vue manages the CSS variables for you.
You can take a look at the RFC here.

Vue.js dynamic <style> with variables

Is it possible to add the dynamic variable in style?
I mean something like:
<style>
.class_name {
background-image({{project.background}});
}
#media all and (-webkit-min-device-pixel-ratio : 1.5),
all and (-o-min-device-pixel-ratio: 3/2),
all and (min--moz-device-pixel-ratio: 1.5),
all and (min-device-pixel-ratio: 1.5) {
.class_name {
background-image({{project.background_retina}});
}
}
</style>
I faced the same problem. I have been trying to use a background color value from a database. I find out a good solution to add a background color value on inline CSS which value I set from database.
<img :src="/Imagesource.jpg" alt="" :style="{'background-color':Your_Variable_Name}">
With Vue.js 3.2 you can do State-Driven Dynamic CSS like this:
<template>
<h1 id="script">Script</h1>
<h1 id="scriptSetup">Script setup</h1>
</template>
<script>
export default {
data() {
return {
colorFromScript: 'red'
}
}
}
</script>
<script setup>
const colorFromScriptSetup = 'green'
</script>
<style>
#script {
color: v-bind('colorFromScript')
}
#scriptSetup {
color: v-bind('colorFromScriptSetup')
}
</style>
See an implementation here
The best way to include dynamic styles is to use CSS variables. To avoid inline styles while gaining the benefit (or necessity—e.g., user-defined colors within a data payload) of dynamic styling, use a <style> tag inside of the <template> (so that values can be inserted by Vue). Use a :root pseudo-class to contain the variables so that they are accessible across the CSS scope of the application.
Note that some CSS values, like url() cannot be interpolated, so they need to be complete variables.
Example (Nuxt .vue with ES6/ES2015 syntax):
<template>
<div>
<style>
:root {
--accent-color: {{ accentColor }};
--hero-image: url('{{ heroImage }}');
}
</style>
<div class="punchy">
<h1>Pow.</h1>
</div>
</div>
</template>
<script>
export default {
data() { return {
accentColor: '#f00',
heroImage: 'https://vuejs.org/images/logo.png',
}},
}
</script>
<style>
.punchy {
background-image: var(--hero-image);
border: 4px solid var(--accent-color);
display: inline-block;
width: 250px; height: 250px;
}
h1 {
color: var(--accent-color);
}
</style>
Also created an alternate more involved runnable example on Codepen.
CSS <style> is static. I don't think you can do that... you might have to look for a different approach.
You can try using CSS variables. For example, (the code below is not tested)
<template>
<div class="class_name" :style="{'--bkgImage': 'url(' + project.background + ')', '--bkgImageMobile': 'url(' + project.backgroundRetina + ')'}">
</div>
</template>
<style>
.class_name{
background-image: var(--bkgImage);
}
#media all and (-webkit-min-device-pixel-ratio : 1.5),
all and (-o-min-device-pixel-ratio: 3/2),
all and (min--moz-device-pixel-ratio: 1.5),
all and (min-device-pixel-ratio: 1.5) {
.class_name {
background-image: var(--bkgImageMobile);
}
}
</style>
Note: Only the latest browsers support CSS variables.
If you still see any issues with the :style in the template then try this,
<div :style="'--bkgImage: url(' + project.background + '); --bkgImageMobile: url(' + project.backgroundRetina + ')'">
</div>
As you are using Vue.js, use Vue.js to change the background, instead of CSS:
var vm = new Vue({
el: '#vue-instance',
data: {
rows: [
{value: 'green'},
{value: 'red'},
{value: 'blue'},
],
item:""
},
methods:{
onTimeSlotClick: function(item){
console.log(item);
document.querySelector(".dynamic").style.background = item;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
<div id="vue-instance">
<select class="form-control" v-model="item" v-on:change="onTimeSlotClick(item)">
<option value="">Select</option>
<option v-for="row in rows">
{{row.value}}
</option>
</select>
<div class='dynamic'>VALUE</div>
<br/><br/>
<div :style="{ background: item}">Another</div>
</div>
Yes, this is possible. Vue.js does not support style tags in templates, but you can get around this by using a component tag. Untested pseudocode:
In your template:
<component type="style" v-html="style"></component>
In your script:
props: {
color: String
}
computed: {
style() {
return `.myJSGeneratedStyle { color: ${this.color} }`;
}
}
There are lots of reasons why you shouldn't use this method. It's definitely hacky and :style="" is probably better most of the time, but for your problem with media queries I think this is a good solution.
Vue 3 State-Driven Dynamic CSS Variables
I know this is a bit late and is using Vue.js 2, but as of now in Vue.js 3 you can create state-driven CSS variables.
You can now use your SFC (Single File Component) state data inside your styles tags using v-bind().
You can read more about state-driven CSS variables here, or read the Vue.js 3 documentation here.
Here is a code example
Example
<template>
<div>
<input type="text" v-model="color" />
<div class="user-input-color">
{{ color }}
</div>
</div>
</template>
<script>
export default {
data: () => ({
color: 'white'
})
}
</script>
<style scoped>
.user-input-color {
background-color: v-bind(color)
}
</style>
Here is a link to the live example.
Links
JS Now Vue state-driven CSS variables
Vue.js 3 Docs
Live Example
You can use the component tag offered by Vue.js.
<template>
<component :is="`style`">
.cg {color: {{color}};}
</component>
<p class="cg">I am green</p> <br/>
<button #click="change">change</button>
</template>
<script>
export default {
data(){
return { color: 'green' }
},
methods: {
change() {this.color = 'red';}
}
}
</script>
I encountered the same problem and I figured out a hack which suits my needs (and maybe yours).
As <style> is contained in <head>, there is a way to make it work:
We generate the CSS content as a computed property based on the state of the page/component
computed: {
css() {
return `<style type="text/css">
.bg {
background: ${this.bg_color_string};
}</style>`
}
}
Now, we have our style as a string and the only challenge is to pass it to the browser.
I added this to my <head>
<style id="customStyle"></style>
Then I call the setInterval once the page is loaded.
mounted() {
setInterval(() => this.refreshHead(), 1000);
}
And I define the refreshHead as such:
methods: {
refreshHead() {
document.getElementById('customStyle').innerHTML = this.css
}
}
In simple terms, this is how you would do it in Vue.js and Nuxt.js:
<template>
<div>
<img :src="dynamicImageURL" alt="" :style="'background-color':backgroundColor"/>
</div>
</template>
<script>
export default{
data(){
return {
dynamicImageURL='myimage.png',
backgroundColor='red',
}
}
}
</script>
I needed to write completely dynamic styles, so I used approach beyond Vue system:
{
// Other properties.
watch: {
myProp: {
handler() {
this.styleElement.innerHTML = this.myProp.css;
},
deep: true,
},
},
mounted() {
this.styleElement = this.document.createElement('style');
this.styleElement.innerText = this.myProp.css;
this.document.head.append(this.styleElement);
},
unmounted() {
this.styleElement.remove();
},
}
Though it may have some performace issues with CSS big enough.
I liked #mickey-mullin reply, but not everything worked entirely. The url missed require, even though the information in his post helped me a lot in my case.
var(), url(), multiple ternary operators (my own case - you shouldn't need it), I was able to do so for background-image in such a way:
template
<div :style="[
case1 ? { '--iconUrl': `url(${require('../../../public/icon1.svg')})`} :
case2 ? { '--iconUrl': `url(${require('../../../public/icon2.svg')})`} :
{ '--iconUrl': `url(${require('../../../public/default.svg')})` },
]" class="myClass">
styles
div.myClass::before {
background-image: var(--iconUrl);
}
Note: I didn't have to declare iconUrl in my data() -> return.

In vue.js component, how to use props in css?

I'm new to vue.js. Here is my problem:
In a *.vue file like this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: ?
}
<style>
How can I use the props color in background-color: (where is a ? now).
Thanks.
You actually can!
You should define the CSS variables in a Computed Property, then call the computed property as a style attribute to the element that will require the CSS variable, and finally you may use the variable within the tags at the bottom of your document.
new Vue({
el: '#app',
data: function() {
return {
baseFontSize: 1,
bgHoverColor: "#00cc00",
hoverContent: "Hovering!"
}
},
computed: {
cssProps() {
return {
'--hover-font-size': (this.baseFontSize * 2) + "em",
'--bg-hover-color': this.bgHoverColor,
'--hover-content': JSON.stringify(this.hoverContent)
}
}
}
})
div {
margin: 1em;
}
div.test:hover {
background-color: var(--bg-hover-color);
font-size: var(--hover-font-size);
}
div.test:hover::after {
margin-left: 1em;
content: var(--hover-content);
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app" :style="cssProps">
<div>Hover text: <input type="text" v-model="hoverContent"></div>
<div>Hover color: <input type="color" v-model="bgHoverColor"></div>
<div class="test">Hover over me</div>
</div>
Or have a look here: https://codepen.io/richardtallent/pen/yvpERW/
And here: https://github.com/vuejs/vue/issues/7346
You don't. You use a computed property and there you use the prop to return the style of the div, like this:
<template>
<div id="a" :style="style" #mouseover="mouseOver()">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color'],
computed: {
style () {
return 'background-color: ' + this.hovering ? this.color: 'red';
}
},
data () {
return {
hovering: false
}
},
methods: {
mouseOver () {
this.hovering = !this.hovering
}
}
}
</script>
<style scoped>
<style>
As we are in 2020 now, I suggest using this trick with a css function called var
<template>
<div id="a" :style="cssVars"></div>
</template>
<script>
export default {
props: ['color'],
computed: {
cssVars () {
return{
/* variables you want to pass to css */
'--color': this.color,
}
}
}
<script>
<style scoped>
#a{
background-color: var(--color);
}
</style>
This method is very useful because it allows you to update the passed values through css later on (for example when you apply hover event).
credit
I know we're talking vue 2 here, but in case anyone from vue 3 lands in this question (like I did), vue 3 introduced a much cleaner way to do this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: v-bind(color);
}
<style>
What Vue actually does behind the scenes is the same "introducing css variables through component's style process", but it sure looks much better on the eyes now.
Documentation source: https://v3.vuejs.org/api/sfc-style.html#state-driven-dynamic-css
Why not just use :style prop in this way:
<template>
<div :style="{ backgroundColor: color }">
</template>
<script>
export default {
props: {
color: {
type: String,
default: ''
}
}
}
</script>
Make sure you define css properties in camelCase style.
If you need css that can't be applied by a style attribute like pseudo classes or media queries, what I do is the following:
Create a globally available style component when initializing Vue (you need it as otherwise you run into linting issues). It creates a style tag that simply renders the content in the slot:
I would only use this if you really need both dynamic values in your css and css features that can't be applied to a style attribute.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
Vue.component('v-style', {
render: function(createElement) {
return createElement('style', this.$slots.default)
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Then use it at the top of your template like this and you get the full JavaScript scope of your component and the full css syntax combined:
<template>
<v-style>
#media screen and (max-width: 820px) {
.gwi-text-media-{{ this.id }} {
background-image: url({{ mobileThumb }});
}
}
</v-style>
</template>
It seems a bit hacky to me, but it does it's job and I would rather go like this in some cases than having to add additional JS for mouse-over or resize events that have a big potential to slow down your application performance.
Vue 3 added new way of binding styles, so now you can easily bind your props to css properties.
Read source:
https://learnvue.co/2021/05/how-to-use-vue-css-variables-reactive-styles-rfc/
<template>
<div>
<div class="text">hello</div>
</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
You could utilise the CSS var(--foo-bar) function. It is also useful if you are trying to pass an asset that has its own dynamic path, like Shopify does.
This method also works for styling the :before and :after elements as they refer back to the style applied on the owner element.
Using the original post example for passing a colour:
<template>
<div
id="a"
:style="{ '--colour': color }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: var(--colour);
}
</style>
Using the original post example for passing an URL:
<template>
<div
id="a"
:style="{ '--image-url': 'url(' + image + ')' }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['image']
}
</script>
<style scoped>
#a {
background-url: var(--image-url);
}
</style>
Source

Preventing fancybox returning to top of page

In my website, I am using fancybox 2.1.5. when I open an image and close it I return to the top of the page unintentionally. The problem can be seen in the following minimal example
<!DOCTYPE html>
<head>
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
<link rel="stylesheet" type="text/css" href="css/jquery.fancybox.css?v=2.1.5" media="screen" />
</head>
<body>
<a href=#>
<img src="http://placehold.it/1000x600">
</a>
<a class="fancybox" href="img/Gallery/500x600.gif">
<img src="http://placehold.it/500x600">
</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.fancybox.js?v=2.1.5"></script>
<script>
$(document).ready(function() {
$('.fancybox').fancybox();
});
</script>
</body>
</html>
You will see that if you open and close the second image you will find yourself at the top of the page.
It appears that if I delete the initial style in the head
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
The problem disappears. if I erase only the body style or the html style the problem also disappears. In order for the problem to appear both body and html heights must be to 100%
Unfortunately I don't understand why this is happening. Can someone please explain?
Note: I have found solutions and hacks to this problem but I would like to understand why this is happening
Update: seems not to work if you trigger the Fancybox while on a URL that points to a tag with an ID (e.g., "https://example.com/#currentsection"). When you exit the Fancybox, it doesn't go to the top of the page, but does scroll to the top of the tag with the ID, even if you've set the autoFocus and placeFocusBack options to false. Strangely, it still works if your URL is pointed at #top.
Original answer
I found that when using Fancybox in Next.js, binding or configuring Fancybox with autoFocus set to false fixed this. It then seems that placeFocusBack property (default: true) will apply. Set it up like so:
npm install --save #fancyapps/ui
components/fancybox-wrapper.js:
// Fancybox UI wrapper for lightbox
// Thanks to https://fancyapps.com/docs/ui/fancybox/react
import React, { useEffect } from "react";
import { Fancybox as NativeFancybox } from "#fancyapps/ui/dist/fancybox.esm.js";
function Fancybox(props) {
const delegate = props.delegate || "[data-fancybox]";
useEffect(() => {
const opts = props.options || {};
NativeFancybox.bind(delegate, opts);
return () => {
NativeFancybox.destroy();
};
}, []);
return <>{props.children}</>;
}
export default Fancybox;
pages/_app.js:
import Fancybox from "../components/fancybox-wrapper";
import "#fancyapps/ui/dist/fancybox.css";
import { SSRProvider } from "#react-aria/ssr";
function MyApp({ Component, pageProps }) {
return (
<SSRProvider>
<Fancybox options={{ infinite: false, autoFocus: false }}>
<Component {...pageProps} />
</Fancybox>
</SSRProvider>
);
}
export default MyApp;
You can use native helper of fancy box to fix returning to top of page problem.
$('.fancybox').fancybox({
padding: 0,
helpers: {
overlay: {
locked: false
}
}
});
reference : http://davekiss.com/prevent-fancybox-from-jumping-to-the-top-of-the-page/

Resources