How to do a full transition when hovered over an element? - html

.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box:hover {
background: yellow;
}
<div class="box"></div>
If the cursor is over the .box for less than a second, the transition stops and falls back to it's original phase.
Is there a way to somehow force the whole animation, regardless of hover duration?
fiddle

Edit: Similar solution but relying on transition and animation: https://jsfiddle.net/ok7pnrsL/
This is my solution: https://jsfiddle.net/9yu0cozq/1/
Basically you need to add a container for the box and then play with CSS animations.
<div id="container">
<div class="box"></div>
</div>
When the mouse enters the .box then the hidden container appears (please note that for this to work that container should have enough width and height to fit the whole area where the mouse might go).
This container creates an animation for itself to "hide" back in 1s. and while it is shown the .box has an animation for the same time.
#container {
position:absolute;
z-index:1;
width: 0;
height: 0;
}
#container:hover{
animation-name:changeSize;
animation-duration: 1s;
}
#container:hover .box{
animation-name:changeColor;
animation-duration: 1s;
}
.box {
z-index:0;
position:absolute;
width: 100px;
height: 100px;
background: red;
transition:1s background;
}
.box:hover {
background: yellow;
}
#keyframes changeColor {
0% {
background: red;
}
100% {
background: yellow;
}
}
#keyframes changeSize {
0%,99% {
width: 100%;height: 100%;
}
100% {
width: 0;height: 0;
}
}
So, without knowing the real context, this solution gives a series of assumptions that might or might not fit your exact case but gives an idea of how to solve it using pure CSS.

I think you heave to use JS for this. First you need to create animation for background change, and and then you can set it as class and add that class on hover, and remove it when animation ends or on webkitAnimationEnd.
$('.box').hover(function() {
$(this).addClass('animate');
$(this).on('webkitAnimationEnd', function() {
$(this).removeClass('animate');
})
})
.box {
width: 100px;
height: 100px;
background: red;
display: inline-block;
margin: 10px;
}
.box.animate {
animation: changeColor 2s linear;
}
#keyframes changeColor {
0% {
background: red;
}
50% {
background: yellow;
}
100% {
background: red;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="box"></div>

I don't think you can do this without javascript, but it would be interesting to find out.
A light weight javascript solution could be something like this:
// Get the elemnt
var myDiv = document.getElementById('box');
// Detect hover
myDiv.onmouseover = function() {
// Add a force class to the element
myDiv.className += " force";
// Reset the cass name after 1sec (100ms)
setTimeout(function(){ myDiv.className = "box"; }, 1000, myDiv);
}
Change your markup slightly to make things easier for now:
<div id="box" class="box"></div>
And add an extra class to your css styles along with the hover state:
.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box.force,
.box:hover {
background: yellow;
}
Check the jsfiddle

Related

CSS Variables in keyframes [duplicate]

I have been trying to get this to work for a while.
The point is that the inner div will have some shape and there will probably more than one (That's why I used the nth-child selector).
This inner div is supposed to be shown and then be hidden again both for some set amount of time.
the problem is, that I would like to animate all the (later) multiple inner divs in one animation. For this I thought I could use CSS variables, but this does not seem to work.
What I am trying to archieve in this example is the inner div basically just blinking by using the variable. But my result in Firefox is just a black box.
Am I missing anything? I already looked up if one could even use CSS variables in #keyframes and sure enough you can.
The only problem with them in animations seems to be that they are not interpolated in between but that they suddenly switch which is not a problem in this case.
#keyframes test{
from{
--one: 0;
}
to{
--one: 1;
}
}
#test{
width: 100px;
height: 200px;
background-color: black;
animation: test 1s infinite;
}
#test :nth-child(1){
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
}
<div id="test">
<div></div>
</div>
This can be achieved by defining variables using (as of writing this, not well-supported) #property, which allows declaring types and that allows the browser to "understand", for example, that a certain property (variable) is a Number and then it can gradually animate/transition that variable.
Example Code:
#property --opacity {
syntax: '<number>'; /* <- defined as type number for the transition to work */
initial-value: 0;
inherits: false;
}
#keyframes fadeIn {
50% {--opacity: 1}
}
html {
animation: 2s fadeIn infinite;
background: rgba(0 0 0 / var(--opacity));
}
The current types that are allowed include:
length, number, percentage, length-percentage, color, image, url, integer, angle, time, resolution, transform-list, transform-function, custom-ident (an identifier string)
Helpful articles:
https://web.dev/at-property/#writing-houdini-custom-properties
https://css-tricks.com/using-property-for-css-custom-properties
Cool Houdini demos
As stated in the specification:
Animatable: no
and also
Notably, they can even be transitioned or animated, but since the UA
has no way to interpret their contents, they always use the "flips at
50%" behavior that is used for any other pair of values that can’t be
intelligently interpolated. However, any custom property used in a
#keyframes rule becomes animation-tainted, which affects how it is
treated when referred to via the var() function in an animation
property.
So even if you use opacity with var() in the keyframes it won't animate:
#keyframes test {
from {
--one:0;
opacity: var(--one);
}
to {
opacity: var(--one);
--one: 1;
}
}
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
animation: test 1s infinite;
}
<div id="test">
<div></div>
</div>
By the way you can make it working if you use it as a transition because in this case you will apply a transtion to the opacity and not the custom property:
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test:hover {
--one:1;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
transition:1s all;
}
<div id="test">
<div></div>
</div>

