Changing element style using JavaScript - javascript

I am trying to change a spans style using JavaScript but cannot seem to do it. Below I have created the span and given it an Id "spanzo", then I have stored the span in a var "elementtl" and tried two ways to add styles to it but its not doing anything. Styles have already been set to the span, I am just trying to override them styles.
const letterEl = document.createElement("span");
letterEl.setAttribute("id", "spanzo");
var elementtl = document.getElementById("spanzo");
elementtl.classList.toggle("spanzo1");
elementtl.style.backgroundColor = "red";
#spanzo{
transform: rotatey(0deg);
}
.spanzo1{
transform: rotatey(180deg);
transition: 2s;
}

const letterEl = document.createElement("span");
letterEl.innerText = "This is a span.";
document.body.appendChild(letterEl);
letterEl.setAttribute("id", "spanzo");
var elementtl = document.getElementById("spanzo");
elementtl.classList.toggle("spanzo1");
elementtl.style.backgroundColor = "red";
#spanzo{
transform: rotatey(0deg);
}
.spanzo1{
transform: rotatey(180deg);
transition: 2s;
}

First of all you need to add a width and height to your #spanzo style for it to actually occupy some space and you need to add it to the <body> element using
document.body.append(letterEl)
All together
const letterEl = document.createElement("span");
letterEl.setAttribute("id", "spanzo");
document.body.append(letterEl)
document.body.appendChild(letterEl);
var elementtl = document.getElementById("spanzo");
elementtl.classList.toggle("spanzo1");
elementtl.style.backgroundColor = "red";
#spanzo{
transform: rotatey(0deg);
width:50px;
height:50px;
}
.spanzo1{
transform: rotatey(180deg);
transition: 2s;
}

const letterEl = document.createElement("span");
letterEl.setAttribute("id", "spanzo");
letterEl.textContent = 'hello world';
document.body.appendChild(letterEl);
var elementtl = document.getElementById("spanzo");
elementtl.classList.toggle("spanzo1");
elementtl.style.backgroundColor = "red";
#spanzo{
transform: rotatey(0deg);
}
.spanzo1{
transform: rotatey(180deg);
transition: 2s;
}

To create and append an element you may want to use insertAdjacentHTML. To add or remove css-classes use classList[add/remove]. For example:
document.body.insertAdjacentHTML(`beforeend`,
`<div id="spanzo">Hi, i am div#spanzo</div>`);
document.addEventListener(`click`, handle);
function demo() {
const demoElem = document.querySelector(`#spanzo`);
demoElem.textContent = `Hi, i am div#spanzo. Wait a sec ...`;
setTimeout(() => {
demoElem.classList.add(`spanzo1`);
setTimeout(() => {
demoElem.classList.remove(`spanzo1`);
demoElem.textContent = `I'm back!`}, 3000);
}, 1000);
}
function handle(evt) {
if (evt.target.nodeName === `BUTTON`) {
return demo();
}
}
#spanzo.spanzo1{
transform: rotatey(180deg);
transition: 2s;
}
<button>Demo</button>

Related

Halting CSS animation with ::after selector in JavaScript

I have a JavaScript function that types out, letter by letter, a message. However, where the current character to be typed is located, I have a blinking css animation. What I need is to stop this animation and make it disappear.
I am using a css with #id::after to put the animation after the text in question. The animation works fine, I need a way to set content: '█'; to content: ''; via JavaScript.
(function type_p(){
let msg = 'This is a message to type out! Spooky!';
let element = document.getElementById('typehere');
typeOut(msg, '', 0, element);
}());
function typeOut(text, letter, index, element){
letter = text.slice(0, ++index);
element.textContent = letter;
if (letter.length == text.length){
stop();
}
setTimeout(typeOut, 100, text, letter, index, element);
}
#typehere {
position: relative;
}
#typehere::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
/* animation-iteration-count: 2; */
}
#keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<p id="typehere">Here</P>
I am aware of CSS animation-iteration-count: however this will stop the animation but it will still be visible (motionless). How do I remove this?
I would just add a class to your element and change the content based on class.
(function type_p(){
let msg = 'This is a message to type out! Spooky!';
let element = document.getElementById('typehere');
typeOut(msg, '', 0, element);
}());
function typeOut(text, letter, index, element){
letter = text.slice(0, ++index);
element.textContent = letter;
if (letter.length == text.length){
element.classList.add('stop');
stop();
}
setTimeout(typeOut, 100, text, letter, index, element);
}
#typehere {
position: relative;
}
#typehere::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
/* animation-iteration-count: 2; */
}
#typehere.stop::after {
content: '';
}
#keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<p id="typehere">Here</P>
This is similar to the other answer, but I find it easier/cleaner than adding multiple classes to something that will no longer be visible.. You can add the animation styling as a class, and then remove that class when you no longer want it to animate.
Change to class in css:
.typehereclass::after {
content: '█';
position: absolute;
animation: blink 1.5s infinite;
}
Add the class to your element in html:
<p id="typehere" class="typehereclass">Here</P>
And then when you want to stop the blinking in JS:
element.classList.remove('typehereclass')

