I am trying to smooth transition between background linear gradients in vue js
Previously when I created this transition effect using plain js / HTML / css - i created a div for each color and just changed there opacity - fading one out to another
(you can see the effect i am trying to create here, just nav between different languages to see the effect) https://littleleo.dev/
in vue js -
the nav invokes a function when clicked (which gets the nav id)
<Navbar :articleData="articleData" #backgroundColor="background"/>
background(f) updates a watched property - using a list of colors
methods: {
background(id){
let bg_id = id-1 // -1 so the number is inline with the array starting at 0 not 1
this.backgroundColor = this.backgrounds[bg_id]
}
data(){return{
backgroundColor: null,
backgrounds:
[
'linear-gradient(45deg, #e96443, #904e95)',
'linear-gradient(45deg, #3a7bd5, #3a6073)',
'linear-gradient(45deg, #f7ff00, #db36a4)',
'linear-gradient(45deg, #B24592, #F15F79)',
'linear-gradient(45deg, #FFB75E, #ED8F03)',
'linear-gradient(45deg, #673AB7, #512DA8)',
'linear-gradient(45deg, #fc00ff, #00dbde)',
'linear-gradient(45deg, #00C9FF, #92FE9D)',
],
and the magic happens here: where the background is changed
// changes background color
watch: {
backgroundColor: function(){
document.querySelector('.topElements').style.background = this.backgroundColor
}
}
So currently this happens with no transition time between the background colors changing - i was wondering if anyone knew how to transition without creating a overlay div for each of the colors &/or there is some clever vue js magic that can solve this type of issue:
further details:
this is in App.vue and my template looks like this:
<template>
<div id="app">
<div class="topElements" :class="[noneSelected]"> // <<< COLOR APPLIED HERE
<!-- animation -->
<lottie :options="defaultOptions" :height="350" :width="350"/>
<Navbar :articleData="articleData" #backgroundColor="background"/>
<span class="breaker"></span>
<transition name="content-holder">
<router-view :key="$route.path"/>
</transition>
</div>
<Footer />
</div>
</template>
the background color is being applied to everything inside of the class="topElements"
any help or suggestions would be amazing -
thanks in advance -
Wally
As vue.js documentation says, the best way to make a similar effect is using absolute positioning.
https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes
This is the best way to deal with it.
Most tricks wich get the same effect has a much bigger code and it is not the right way.
To understand how vue.js transition works please visit https://alligator.io/vuejs/understanding-transitions/
https://medium.com/#msanathkumar/understanding-transitions-and-animations-in-vuejs-115a0f5c6fbc
Related
Currently I'm trying to add an animation to a page of a few shooting stars flying across the screen. I want the star to appear and end at certain percentages of the available screen to make it responsive and visible on any device. However when I try to do this, my values seem to default to 0px rather than the percentage that I am passing into my tailwind.config.js from my React Component. The values work if I pass in pixels, but as I mentioned, I would rather do percentages so that it can work well on any screen.
Currently, I am passing in my desired percentage values using this method with an alteration to make it React compatible like this:
style={{"--startingX":props.startingX}}
I am currently using NextJS and TailwindCSS to attempt to make this.
Here are (what I believe are) the relevant files:
/components/shootingStar.js
export default function ShootingStar(props) {
return (
<div>
<div style={{"--percentage":props.startingX}} className="absolute animate-star">
<div className="transform absolute top-2/4 ..."></div>
<div className="absolute top-full left-2/4 ..."></div>
</div>
</div>
)
}
animation: 'star' is the animation in question, inside of keyframes I created my custom animation.
tailwind.config.js:
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
fontFamily: {
'Quicksand': ['Quicksand', ...defaultTheme.fontFamily.sans],
},
'animation': {
...
star : "star 3s linear infinite"
},
'keyframes': {
...
star: {
'0%' : {
transform : 'translateX(var(--percentage)) translateY(0px) rotate(235deg)',
'opacity': '50%'
},
'75%' : {
'opacity' : '100%'
},
'100%' : {
transform : 'translateX(350px) translateY(500px) rotate(235deg)',
'opacity' : '0%'
}
}
}
},
},
plugins: [],
}
index.js
return (
//This div is the parent div to the whole page which is why I included it.
<div className="bg-gradient-to-tl from-blue-900 to-black overflow-x-auto h-screen w-screen ">
<ShootingStar startingX={'25%'} startingY={'25%'} endingX={'500px'} endingY={'500px'}</ShootingStar>
{The remaining shooting stars would eventually get created here}
</div>
...
)
When the animation is at 0%, I would like my star component to start at a specified X% of my screen (for example if I pass in 25% to my percentage var, I would like it to start 1/4 of the way into the screen from the left hand side of the window.)
If this is possible, I plan to expand this for the starting Y value and the ending values of X & Y as well which is why I have those props passed in.
If I pass in 25% to my percentage var, my starting value is at the top left of the screen (or 0). and allows the animation to run. If I try to hardcode percentage values into my Keyframe animation, the animation does not occur since all of the values are technically defaulting to 0.
I am expecting the animation to start at 1/4 of the way in from the left hand side.
I feel as if I'm doing something slightly wrong that won't allow me to make this animation possible but I am not entirely sure what that would be.
I figured out why my animation was stuck in the top left after further research. Keyframe animations take the height and width specifications of the component that is being animated, and do not inherit their parent's height or width (as I initially thought they did). Because I had not specified a height or width for my component it could not move across the screen as I originally wanted it to.
For anyone who might run into this as I did make sure you are setting the height and width of your components to allow your animation to go through your component. Otherwise, if you want it to run through your entire viewport, use vh rather than % when setting your animation values.
Regardless, I decided to opt for viewport since it better fits my use case.
I have a simple HeadlessUI Tab component like the one below.
import { Tab } from '#headlessui/react'
function MyTabs() {
return (
<Tab.Group>
<Tab.List>
<Tab>Tab 1</Tab>
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab>
</Tab.List>
<Tab.Panels>
<Tab.Panel>Image content 1</Tab.Panel>
<Tab.Panel>Image content 2</Tab.Panel>
<Tab.Panel>Image content 3</Tab.Panel>
</Tab.Panels>
</Tab.Group>
)
}
I would like to smoothly change the view (in this case, each Tab.Panel content) when I click the tab menu.
When I looked into the official example, there was no description of how to handle the transition like fade-in.
I know there is a tailwind fade-in & delay & transition animation CSS tag, but I am unsure where to add that tag so the headlessUI Tabs work smoothly.
Any code example is appreciated!
Use transitions provided from headlessui:
import { Transition } from '#headlessui/react'
Example:
import { Transition } from '#headlessui/react'
import { useState } from 'react'
function MyComponent() {
const [isShowing, setIsShowing] = useState(false)
return (
<>
<button onClick={() => setIsShowing((isShowing) => !isShowing)}>
Toggle
</button>
<Transition
show={isShowing}
enter="transition-opacity duration-75"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity duration-150"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
I will fade in and out
</Transition>
</>
)
}
Animating transitions
By default, a Transition will enter and leave instantly, which is probably not what you're looking for if you're using this component.
To animate your enter/leave transitions, add classes that provide the styling for each phase of the transitions using these props:
enter: Applied the entire time an element is entering. Usually you define your duration and what properties you want to transition here, for example transition-opacity duration-75.
enterFrom: The starting point to enter from, for example opacity-0 if something should fade in.
enterTo: The ending point to enter to, for example opacity-100 after fading in.
leave: Applied the entire time an element is leaving. Usually you define your duration and what properties you want to transition here, for example transition-opacity duration-75.
leaveFrom: The starting point to leave from, for example opacity-100 if something should fade out.
leaveTo: The ending point to leave to, for example opacity-0 after fading out.
Reference : Create top-down slide animation using `Transition` from `#headlessui/react` using Tailwind CSS
The same problem as this post except it is Vuetify.
Is there any solution that use provided API? CSS would be the last option I choose.
codepen demo
<template>
<v-app-bar app dark absolute class="navbar-bg" >
<v-app-bar-nav-icon #click="toggleSidebar" />
<v-toolbar-title>Homepage</v-toolbar-title>
</v-app-bar>
</template>
Currently, there's no a single prop in API.
But you may help yourself a lot with a built-in vuetify classes and directives.
First of all, you (sadly) need to write some CSS to manually disable initial page scrolling:
html {
overflow-y: hidden;
}
.scrollable {
overflow-y: scroll;
}
Then you need to add <v-main> component to your application with scrollable pt-0 mt-16 classes and wrap all of your future app components into it. This classes will adjust the padding from the default <v-app-bar> and enable scrolling directly in <v-main>.
Finally, you should add v-resize directive to <v-main> to automatically recalculate your page size when user will resize a page:
<v-main class="scrollable pt-0 mt-16" v-resize="onResize">
...your application data...
</v-main>
...
methods: {
onResize() {
//64px is v-app-bar height in your case
document.querySelector(".scrollable").style.height = (window.innerHeight - 64) + 'px';
}
},
That's it. You may then create your custom component to wrap <v-main> and forget about such manipulations.
Codepen link with an example
I'm using the bootstrap-vue overlay on a page that has long content scrolled via the browser window.
<b-overlay :show="loading">
The overlay correctly covers all of the content, even the part below the viewport, but the overlay's built-in spinner is centered on the content rather than the viewport, so the spinner ends up near or below the bottom of the viewport when the content is long enough.
I've tried custom content via a slot, like this...
<b-overlay :show="loading">
<template v-slot:overlay>
<div style="???" class="text-center">
<p style="???">Make me a spinner and center me on the viewport</p>
<b-button
</div>
</template>
...with dozens of ideas for style="???", including position:absolute with different tops, including top=50vh, including !important strewn around, etc., but the content doesn't budge.
// Note that this snippet doesn't run, because I don't see a way to get
// bootstrap-vue via CDN
var app = new Vue({
el: '#app',
data: function() {
return {
message: 'Hello Vue!',
messages: []
}
},
mounted() {
for (let i=0; i<50; i++)
this.messages.push(i)
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<b-overlay :show="true">
{{ message }}
<!-- long content below extends the overlay size -->
<!-- this moves the spinner down and off the viewport -->
<ul>
<li v-for="m in messages" :key="m">{{m}}</li>
</ul>
</b-overlay>
</div>
I think key to solving this is finding the CSS selector that allows me to change the spinner's position to "fixed" as opposed to "absolute" which seems to be what bootstrap generates.
To get spinner on center of screen you need to make it as direct child of body.
If it is nested it will have restrict area inside immediate parents area.
Try to add that separately or once your DOM ready detach overlay and append to body tag.
I ran into the same issue. Adding this line of CSS on the component resolved it for me:
<style>
.position-absolute {
position: fixed !important;
}
</style>
Note: make sure to not include the scoped keyword in your <style> tag, as this will not work for Bootstrap classes.
Say you got two divs like this on the component.html
<div *ngIf="htmlSegment == 'a" >
{{someMessage}}
</div>
<div *ngIf="htmlSegment == 'b" >
{{someMessage}}
</div>
When you set the htmlSegment to a or b, we know that the truthy value segment comes alive and the other would disappear. No issues there.
But, what does it take to make the appearance and the disappearance of those segments come alive with some transitioning effects; such as fading in or out etc?
And is it possible to make sure, the transition starts after the dom is done in the new htmlSegment? ( This is so that the user does not experience any flashing or page jerking except the awesome fade in and fade out only. )
The Animate module does not animate your HTML elements, but when Animate notice certain events, like hiding or showing of an HTML element, the element gets some pre-defined styles(or classes) which can be used to make animations.
Add animate module to your project:
import {
trigger,
state,
style,
animate,
transition
} from '#angular/animations';
Add animation property to your component:
animations: [
trigger('heroState', [
state('a', style({
backgroundColor: 'yellow',
opacity:0.5
})),
state('b', style({
backgroundColor: 'black',
opacity:1
})),
transition('a => b', animate('100ms ease-in')),
transition('b => a', animate('100ms ease-out'))
])
]
The trigger will be called when herostate change.
At the end, your HTML code will be:
<div *ngIf="htmlSegment == 'a"
[#heroState]="a">
{{someMessage}}
</div>
<div *ngIf="htmlSegment == 'b"
[#heroState]="b" >
{{someMessage}}
</div>
I can't create an Angular2 online sample of this code but I create an AngularJS online sample for sensing what exactly happen in animations.(for changing animation, you can change 'nga-slide-down' class to 'nga-fade' or your own class)
Check Online(AngularJS - check auto-run js at the right panel and click on change button)