Can I have multiple transitions on the same property?

I need to change width of the element on two different events and with different speeds. Can I somehow specify two transitions of the same property or do I have to change approach?
Let's say I want to quickly increase width of a box with hover. And be able to do the same thing with a button but slower. The problem here is when the class is removed from the box so is the 3s transition. I want a 3s transition to last for the shrinking of the box after the button is pushed again.
const box = document.getElementById("box");
function growQuickly(){
box.classList.toggle("grow");
}
.box{
height:100px;
width:100px;
background: red;
transition: .5s;
}
.box.grow{
width: 200px;
transition: 3s;
}
.box:hover{
width:200px;
}
<div class="box" id="box" ></div>
<button onclick="growQuickly()">GROW SLOWLY</button>
You can separate your logic into more classes and check if something is already included using js.
CSS
.box {
height: 100px;
width: 100px;
background: red;
transition-duration: 0.5s;
}
.box:hover {
width: 200px;
}
.wide {
width: 200px;
}
.slow {
transition-duration: 3s;
}
JS
const box = document.getElementById('box');
function growQuickly() {
const boxWidth = box.offsetWidth;
if (boxWidth === 200 && box.classList.contains('slow')) {
box.classList.toggle('wide');
setTimeout(() => box.classList.toggle('slow'), box.style.transitionDuration);
} else {
box.classList.toggle('wide');
box.classList.toggle('slow');
}
}

Vue.js leave animation not working as expected