Continuously changing the width of an element with setInterval( )

So I want to change the width of a span element inside a h1 element that have the textContent changed every 4s with setInterval().I want to do that to add a transition to the width property to fill the space between the h1 and the next word that span will have smoothly.
I tried to get the width of the span with getBoundingClientRect() but that didn't work and when I set the width it remains the width of the first element and it's not changed dynamically as I would want.
Here is the code:
const changingSpan = document.querySelector('.changing-span');
let array = ['best', 'tastiest', 'freshest'];
let count = 0;
setInterval(function() {
count++;
let elementWidth = changingSpan.getBoundingClientRect().width.toString();
if(count === array.length) count = 0;
changingSpan.classList.add('animation-span');
changingSpan.textContent = array[count];
changingSpan.style.width = `${elementWidth}px`;
changingSpan.addEventListener('animationend', function() {
changingSpan.classList.remove('animation-span');
})
}, 4000);
.changing-span {
display: inline-block;
color: #c82929;
transition: width .2s ease;
}
.animation-span {
animation: moveDown .8s ease;
}
#keyframes moveDown {
0% {opacity: 0;
transform: translateY(-50%);
}
100% {
transform: translateY(0);
}
}
<h1 class="first-heading">The <span class="changing-span">best</span> burgers in town.</h1>
consider an animation using max-width:
const changingSpan = document.querySelector('.changing-span');
let array = ['best', 'tastiest', 'freshest'];
let count = 0;
setInterval(function() {
count++;
if (count === array.length) count = 0;
changingSpan.classList.add('animation-span');
changingSpan.textContent = array[count];
changingSpan.addEventListener('animationend', function() {
changingSpan.classList.remove('animation-span');
})
}, 4000);
.changing-span {
display: inline-block;
color: #c82929;
}
.animation-span {
animation: moveDown .8s ease;
}
#keyframes moveDown {
0% {
opacity: 0;
transform: translateY(-50%);
max-width:0;
}
100% {
transform: translateY(0);
max-width:200px; /* a big value here */
}
}
<h1 class="first-heading">The <span class="changing-span">best</span> burgers in town.</h1>
Your code is very good.
But you need to remove 2 rows like below, then you code works well as you want
let elementWidth = changingSpan.getBoundingClientRect().width.toString();
changingSpan.style.width = ${elementWidth}px;
So the answer was posted by Sean above(Thank you). I will put here the code snippet for this in case somebody will search for something similar and will want to do the same thing:
const changingSpan = document.querySelector('.changing-span');
const changingSpanWrapper = document.querySelector('.changing-span-wrapper');
let array = ['best', 'tastiest', 'freshest'];
let count = 0;
changingSpanWrapper.style.width = `${changingSpan.getBoundingClientRect().width.toString()}px`;
setInterval(function() {
count++;
if(count === array.length) count = 0;
changingSpan.classList.add('animation-span');
changingSpan.textContent = array[count];
changingSpan.addEventListener('animationstart', function() {
let elementWidth = changingSpan.getBoundingClientRect().width.toString();
let elementHeight = changingSpan.getBoundingClientRect().height.toString();
changingSpanWrapper.style.width = `${elementWidth}px`;
changingSpanWrapper.style.height = `${elementHeight}px`;
})
changingSpan.addEventListener('animationend', function() {
changingSpan.classList.remove('animation-span');
})
}, 4000);
.changing-span-wrapper {
display: inline-block;
transition: width .2s ease, height .2s ease;
}
.changing-span {
display: inline-block;
color: #c82929;
}
.animation-span {
animation: moveDown 1s ease;
}
#keyframes moveDown {
0% {opacity: 0;
transform: translateY(-50%);
}
100% {
transform: translateY(0);
}
}
<h1 class="first-heading">The <span class="changing-span-wrapper"><span class="changing-span">best</span></span> burgers in town.</h1>

