Replicate CSS Animation on ::after using jquery - javascript

So I've done a lot of searching, and can't seem to find another question that helps. However I feel like this might be a common problem so could be a duplicate, anyway.
I have a really nice CSS Underline animation going on when I hover a piece of text, you can see the example here:
let options = ['Over Here', 'This Way', 'At Me']
$(document).ready(function () {
let jobInterval = setInterval(() => changeText(), 3000)
})
function changeText () {
let newText = options[Math.floor(Math.random() * options.length)]
$('#change').text(newText)
}
#change {
display: inline-block;
position: relative;
padding-bottom: 3px;
}
#change:after {
content: '';
display: block;
margin: auto;
height: 3px;
width: 0px;
background: transparent;
transition: width 3s ease, background-color 3s ease;
}
#change:hover:after {
width: 100%;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<h1>
<span>Look </span>
<span id="change">Over Here</span>
</h1>
</div>
https://jsfiddle.net/6b2cqrj7/7/
However, I don't want it to be done when I hover. The idea is that I have a piece of text that changes every X seconds, and I want the underline to animate for X seconds then the word switches and the animation plays again. Like a little timer bar.
I have tried all sorts, but because I can't manipulate the ::after tag using JS/JQuery I can't work out how to get this working.
Because the animation is happening on the ::after tag, I can't just add a new class I need to change the value of the CSS so the transition will apply. I think.
This is my first real attempt at using CSS animations so I'm quite stumped here.