The demo is quite simple, and similar to the example in the Vue.js docs.
new Vue({
el: '#demo',
data: {
show: true
}
})
p {
width: 100px;
border: 1px solid red;
}
.fade-enter-active,
.fade-leave-active {
transition: all 5s;
}
.fade-enter {
opacity: 0;
width: 500px;
background: red;
}
.fade-enter-to {
background: black
}
.fade-leave {
opacity: 0;
background: red
}
.fade-leave-to {
background: black;
width: 1000px;
opacity: 1
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
The question is, when the leave animation begins, it seems it's removed from the DOM (v-if is false) so quickly that there isn't any animation at all!
But, if I remove opacity, the animation works! Why does opacity matter?
.fade-leave {
/* opacity: 0; */
background: red;
}
.fade-leave-to {
background: black;
width: 1000px;
/* opacity:1; */
}
There is another question, I thought the leave animation should be that the DOM background becomes red firstly (while the result is it didn't or I just can't tell), then change to black slowly. So, is it my misconception?
The opacity is important because the animation is fading according to it.
Here I have added to opacity of 0 directly to the class fade-enter-active of the button Hello. You can see the animation fading step by step.
Instead, with an opacity of 1, there is no direction to your fading. It stays at 1.

CSS animate custom properties/variables

I have been trying to get this to work for a while.
The point is that the inner div will have some shape and there will probably more than one (That's why I used the nth-child selector).
This inner div is supposed to be shown and then be hidden again both for some set amount of time.
the problem is, that I would like to animate all the (later) multiple inner divs in one animation. For this I thought I could use CSS variables, but this does not seem to work.
What I am trying to archieve in this example is the inner div basically just blinking by using the variable. But my result in Firefox is just a black box.
Am I missing anything? I already looked up if one could even use CSS variables in #keyframes and sure enough you can.
The only problem with them in animations seems to be that they are not interpolated in between but that they suddenly switch which is not a problem in this case.
#keyframes test{
from{
--one: 0;
}
to{
--one: 1;
}
}
#test{
width: 100px;
height: 200px;
background-color: black;
animation: test 1s infinite;
}
#test :nth-child(1){
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
}
<div id="test">
<div></div>
</div>
This can be achieved by defining variables using (as of writing this, not well-supported) #property, which allows declaring types and that allows the browser to "understand", for example, that a certain property (variable) is a Number and then it can gradually animate/transition that variable.
Example Code:
#property --opacity {
syntax: '<number>'; /* <- defined as type number for the transition to work */
initial-value: 0;
inherits: false;
}
#keyframes fadeIn {
50% {--opacity: 1}
}
html {
animation: 2s fadeIn infinite;
background: rgba(0 0 0 / var(--opacity));
}
The current types that are allowed include:
length, number, percentage, length-percentage, color, image, url, integer, angle, time, resolution, transform-list, transform-function, custom-ident (an identifier string)
Helpful articles:
https://web.dev/at-property/#writing-houdini-custom-properties
https://css-tricks.com/using-property-for-css-custom-properties
Cool Houdini demos
As stated in the specification:
Animatable: no
and also
Notably, they can even be transitioned or animated, but since the UA
has no way to interpret their contents, they always use the "flips at
50%" behavior that is used for any other pair of values that can’t be
intelligently interpolated. However, any custom property used in a
#keyframes rule becomes animation-tainted, which affects how it is
treated when referred to via the var() function in an animation
property.
So even if you use opacity with var() in the keyframes it won't animate:
#keyframes test {
from {
--one:0;
opacity: var(--one);
}
to {
opacity: var(--one);
--one: 1;
}
}
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
animation: test 1s infinite;
}
<div id="test">
<div></div>
</div>
By the way you can make it working if you use it as a transition because in this case you will apply a transtion to the opacity and not the custom property:
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test:hover {
--one:1;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
transition:1s all;
}
<div id="test">
<div></div>
</div>

CSS Effect shrink from small to bigger

i really want to know how this effect is created.
check this video, only 12 secs.
https://youtu.be/cJqU8jW0xsg
i try with :
.zoom {transform:scale(0.1); }
.zoom:hover {transform:scale(2); }
how to make it start from (top-left) and will end at (bottom-right) just like that in the video?
thanks in advance..
What you're after is the transform-origin property.
Here's an example.
http://codepen.io/dropkick/pen/YqKzdG/
HTML
<div class="box"></div>
<button>click me</button>
CSS
.box {
background: #0f0;
width: 200px;
height: 200px;
margin: 20px auto;
transition: transform 0.5s linear;
transform-origin: top right;
transform-style: preserve-3D;
transform:scale(0.1);
}
.box-scale {
transform:scale(1.0);
}
button {
display: block;
margin: auto;
}
JS
$('.scale').click(function () {
$('.box').toggleClass('box-scale');
});
You need transform-origin! https://developer.mozilla.org/en/docs/Web/CSS/transform-origin
Setting the origin sets the start point for the transition. It'll grow out from there.