Is there a more concise way to write this without a bunch of IF statements?

This script uses intersection observer to look for anything with the class ".anim-target" and then looks to see if it also contains another class ("anim-target-NAME") that tells it which class to add. Then it removes it once it's out of view so it can re-animate again. Is there a more concise way to write it without relying on individual IF statements?
document.addEventListener("DOMContentLoaded", function(event) {
observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (entry.target.classList.contains('anim-target-fadeIn')) {
entry.target.classList.add('animated', 'fadeIn');
}
if (entry.target.classList.contains('anim-target-fadeInUp')) {
entry.target.classList.add('animated', 'fadeInUp');
}
if (entry.target.classList.contains('anim-target-bounceIn')) {
entry.target.classList.add('animated', 'bounceIn');
}
if (entry.target.classList.contains('anim-target-zoomIn')) {
entry.target.classList.add('animated', 'zoomIn');
entry.target.style.opacity = 1;
}
}
else {
entry.target.classList.remove('animated', 'fadeIn', 'fadeInUp', 'bounceIn', 'zoomIn');
entry.target.style.opacity = 0;
}
});
});
document.querySelectorAll('.anim-target').forEach(image => {
observer.observe(image);
});
});
You can replace
if (entry.target.classList.contains('anim-target-fadeIn')) {
entry.target.classList.add('animated', 'fadeIn');
}
if (entry.target.classList.contains('anim-target-fadeInUp')) {
entry.target.classList.add('animated', 'fadeInUp');
}
if (entry.target.classList.contains('anim-target-bounceIn')) {
entry.target.classList.add('animated', 'bounceIn');
}
if (entry.target.classList.contains('anim-target-zoomIn')) {
entry.target.classList.add('animated', 'zoomIn');
entry.target.style.opacity = 1;
}
with
var classList = entry.target.classList;
entry.target.classList.add('animated', classList.split('-')[2]);
if (classList.contains('anim-target-zoomIn')) {
entry.target.style.opacity = 1;
}
Use just a single class .anim and the desired animation-type class.
Use classList.toggle() to toggle/trigger the .animated class:
const animEntry = (ent) => ent.target.classList.toggle('animated', ent.isIntersecting);
const animObserve = () => {
const observer = new IntersectionObserver(ents => ents.forEach(animEntry));
document.querySelectorAll('.anim').forEach(el => observer.observe(el));
}
document.addEventListener("DOMContentLoaded", animObserve);
.anim {
height: 50vh;
width: 50vh;
background: #f48024;
position: relative;
transition: 1.2s;
margin: 500px auto;
}
.fadeIn {opacity:0;}
.fadeIn.animated {opacity:1;}
.fadeInUp {opacity:0; transform: translateY(100%); }
.fadeInUp.animated {opacity:1; transform: translateY(0%);}
.zoomIn {transform: scale(0);}
.zoomIn.animated {transform: scale(1);}
.rotateCW {transform: rotate(0deg);}
.rotateCW.animated {transform: rotate(1turn);}
Scroll down...
<div class="anim fadeIn">fadeIn</div>
<div class="anim fadeInUp">fadeInUp</div>
<div class="anim zoomIn fadeIn">zoomIn & fadeIn</div>
<div class="anim rotateCW">rotateCW</div>
Consider making your code DRYer:
DRY:
let animArr = ["animated"]
let etcl = entry.target.classList
if (etcl.contains("anim-target-fadeIn")) {
animArr.push(["fadeIn"])
}
if (etcl.contains("anim-target-fadeInUp")) {
animArr.push(["fadeInUp"])
}
if (etcl.contains("anim-target-bounceIn")) {
animArr.push(["bounceIn"])
}
if (etcl.contains("anim-target-zoomIn")) {
animArr.push(["zoomIn"])
entry.target.style.opacity = 1;
}
etcl.add(...animArr)
Even DRYer:
let animStyles = ["fadeIn","fadeInUp","bounceIn","zoomIn"]
let et = entry.target
let animArr = []
animStyles.forEach(style => {
if(et.classList.contains("anim-target-" + style)){
animArr = animArr.concat(["animated", style])
}
}
et.style.opacity = et.classList.contains("anim-target-zoomIn") ? 1 : 0
et.classList.add(...animArr)

Cannot get setTimeout working

I am working on a simple css animation for webkit. A number of elements will slide in and then unfold.
My idea is to keep to have a single css animation and trigger it by adding the slideIn class with jquery.
.slideIn {
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-iteration-count: 1;
-webkit-animation-fill-mode: forwards;
-webkit-animation-name: slideIn;
clip: rect(0,125px,315px,0);
}
#-webkit-keyframes slideIn {
0% { -webkit-transform: translateX(0); }
50% { -webkit-transform: translateX(-700px); clip: rect(0,125px,315px,0); }
100% { -webkit-transform: translateX(-700px); clip: rect(0,550px,315px,0); }
}
As I mentioned, there are more than one item on the page and I want them to slide in one by one. So I need to add the slideIn class one by one, with somtehing like:
var pref = "animated";
var animClass = "slideIn";
var eNumber = 5;
var interval = 10000;
animateMultiple(pref, eNumber, interval, animClass);
function animateMultiple(pref, eNumber, interval, animClass) {
var i = 0;
function addAnimClass() {
i++;
$('#' + pref + i).addClass(animClass);
if(i < eNumber){
setTimeout(addAnimClass(), interval);
}
}
addAnimClass ();
}
Yet, this ends in all the element sliding in alltogether.
Why does not the interval have any effect?
setTimeout(addAnimClass(), interval);
You are (immediately) calling addAnimClass and passing its return value (undefined) to setTimeout.
Remove the ().

