I have a piano keyboard rendered in React and I want to replicate a trailing note effect that's also present in Synthesia. That is, while a key is pressed, a trailing note should be rendered above the key, it's height continuously increasing while that key is pressed, and once released, the trailing note should move up at the same speed that its height was increasing.
I managed to apply the move-up part of the notes:
componentDidMount(){
setTimeout(this.applyMoveUp,1)
}
applyMoveUp =()=>{
console.log("apply move up")
this.ref.current.classList.toggle('trailingNote-moveUp')
}
and this is the css:
.trailingNote {
background:black;
width:20px;
transition: transform 5s;
transition-timing-function: linear;
}
.trailingNote-moveUp{
transform: translateY(-700px);
}
This renders the trailing note on the screen and applies the trailingNote-moveUp css class to it so it starts moving up as soon as it's on the screen, but its height does not increase.
I tried using css keyframes as well (https://codepen.io/Sederfo/pen/NWyEjvK) but I'm not sure how to tell CSS to continue the first transformation until the key is released and how to code all of this in React since I am new to this framework.
How can this effect be achieved in React?
Related
In my project, I have a button that I want to display and hide under certain conditions. When the button is hidden, it should still take up space (meaning display: none; is not what I want) but it should not be visible and the user should not be able to interact with it. Changing the visibility does everything I want, but then it appears and disappears instantly, and I would like to have a smooth transition. When using the opacity, I can set the transition duration, but then the cursor still changes to a pointer when hovering over the button. By accident, I discovered that I can simply combine these two things to get the desired result: When I click on the button in the example, it fades out slowly, but once it is gone I cannot interact with it anymore. However, I don't understand why it works that way, since the visibility changes instantly, and I also don't know if it works like this in all major browsers. Could somebody answer these two things for me, please?
function hide() {
document.querySelector("button").style.visibility = "hidden";
document.querySelector("button").style.opacity = "0";
}
button {
transition-duration: 1s;
}
<button onclick="hide()">This is a test.</button>
You can use opacity and pointer-events. Also please don't use javascript for css stuff. In my example I add a class instead.
const button = document.querySelector('.js-disable')
button.addEventListener('click', function() {
button.classList.add('button--is-disabled')
})
.button {
background-color: #ededed;
padding: .5rem 1rem;
border: none;
}
.button--is-disabled {
opacity: 0;
pointer-events: none;
transition: opacity 2s;
}
<button class="button js-disable">Click me</button>
The question was basically: why does this work when visibility is changed instantly.
This is in fact not correct. visibility is interpolated and as you have the transition set on everything, the visibility will transition.
Obviously it can not have continuous values, but it 'chooses' a value of visible or hidden, which are the two endpoints you have specified, in steps. The place(s) at which it changes are determined by the timing function.
So, your code works absolutely fine. The element fades away with the opacity and at some point (near the end in the case of the ease timing function) it will switch from visible to hidden.
See for example MDN:
Visibility values are interpolated between visible and not-visible.
I have a loading indicator (a bar that continuously animates its width from 0% to 100%) using css3 keyframes. I trigger this behavior by adding a .loading class to by loading bar. Now once I am done loading I would like to animate out of the keyframes. Say, for example at the time that I finish loading the width is animated to 50% I would not have it jump to 100%, but ease it to 100% where it should stay.
I have tried adding a transition and animation to my loading bar class, but neither seems to be working. How do I go about this?
Here's the jsFiddle.
You can use the animationiteration (MDN) event to detect when the animation reaches the end of a loop and then remove the class.
$('#bar').on('webkitAnimationIteration', function(e){
$('#bar').removeClass('loading').off('webkitAnimationIteration');
});
I've updated the fiddle here: http://jsfiddle.net/jedidiah/kYnhF/6/
-
For simplicity I've only added the webkit prefix to the the fiddle but there is a useful article about css animation events in javascript here http://www.sitepoint.com/css3-animation-javascript-event-handlers/ where they share a little function to simplify using the prefixes you could use to support other browsers.
I upvoted #Jedidiah answer, I think that is what you need.
BTW, If you are interested in an alternative, simple CSS3 solution, then add to your #bar:
transition: all 1s;
-webkit-transition: all 1s
Running Demo
Potential drawbacks (depending on your needs):
It won't respect the previous speed of the progressbar (no matter if you are at 10% or 90%, the remaining part will take 1 second to complete... but this is how often the progressbars of the installers work, so it may not be a problem);
It won't run all the animation: if you are in the first half, it will fill to the left, instead of completing all the round.
I am trying to apply a Minecraft-like style to a div element. The end result should look something like the "if not ok then return end" message:
Quick sidenote: For those of you who haven't played the game, a random line from a specific file is read and it's contents are displayed as the message of the day. It throbs in and out and grabs your attention.
The text shadow, font, and throbbing animation has already been done. However, when I try to apply the second animation, it overrides the throbbing animation (meaning it does not throb, but is rotated)
My CSS is as follows:
#random-message {
/* font/text stuff */
animation:minecraft, minecraft-rotate 0.5s infinite;
-webkit-animation:minecraft 0.5s infinite; /* Safari and Chrome */
}
The animation minecraft applies a transform: scale effect, and minecraft-rotate applies a transform: rotate effect.
What would be the best way to implement a rotation effect without overriding my throbbing effect?
You don't want to have a rotation animation...you want to rotate the div. Simply add transform: rotate(340deg); line to the css block.
Any given element can have only one transform at any given time. Any attempt to set at the same time 2 transforms will result in one of them being overriden.
You can:
1) set two divs, one inside the other, and apply a different transform to the parent and to the child.
2) build the composite transform. In the case of an animation, that means creating composite transforms for each frame.
I've created a page that has content showing & hiding based on the device orientation, however I find that there's somewhat of a jump/lag when you rotate and the content shows/hide.
Is it possible to animate a smoother transition between lelements showing/hiding using just css?
For the elements that animate in and out of view, you can use transition-property: all; and transition-duration: 1s; (or whatever duration you'd like) to fade in/slide in said elements. Of course those CSS properties will need to be prefixed in some browsers.
In my app I'm animating the opacity of elements on the page with something like:
.s {
transition-property: opacity;
transition-duration: 250ms;
}
(with vendor-specific versions, of course). And then
.s.hidden {
opacity: 0;
}
So the animation starts when the hidden class is assigned. Problem is, mouse events are still detected on elements with opacity zero, which I don't want, so I need to either set visibility to hidden or display to none after the transition is finished. I would hope to be able to do something like:
.s {
transition-property: opacity, visibility;
transition-duration: 250ms;
transition-delay: 0, 250ms;
}
and then
.s.hidden {
opacity: 0;
visibility: hidden;
}
to use the CSS transition machinery to do this painlessly. As far as I can tell, that doesn't work because visibility is a non-animatable property. But other transition frameworks such as d3 do handle non-animatable properties, in the obvious way by simply setting the value when the transition starts, or when it ends.
The best I've been able to come up with is to use the transitionend event (and its browser-specific variants such as oTransitionEnd) to catch the end of the transition and set visibility at that point, but I'm wondering if there's any easier way, preferably sticking purely to CSS. Or, as the title of my question implies, are non-animatable properties just that?
visibility is an animatable property, see the spec.
Which means your .hidden class will work as you have described. Demo here: http://jsfiddle.net/ianlunn/xef3s/
Edit: the spec isn't perfectly clear:
visibility: if one of the values is ‘visible’, interpolated as a
discrete step where values of the timing function between 0 and 1 map
to ‘visible’ and other values of the timing function (which occur only
at the start/end of the transition or as a result of ‘cubic-bezier()’
functions with Y values outside of [0, 1]) map to the closer endpoint;
if neither value is ‘visible’ then not interpolable.
But this is what I believe it means:
visibility doesn't smoothly animate between a range of visible and hidden in the way that opacity animates between 1 - 0. It simply switches between visible and hidden at the start and end states of the transition.
Providing the transition is either going to or from visibility, then a transition will occur. If trying to transition between visibility: hidden and visibility: collapse for example, those values are "not interpolable" and the transition would not occur.
So in my example, opacity causes the element to fade out and then at the end of the transition, visibility snaps to hidden.
As a good alternative to display/visibility toggle, opacity:0 with pointer-events:none could be used.