Restate(override) css-transition after it has already triggered - css

Is it possible to restate(override) css-transition after it has already triggered?
It seems down right impossible to override transition-delay after the css-transition has already taking effect.
(Especially considering the possible case when delay duration might have past already, delay value gets shortened and so on.)
However I failed to find concrete explanation.
I suppose css-transition has to be instructed at before or the exact same time when the change of target property (background-color in this case) is instructed?
(Sorry I had to edit numerous times to narrow down my question. If anyone wonder why I need such thing, I explained a mechanism I want below. It's already in simplified of my project.)
What I'm trying to do is
Before jQuery 'load' event, background-color: transparent is applied.
Then on jQuery 'load' event, apply background-color: red
(which is determined by css with class name loaded added by jQuery).
On the otherhand, transition-delay is determined separately by its class name which is provided by jQuery.
Clarification
Just to differentiate from other similar questions..
I only need transition-delay to be override conditionally.
Although interestingly, it would succeed when background-color is changed alongside.
Overriding happens conditionally, i.e: CSSOM remains constant but DOM's class name might change after its initial state. (To be specific to this case, class is added when the button is pressed.)
Override succeeds while DOM stays constant, but that's not what I want.
Here's fiddle to illustrate the situation
HTML
<div>
<!-- class name "loaded" will be given after load event. -->
<p class="delay delay-1s">
<!-- class name 'delay-1s' will be replaced with 'delay-5s' with button -->
This will be turning into red after loaded in..<br>
1.) 1 seconds without button or<br>
2.) 5 second with button
</p>
</div>
<button id="change-delay">Change delay to 5s</button>
CSS
/* Make P from transparent to red when loaded */
div p {
background-color: transparent;
}
div.loaded p {
background-color: red;
}
.delay.delay-1s {
transition-delay: 1s;
}
.delay.delay-5s {
transition-delay: 5s;
}
Javascript
$(window).on('load', function(){
$('div').addClass('loaded');
});
$('button#change-delay').click(function() {
$('.delay').removeClass('delay-1s').addClass('delay-5s');
});
I tested this on Chrome/Firefox updated to this day (Sep 2017), but both returned the same result.
edit1:
I'm pretty sure this has something to do with the time to provide class name.
If I add the class btn-pressed in HTML, i.e hardcode them on the document, override works as intended. Although, it wouldn't happen exclusively when the class is modified.
edit2:
Added clarification.
edit3:
Narrowed down question.
edit4:
adding timelapse of event happening on code:
Loads document.
P gets background-color: transparent and transition-delay: 1s;
Loading is done, adding class 'loaded' to DIV,
P gets background-color: red and fires css-transition
BUTTON gets clicked*, adding class 'btn-pressed' to DIV.
P gets transition-delay: 5s; assigned, overrides CSSOM; however, since css-transition from 2. is already in action, it doesn't take effect.
*Surely, if BUTTON has clicked before loading completed, it will take effect.
I was too lazy to read W3C documents but maybe that's what I should do in spare time..

Html code here
<div class="bg">
<p>test here</p>
</div>
<button class="btn">Activate</button>
Css code here
.bg {
min-height: 200px;
background-color: transparent;
}
Js code here
$(window).on('load', function(){
var delay = 5000;
If ( $('.bg').hasClass('pressed') ) {
delay = 2000; //set delay to 2 sec,
}
$('.btn').on('click', function() {
$('.bg').addClass('pressed');
});
$('.bg').animate({
'background-color': 'red'
}, delay);
});
I assume that you have jquery. If any issue plz let me know by putting a comment below.
I hope this is what you need.
Note - Make few changes as per you needs like class name and events.

Related

Pause/play ALL the CSS animations of every child element

I'm creating a dashboard page which is full of CSS animations. From Bootstrap stuff (animated progress bars) to custom animations.
When you click some of the elements, a near full-screen modal is triggered, which overlaps all the animations, so I want to temporarily pause them all (because of possible performance issues) by adding/removing a class to one of the top elements, and using CSS to pause all animations when that class is set.
This solution would use only a single line of js, just to toggle the class on opening the modal.
My template looks somewhat like this:
<body>
<div class="modal">
<!-- Modal code -->
</div>
<div class="app">
<!-- Template -->
</div>
</div>
Is it possible to add a class to .app which pauses every CSS animation in every child element?
Note 1:
I know you can use the exact opposite of what I request: namely, have a default .animation-play class to one of the top elements, and prefix every child element with an animation with this class, and then remove this class to pause every animation. Just like:
app.animation-play .somediv .somediv .element {
// animation code
}
app.animation-play .somediv .element {
// animation code
}
app.animation-play .somediv .somediv .somediv .somediv .element {
// animation code
}
But then I have to edit a lot of CSS code, and it doesn't look very nice either.
Note 2:
I'm also open for a JS solution, but I would heavily prefer a pure CSS way of achieving this.
You can use a universal selector to target everything when a class of 'paused' is added to your app wrapper, however many CSS linters still warn against using these due to performance impacts.
To be honest the impact is probably minimal these days and many CSS resets for example use them.
You could use something like:
.app.paused * {
animation: none;
}
EDIT:
Looking through the comments above it seems as though the above selector doesn't have enough precedence to overwrite the animations so '!important' has been added.
.app.paused * {
animation: none !important;
transition: none !important;
}
However this is generally not a great idea, I always try to avoid using '!important' at all costs due to the difficulty in maintaining the stylesheet with these selectors in place. If you can overwrite the animations with a greater precedence then it would be better to do so rather than using '!important'.
EDIT 2:
As you mentioned you were open to JS solutions, here is some JS that should clear all the animations within a given selector. I'm not sure what the performance impact of doing it this way is but I added it here just in case someone else prefers to do it only using JS:
let stopAnimationsWrap = document.querySelector('.app');
let stoppedAnims = [];
// Stop animations
document.querySelector('.stop').addEventListener('click', () => {
let appAllEls = stopAnimationsWrap.querySelectorAll('*');
let allElsAr = Array.prototype.slice.call(appAllEls);
allElsAr.forEach((thisEl) => {
let elClass = thisEl.classList[0];
let cs = getComputedStyle(thisEl, null);
let thisAnimation = cs.getPropertyValue('animation-name');
if (thisAnimation !== 'none') {
stoppedAnims.push([elClass, {
'animationName': thisAnimation
}]);
thisEl.style.animationName = 'none';
}
});
});
// Start animations
document.querySelector('.start').addEventListener('click', () => {
stoppedAnims.forEach((thisEl) => {
let domEl = '.' + thisEl[0];
stopAnimationsWrap.querySelector(domEl).style.animationName = thisEl[1].animationName;
});
});
Fiddle:
https://jsfiddle.net/vu6javb2/14/
.app {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}
on hover:
.app:hover {
-webkit-animation-play-state: paused; /* Safari 4.0 - 8.0 */
animation-play-state: paused;
}