How to hide elements (with smooth transition) by class with javascript?

I have a group of divs that share the same class (optionsclass). The display is set to block. When a user clicks them the following javascript function is executed the display is changed to none.
function hideBlockElementsByClass(className)
{
var elements = document.getElementsByClassName(className);
for(i in elements)
{
elements[i].style.display = "none";
}
}
The transition between display block and none is quite rough and I would like to make a smoother transition. What's the best strategy to accomplish this?
Use CSS3 :
.className {
opacity: 0;
visibility: hidden;
-webkit-transition: visibility 0.2s linear,
opacity 0.2s linear;
-moz-transition: visibility 0.2s linear,
opacity 0.2s linear;
-o-transition: visibility 0.2s linear,
opacity 0.2s linear;
}
.className:hover {
visibility: visible;
opacity: 1;
}
While Sridhar gives a nice CSS3 solution and other mention Jquery.
Here you can find a pure javascript/CSS solution:
https://codereview.stackexchange.com/questions/7315/fade-in-and-fade-out-in-pure-javascript
Try this method
HTML
<div class = "image" onclick = "eff()"></div>
CSS
.transition {
-moz-transition: 2s width;
width: 150px;
height: 100px;
}
Script
function eff() {
var k = document.getElementsByClassName("image");
k[0].className = "transition";
}
try this in plain javascript:(Will work on IE10, chrome, firefox, safari, android, ios)
<script>
function hideBlockElementsByClass(className) {
var elements = document.getElementsByClassName(className);
console.log(elements.length)
for (var i = 0; i < elements.length; i++) {
(function (a) {
elements[a].addEventListener('webkitTransitionEnd', function () {
elements[a].style.display = "none";
}, false);
elements[a].addEventListener('mozTransitionEnd', function () {
elements[a].style.display = "none";
}, false);
elements[a].addEventListener('oTransitionEnd', function () {
elements[a].style.display = "none";
}, false);
elements[a].addEventListener('transitionend', function () {
elements[a].style.display = "none";
}, false);
})(i);
elements[i].style.webkitTransitionDuration = "1s";
elements[i].style.mozTransitionDuration = "1s";
elements[i].style.oTransitionDuration = "1s";
elements[i].style.transitionDuration = "1s";
elements[i].style.opacity = "0";
}
}
</script>

Categories

Resources