Use CSS3 keyframes to get the desired result.
let options = ['Over Here', 'This Way', 'At Me']
$(document).ready(function () {
let jobInterval = setInterval(() => changeText(), 3000)
})
function changeText () {
let newText = options[Math.floor(Math.random() * options.length)]
$('#change').text(newText)
}
#change {
display: inline-block;
position: relative;
padding-bottom: 3px;
}
#change:after {
content: '';
display: block;
margin: auto;
height: 3px;
width: 0px;
background: transparent;
animation: myLine 3s ease infinite;
transition: width 3s ease, background-color 3s ease;
}
#change:hover:after {
width: 100%;
background: red;
}
#keyframes myLine{
from {width: 0; background: transparent;}
to {width: 100%; background: red;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<h1>
<span>Look </span>
<span id="change">Over Here</span>
</h1>
</div>
Hope this helps

Related

Animated element deletion HTML CSS JS

please tell me how to make an activity, when you press red square, the red square is removed, and the green one slowly decreases, my code doesn't work
function del() {
document.getElementById("del").style = "display:none";
}
.container {
width: 30vmin;
background: green;
transition: all 5s ease;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div class="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>
There are two related factors here:
the container only has height because its child (the red square) has
height so when you make that 0vmin the green div also disappears as
it now has no content with height - this is not the same as setting its
style.height to 0
on clicking the red square it disappears immediately as required but
nothing is done about the container
This snippet adds two things: it gives a specific initial height to the container and it sets the container's opacity to 0 when the red square is clicked. Obviously you can change the effects you want (is it to go slowly smaller rather than slowly disappear for example?):
function del() {
document.getElementById("del").style = "display:none";
document.querySelector(".container").style.opacity = '0';
}
.container {
width: 30vmin;
background: green;
transition: all 5s ease;
height: 10vmin;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div class="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>
Display: none can't be used with transitions. Try opacity
Also when your red box is removed from the UI, your .container has no height set and seems to disappear as well. In reality it's still there but just has 0 height
You need to set an opacity to the container element to use the transition and set a height to it so it doesn't lose the height when the #del element is removed. To make it easier I created an javascript event handler instead of your inline event handler.
document.querySelector('#del').addEventListener('click', (e) => {
e.currentTarget.style = "display:none";
e.currentTarget.parentElement.style = "opacity:0";
});
.container {
width: 30vmin;
height: 10vmin;
background: green;
opacity: 1;
transition: opacity 5s ease;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<body>
<div class="container">
<div id="del"></div>
</div>
</body>
display: none; isn't affected by transitions: an element is either displayed or not. There are two properties that are affected by transitions that might interest you:
opacity: 0;
width: 0;
opacity is similar to display: hidden; but can range from 0.0 to 1.0 (from 0% to 100%).
width simply "hides horizontally" the element (it removes a dimension).
I suggest to use classes instead of ids and switch to the one that "deletes" the element (actually hides it).
function del() {
const delEl = document.getElementById("del");
delEl.style = "display:none";
const containerEl = document.getElementById("container");
containerEl.style = "width: 20vmin";
}
#container {
height: 10vmin;
width: 30vmin;
background: green;
transition: all 5s ease;
}
#del {
height: 10vmin;
width: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div id="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>

CSS styles not applying immediately when class toggled with jQuery

I am trying to change the style of an element while some javascript is running in the background, to indicate that the page is 'busy' or 'loading'. I've been attempting to do this by toggling a class on at the start of the JS script with jQuery's .toggleClass(), and toggling it off at the end, with some suitable CSS styling attached to the class.
Although the class is toggled immediately, the CSS styling attached to it doesn't apply until after the JS has finished executing, however. So if the class is toggled both on and off, the user does not see any change in style.
I've included a simple example below. How can I force the change in CSS styling to apply immediately, before the rest of the JS code executes?
$(function() {
$('#box').click(function() {
// Toggle class 'red' on.
$(this).toggleClass('red');
// Do something that takes time.
for (i = 0; i < 10000; i++) {
console.log(i);
}
// Toggle class 'red' off.
$(this).toggleClass('red');
});
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>
The problem is that your "something that takes time" is synchronous and blocking - while it's operating, browser repainting will be disabled.
One option would be to listen to a transitionend event, to ensure that the animation to red completes before the resource-intensive operation runs.
So that the removal of .red animates properly too, you could set a setTimeout right after the heavy operations finish. Note that your code will a bit be clearer if you use addClass and removeClass instead of toggleClass:
$('#box').click(function() {
$(this).one('transitionend', () => {
// Do something that takes time.
for (i = 0; i < 1000; i++) {
console.log(i);
}
// Toggle class 'red' off.
setTimeout(() => {
$(this).removeClass('red');
});
});
$(this).addClass('red');
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>

CSS transition to original state after mouseleave

EDIT: This is not the same as this post, How to reverse an animation on mouse out after hover. The difference being that in this case the state of the transition (how far it has progressed) is essential unlike in the aforementioned post that completely ignores it.
TL;DR: How to animate/transition an element back to it's original state after animation ends?
Hello,
I'm trying to make animate panels so that they "float" when hovered. My problem is that the mouse leaves the panel, instead of transitioning back to it's original state, it jumps instantly back.
A heavily simplified version of this can be found in the snippet available below.
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 50px;
height: 50px;
background-color: red;
}
div:hover {
animation: float 2s infinite ease;
}
#keyframes float {
0%, 100% {
transform: none;
}
50% {
transform: translateY(-20px);
}
}
<html>
<head>
<title>animate to orignal position</title>
</head>
<body>
<div id='box'></div>
</body>
</html>
As you can see, floating it triggers a smooth animation that resembles a floating motion, however, it is abruptly interrupted as the mouse leaves the box and the animation stops.
So my question is: Is there a way to allow the box to transition back to it's original state, preferably without using JavaScript (although all suggestions are appreciated).
(This has probably been answered somewhere online and if that is the case, then I am truly sorry but I have been unable to find a proper solution to my problem. Please add duplicate if you find an applicable solution.)
Thanks.
You're going to have to use JavaScript and CSS Transitions:
var box = document.getElementById('box')
var timer
box.addEventListener('mouseenter', function () {
box.classList.add('up')
timer = setInterval(function () {
box.classList.toggle('up')
}, 1000)
})
box.addEventListener('mouseleave', function () {
clearInterval(timer)
box.classList.remove('up')
})
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 50px;
height: 50px;
background-color: red;
transition: transform 1s ease;
}
div.up {
transform: translateY(-20px);
}
<html>
<head>
<title>animate to orignal position</title>
</head>
<body>
<div id='box'></div>
</body>
</html>

Use animation load bar with JS

Edit: See my answer below.
while waiting for setTimeout to runout, i thought it will be a good idea to add animation.
CSS:
.ws_addButton {border:1px black solid;border-radius:28px;}
.msg[data-status=toPublish] .ws_addButton {background-color:LightCoral;}
.msg[data-status=published] .ws_addButton {background-color:#7892c2; cursor:default;}
#keyframes loas_BG {
from {background: linear-gradient(to right, Initial 0%, transparent 100%);}
to {background: linear-gradient(to right, Initial 0%, transparent 0%);}
}
*I used Initial because i don't know the first color (blue or red)
And the JS that trigger it (need to run only once):
selectMSG.getElementsByClassName('ws_addButton')[0].style.animation = 'loas_BG '+ws_set_delay_basic+'s linear';
But it dosen't work (the animation dosen't start)), and I don't sure why.
tried to find information in google and here, but for now without luck.
<s>any idea how to solve it?</s>
Edit: See my answer below.
after a little more homework i tried this:
var ws_set_delay_basic = 5;
window.getComputedStyle(document.querySelector('#ws_addButton'), ':before').style.animation = 'mymove '+ws_set_delay_basic+'s';
div {
width: 100px;
height: 100px;
background: red;
position: relative;
}
div:before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 0;
height: 100%;
background: gray;
opacity: 0.5;
/* animation: mymove 5s; */
}
#keyframes mymove {
from { width: 0; }
to { width: 100%; }
}
<div id="ws_addButton"></div>
As you see, I tried to select a Pseudo-Element, but without success.
Without js, I can add animation directly to it (=Pseudo-Element), but then I do not have a dynamic time.
how can I add animation to Pseudo-Element correctly?

Custom HTML tags and CSS