AngularJS temporarily disable animations

I have a pretty complex ng-repeat. The number of displayed items can be controlled by two buttons. The first button removes a single element from the ng-repeat by using a filter. The second button removes a bunch of elements and displays a bunch of other elements (also by using a filter).
I currently have an animation on the ng-repeat like this:
<style>
.animation {
-webkit-transition: 1s;
}
.animation.ng-enter {
opacity: 0;
}
.animation.ng-enter.ng-enter-active {
opacity: 1;
}
/* Similar for ng-leave */
</style>
<div class="animation" data-ng-repeat="item in items"> ... </div>
When the user clicks the first button I want the elements to use the animation.
When the user clicks the second button I want to disable any animations.
I'm using AngularJS 1.2.16.
You could use ng-class directive to have animation class conditionally. Remove animation class when you don't want it, specifically saying on click of second button.
<div ng-class="{animation: expression }" data-ng-repeat="item in items"> ... </div>
In above snippet expression will be condition/scope variable which will set to false so that animation will get removed and animation will get disabled.

Oddness with simple CSS: .class:hover property is overridden by property of #child

In Chrome and Firefox, the following doesn't have the desired effect:
<style>
#hoverOnMe { background-color:orange; }
.open:hover { background-color:lightblue; }
</style>
<div id='hoverOnMe' class='open'>HELLO</div>
The :hover doesn't work. The background remains orange on hovering.
However, each of the other three possible combinations (listing by id twice, listing by class twice, and listing by class followed by id) works.
Of course my actual project is a little more complicated than this example; I'd like to add an "open" class to every hoverable element.
What's going on here? What's the simplest workaround?
I'd like to add an "open" class to every hoverable element.
Well if this is the case and you expect the same behaviour for all elements,
then you could just use !important:
.open:hover {
background-color:lightblue!important;
}

CSS selector based on a:target

This is my HTML:
<p class="define"><a class="term" href="#jump" name="jump">jump</a> - Some description</p>
When the browser jumps to #jump I want to highlight the .define class. If I do;
a.term:target { background-color: #ffa; -webkit-transition: all 1s linear; }
I of course only highlight the a. How do I modify this to complete p? I tried a couple of variants like the one below, but none of them work.
a.term:target .define { stuff here }
a.term:target p.define { stuff here }
a.term:target p { stuff here }
jsFiddle: http://jsfiddle.net/vVPPy/
You can't modify the parent of an element using css. You will have to use a javascript alternative.
You will not be able to determine where the user is on the page using CSS. This can be accomplished with JavaScript - If you're not trying to reinvent the wheel, I'd recommend using Bootstrap's ScrollSpy.
Your <p> tag isn't the target of anything. If it were:
<p class="define" id="something">
<a class="term" href="#something" name="jump">jump</a> - blah
</p>
You could style it like so:
a.term:target { background-color: #ffa; }
but that has nothing to do with the <a> actually being clicked on. You'll need to use an onclick handler for that, ideally adding a class to the target and styling based on that class.

Meteor transition effects for auto-updating content

Looking at the meteor leaderboard example, I understand how content in the view templates is bound to functions in the javascript application file. For example, consider this snippet from the view file which defines the "selected" class to determine which name is highlighted yellow:
<template name="player">
<div class="player {{selected}}">
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
The value of {{selected}} is defined and kept up to date in this function from leaderboard.js:
Template.player.selected = function () {
return Session.equals("selected_player", this._id) ? "selected" : '';
};
My question is: How would you add transition effects to this auto updating process? For example, say we wanted the yellow highlighting to fade to white on the existing name, and then fade into yellow on the new name, whenever a new name was clicked. How could we accomplish that in meteor?
The easiest way would be using CSS transitions. Just ensure that the element is preserved (so it isn't replaced on re-draw, just patched):
Template.player.preserve(['.player']);
Then go nuts with the CSS transitions:
.player {
background-color: white;
transition: background-color 500ms linear 0;
-moz-transition: background-color 500ms linear 0;
// etc
}
.player.selected {
background-color: yellow;
}

Resources