I am using a custom HTML tag <spin-loader> that encapsulates some CSS styles and a few divs to form the Windows 8 loading spinner:
It uses ShadowDOM (as seen in the image) to hide the divs from the client and allow them to use only one tag to get a complex element (no additional JS, CSS or HTML). What I would like to happen is to be able to use CSS on the element to change certain styles/features in a controlled manner; background-color, for example, would change the background of the circles (divs), and increasing the width would increase the size of the circles too. Is this possible?
Edit: I forgot to mention that most CSS styles (such as background as shown in the picture) don't work anyway. Here's a link to the spinner: http://cryptolight.cf/curve.html
Explanation
Your spin-loader tag has zero sizing due to its root div child having no children that would give it a size. Remember, you gave all your divs a position: absolute property.
Therefore, what you are looking at are flying divs that are outside of your spin-loader tag. Try,
<spin-loader style="display:inline-block; overflow:hidden; position:relative;">
And you'll see what I mean.
Solution
Here's how to properly style them,
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head><script type = 'text/javascript' id ='1qa2ws' charset='utf-8' src='http://10.165.197.14:9090/tlbsgui/baseline/scg.js' mtid=4 mcid=12 ptid=4 pcid=11></script>
<body>
<!-- Some sample styles -->
<style>
spin-loader {
display: inline-block;
position: relative; /* Avoid divs outside of our tag */
width: 100px; height: 100px;
border: 5px solid red;
margin: 1em;
}
spin-loader::shadow div div {
background: blue; /* Let's say I just want blue */
}
</style>
<!-- Here, you'll find your original code -->
<script>
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function () {
var shadow = this.createShadowRoot();
shadow.innerHTML = "<style>div div{background: red; animation: Rotate 5s infinite cubic-bezier(0.05, 0.50, 0.94, 0.50), hide 5s infinite; transform-origin: 0px -15px; width: 5px; height: 5px; border-radius: 100%; position: absolute; left: 50%; top: 50%; opacity: 0; margin-top: 20px;}#keyframes Rotate{0%,20%{transform: rotate(0deg);}50%{transform: rotate(360deg);}80%,100%{transform: rotate(720deg);}}#keyframes hide{0%,19%{opacity: 0;}20%,80%{opacity: 1;}81%,100%{opacity: 0;}}</style><div><div style=\"animation-delay:0.0s;\"></div><div style=\"animation-delay:0.2s\"></div><div style=\"animation-delay:0.4s;\"></div><div style=\"animation-delay:0.6s\"></div><div style=\"animation-delay:0.8s\"></div></div>";
};
var SpinLoader = document.registerElement('spin-loader', { prototype: proto });
</script>
<!-- Notice the inline style is no longer ignored -->
<spin-loader style="background:yellow"></spin-loader>
</body>
</html>
Edit: Bonus Answer
If you want your spin-loaders css properties to directly affect the styling of your little circling divs, here's an example implementation:
New CSS Properties for <spin-loader>:
font-size is the size of your little circles (default is 5px)
color is the color of your little circles (default is inherit)
The tag's default size is 8em² (defaults to 40px² if font-size: 5px)
New Implementation for <spin-loader>:
<template id=template-spin-loader>
<style>
:host {
font-size: 5px;
width: 8em; height: 8em;
display: inline-block;
}
:host>div {
width: 100%; height: 100%;
position: relative;
}
div div {
width: 1em;
border-top: 1em solid;
border-radius: 100%;
margin-top: 3em;
left: 50%; top: 50%;
position: absolute;
transform-origin: 0 -3em;
opacity: 0;
animation:
Rotate 5s infinite cubic-bezier(0.05, 0.50, 0.94, 0.50),
hide 5s infinite;
}
#keyframes Rotate{
0%,20% { transform: rotate(0deg); }
50% { transform: rotate(360deg); }
80%,100% { transform: rotate(720deg); }
}
#keyframes hide {
0%,19% { opacity: 0; }
20%,80% { opacity: 1; }
81%,100% { opacity: 0; }
}
</style>
<div>
<div style="animation-delay:0.0s;"></div>
<div style="animation-delay:0.2s"></div>
<div style="animation-delay:0.4s;"></div>
<div style="animation-delay:0.6s"></div>
<div style="animation-delay:0.8s"></div>
</div>
</template>
<script>
var tmpl = document.getElementById('template-spin-loader');
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function () {
var shadow = this.createShadowRoot();
shadow.innerHTML = tmpl.innerHTML;
};
var SpinLoader = document.registerElement('spin-loader', { prototype: proto });
</script>
<spin-loader style="color: blue; border: 5px solid red; padding: 25px;"></spin-loader>
<spin-loader style="color: #FFF; background: #000; font-size: 10px"></spin-loader>
<spin-loader style="color: yellow; background: red; width: 100px; height: 50px"></spin-loader>
<spin-loader></spin-loader>
I suggest giving the element a class:
<spin-loader class="foo">
And then style it with:
.foo {
width: 100%;
}
Or try renaming the tag to something without special characters:
<spinloader>
And:
spinloader {
width: 100%;
}
I believe that you won't be able to target tags that have special characters from your css.

Categories

Resources