I have a simple app that outputs messages when some actions are performed on a page, and it is done through the javascript createElement function, what I want to do is add a special style to only the newest message, so if a newer messages comes up the old newest message would revert to the old style. Is there any way to do this? when I createElement it seems all the divs would have to have the same class, and anything I try just applies the style to all the messages.
So is there anything to use in CSS that allows me to only apply a style to the newest member of a certain class?
here is how I create the new messages
function selfMsg(message) {
const msg = document.createElement('div');
msg.style.cssText = 'display: flex; justify-content: flex-end;background-color:aquamarine';
msg.innerText = message;
display.append(msg);
}
but all this does is style all the divs the same style, and I have no idea how I'm supposed to remove the style if a newer message comes up.
Ideally I'm looking for something in CSS that I can use in my stylesheet file that can target an entire class like how ".classnamehere" works, but only applies the style to the newest member of that class.
Depending on the container your divs are in, you can use CSS last:child (https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child) like this:
So if your container has the class display, you'd do
.display div:last-child {
display: flex;
justify-content: flex-end;
background-color:aquamarine
}
In case you don't know how to use this outside of javascript, simply wrap the above code in a style tag and add it to the head of your html document.
For clarity and possibly-upcoming-changes reasons, i highly suggest giving all of your divs a class on creation and using that instead of just div in the CSS. It's just easier to maintain that way.
.message-wrapper .message:last-child {
color: red;
}
<div class="message-wrapper">
<div class="message">Message 1</div>
<div class="message">Message 2</div>
<div class="message">Message 3</div>
</div>
You can use the :last-child pseudo selector. Something like:
.display div:last-child{
// your style
}
You can add a class to your messages like this:
msg.classList.add("mystyle");
Then use a css selector to only apply styles to the last element of this type
div.mystyle:last-of-type {
/* ... your styles */
}
Here's an example you can play with, from w3schools: https://www.w3schools.com/cssref/tryit.asp?filename=trycss3_last-of-type
If you want to use pure javascript, you could use element.removeAttribute("style") or element.style.cssText = null, but you would have to keep track of the previous message elements, or get ALL messages and loop through them, removing the style from all before adding the newest element. I'd recommend just using CSS.
Something along this line
The key is the :last-child pseudo class
"use strict";
console.clear();
document.getElementById('add').addEventListener('click', e => {
const target = document.getElementById('add-target')
const div = document.createElement('div')
const text = document.createTextNode(`#${target.querySelectorAll('div').length+1}`)
div.appendChild(text)
target.appendChild(div)
})
.container {
width: 600px;
margin: auto;
border: 1px solid gray;
}
.container > div {
--bg-in: lightgray;
--bg-out: transparent;
transition: background-color 1s;
padding: 20px;
font-family: sans-serif;
}
.container > div:not(:last-child) {
border-bottom: 1px solid gray;
-webkit-animation: anim-out 1s .3s both;
animation: anim-out 1s .3s both;
}
.container > div:last-child {
-webkit-animation: anim-in 1s both;
animation: anim-in 1s both;
}
#-webkit-keyframes anim-in {
from {
background-color: var(--bg-out, white);
}
to {
background-color: var(--bg-in, pink);
}
}
#keyframes anim-in {
from {
background-color: var(--bg-out, white);
}
to {
background-color: var(--bg-in, pink);
}
}
#-webkit-keyframes anim-out {
from {
background-color: var(--bg-in, pink);
}
to {
background-color: var(--bg-out, white);
}
}
#keyframes anim-out {
from {
background-color: var(--bg-in, pink);
}
to {
background-color: var(--bg-out, white);
}
}
<button id="add">Add</button>
<div class="container" id="add-target">
<div>#1</div>
<div>#2</div>
<div>#3</div>
</div>
Or—a little bit more sophisticated—with animationend event to implement a fadeoutafter some time
"use strict";
console.clear();
document.getElementById('add').addEventListener('click', e => {
const target = document.getElementById('add-target')
const div = document.createElement('div')
div.classList.add('in')
const text = document.createTextNode(`#${target.querySelectorAll('div').length+1}`)
div.appendChild(text)
target.appendChild(div)
})
document.addEventListener('animationend', e => {
e.target.classList.add('out');
e.target.classList.remove('in');
})
.container {
width: 600px;
margin: auto;
border: 1px solid gray;
}
.container > div {
--bg-in: lightgray;
--bg-peak: gray;
--bg-out: transparent;
transition: background-color 1s;
padding: 20px;
font-family: sans-serif;
}
.container > div:not(:last-child) {
border-bottom: 1px solid gray;
}
.container > div.out {
-webkit-animation: anim-out 1s 5s both ease-out;
animation: anim-out 1s 5s both ease-out;
}
.container > div.in {
-webkit-animation: anim-in 1s both;
animation: anim-in 1s both;
}
#-webkit-keyframes anim-in {
0% {
background-color: var(--bg-out, white);
}
25% {
background-color: var(--bg-peak, black);
}
100% {
background-color: var(--bg-in, pink);
}
}
#keyframes anim-in {
0% {
background-color: var(--bg-out, white);
}
25% {
background-color: var(--bg-peak, black);
}
100% {
background-color: var(--bg-in, pink);
}
}
#-webkit-keyframes anim-out {
from {
background-color: var(--bg-in, pink);
}
to {
background-color: var(--bg-out, white);
}
}
#keyframes anim-out {
from {
background-color: var(--bg-in, pink);
}
to {
background-color: var(--bg-out, white);
}
}
<button id="add">Add</button>
<div class="container" id="add-target">
<div>#1</div>
<div>#2</div>
<div>#3</div>
</div>
Related
CodePen
I am trying to replicate the letter flipping animation in Wordle. But I cannot manage the smooth chaining/sequencing. How can I fix it? (I guess I need to use the JS Promise feature, but yet to understand that concept.)
function myFunction() {
var tiles = document.getElementsByClassName("inner");
var myArray = Array.from(tiles);
myArray.map(function (tile) {
tile.classList.add("flip-in");
// tile.style.setProperty("--flipColor", "green");
tile.addEventListener(
"animationend",
() => {
tile.classList.remove("flip-in");
tile.style.backgroundColor = "green";
tile.classList.add("flip-out");
},
{
once: true
}
);
return;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", myFunction);
You've essentially done it but probably overengineered it a bit. The wordle animation is pretty simple to accomplish using only one animation.
First, let's take care of the CSS animation. Since we will only use one animation for the entire flip we can rename it "flip".
To simulate the card "flipping" we can adjust the scale on the height rather than flipping it. At the same time, we can also apply the background color change.
We can also remove the animation-delay styles. We will apply these dynamically in the JS.
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
We have to mark the animation as fill-mode: forwards
.flip {
animation: flip 500ms ease forwards;
}
Next, we can simplify the JS to only apply the class. Do some renaming to easier understand what everyone is and does. And here we can also dynamically apply the animation delay based on the index of the tile. This way we will support all different number of tiles.
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
Here's a working snippet:
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
.container {
width: 540px;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 2px;
}
.inner {
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
color: black;
width: 100px;
height: 100px;
background: white;
border: 2px solid black;
border-radius: 6px;
}
button {
margin: 50px;
font-size: 24px;
padding: 4px;
}
.flip {
animation: flip 500ms ease forwards;
}
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
<div class="container">
<div class="inner">S</div>
<div class="inner">T</div>
<div class="inner">A</div>
<div class="inner">C</div>
<div class="inner">K</div>
</div>
<button id="flipper"> Flipper </button>
I am trying to create a foldable menu, through CSS and JS. Css works (almost) correctly (the menu folds and unfolds, even if the class is not correctly applied) but not the JS code, which should change the innerText of the <li> acting as a button from ">" to "<" and opposite.
I have been messing around with js code for a while (making sure that document.getElementById is not undefined), but neither element.innerText or element.innerHTML seem to work properly.
I have two questions:
When applying an animation, and having two classes, shouldn't respect both classes (I mean, the navbar should be red)? Should I add nav class AFTER the animation is done, or fill the navbar in red color through the animation?
Why does ignore InnerText/InnerHTML instructions?? I have debugged the code and definitely goes through that instruction and I cannot understand why the change is not done...
var navButton;
var navbar;
const init = ()=>{
navbar = document.getElementById("navbar");
navButton = document.getElementById("foldButton");
navButton.addEventListener('click', function(){
if(navbar.className==="init nav" || navbar.className==="fade-out-right nav"){
navButton.InnerText=`<p><</p>`;
toggleFold();
}
else{
navButton.InnerText=`<p>></p>`;
toggleFold();
}
});
}
const toggleFold = () => {
if(navbar.className==="init nav" || navbar.className==="fade-out-right nav"){
navbar.className="fade-in-left nav";
}else{
navbar.className="fade-out-right nav";
}
};
* {
margin: 0;
padding: 0;
}
html {
box-sizing: border-box;
font-size: 62.5%;
scroll-behavior: smooth;
}
/* Base styles */
.nav {
display: flex;
justify-content: flex-end;
position: fixed;
top: 0;
left: 0;
width: 4%;
background: red;
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
z-index: 10;
}
.nav-list {
display: flex;
margin-right: 2rem;
list-style: none;
}
.nav-list li {
display: block;
font-size: 2.2rem;
padding: 2rem;
}
.nav-list a{
color:black
}
.nav-list a:hover {
background: blue;
}
.fade-in-left {
animation-name: fade-in-left;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
#keyframes fade-in-left {
from {
opacity: 1;
transform: translateX(-4%);
}
to {
opacity: 1;
transform: translateX(305px);
}
}
.fade-out-right {
animation-name: fade-out-right;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
#keyframes fade-out-right {
from {
opacity: 1;
transform: translateX(305px);
}
to {
opacity: 1;
transform: translateX(-4%);
}
}
<body onload="init()">
<nav id="navbar" class="init nav">
<ul class='nav-list'>
<li><a href='#welcome-section'>About</a></li>
<li><a href='#projects'>Work</a></li>
<li><a href='#contact'>Contact</a></li>
<li id="foldButton"><p>></p></li>
</ul>
</nav>
</body>
Thank you for helping me out.
Apart from my low IQ for the bad typo, whenever the color is not filled when using an animation, use internal container instead (in my case, I filled ul instead of navbar).
I wanna animate the background-color of an html element by class change (via js). The hover effect of the same element on the other hand shouldn't animate the change of the background-color.
Here is the scenario:
.cd-btn {
background-color: $black;
transition: background-color $colorChangeDuration ease;
&:hover {
background-color: $blue;
}
&.light-mode {
background-color: $lightgrey;
&:hover {
background-color: $blue;
}
}
}
The class 'light-mode' toggles with a other element with a javascript click event listener.
How can I keep the background-color transition on class change meanwhile there is no background-color transition on hover?
You can avoid transition on hover.
It's more difficult to avoid it also on unhover. Is this a request ?
function toggle() {
var ele = document.getElementById('test');
ele.classList.toggle ("alt");
}
.test {
height: 80px;
color: white;
background-color: black;
transition: 2s background-color;
}
.test.alt {
background-color: gray;
}
.test:hover {
background-color: blue;
transition: none;
}
<div class="test" id="test" >TEST</div>
<button onclick="toggle();">CHANGE</button>
I you want also the unhover without transition, you need a JS solution for this.
One posibility would be to meove the transition class after a timeout
function toggle() {
var ele = document.getElementById('test');
ele.classList.toggle ("alt");
ele.classList.add ("trans");
window.setTimeout (notrans, 2000);
}
function notrans() {
var ele = document.getElementById('test');
ele.classList.remove ("trans");
}
.test {
height: 80px;
color: white;
background-color: black;
}
.test.alt {
background-color: gray;
}
.test:hover {
background-color: blue;
}
.trans {
transition: 2s background-color;
}
<div class="test" id="test" >TEST</div>
<button onclick="toggle();">CHANGE</button>
I'm not sure I understand the question.
Here is the code working with hover
.cd-btn {
color: white;
background-color: black;
transition: background-color 0.5s ease;
}
.cd-btn:hover {
background-color: blue;
}
.cd-btn.light-mode {
background-color: lightgrey;
}
.cd-btn.light-mode:hover {
background-color: blue;
}
<h1>Hover to toggle</h1>
<button type="button" class="cd-btn">Normal cd-btn</button>
<button type="button" class="cd-btn light-mode">Light cd-btn</button>
Here is the transition working on click instead of on hover:
function toggle(el) {
el.classList.toggle('enable');
}
const elements = document.querySelectorAll('.cd-btn');
for (let el of elements) {
el.addEventListener('click', () => toggle(el));
}
.cd-btn {
color: white;
background-color: black;
transition: background-color 0.5s ease;
}
.cd-btn.light-mode {
background-color: lightgrey;
}
.cd-btn.enable {
background-color: blue;
}
<h1>Click to toggle</h1>
<button type="button" class="cd-btn">Normal cd-btn</button>
<button type="button" class="cd-btn light-mode">Light cd-btn</button>
The simple solution to this is to create a seperate class for just the transition:
.trans {
transition: .5s ease all;
}
Then use jQuery with the mouseenter / mouseleave events to apply the class, adding the transition effect duration as the amount of a delay on the mouseleave event, before reinstating the transition on the element.
$(document).on ('mouseenter', '.scrollToTop', function() {
$(this).removeClass ('trans');
});
$(document).on ('mouseleave', '.scrollToTop', function(e) {
setTimeout (function (e) {
$('.scrollToTop').addClass ('trans');
}, 500);
});
As long as the duration is > 0 then you get no transition effect; as the class state is already changed back prior to the class being added back to the dom (.5 of a second later, the duration of the transition effect).
i have a problem with javascript.I want to control the jumbotron color and set it every 3 seconds to a random one.The problem here is that i don't know how to manipulate CSS with JavaScript, as i am pretty new to javascript.
I saw some other solutions and some other threads but it did not work.(I don't know if i did anything wrong).
I have no js code written right now as i deleted everything that did not work.
.jumbotron {
background-color: #f14444 !important;
}
/*Without the !important rule it won't change color!*/
If you have any threads that you think i haven't checked i would be happy to check them but im confident enough to say that i've seen them already.
Thanks for your time anyways!
To change the background color, simply select the element and the set the property:
setTimeout(() => {
document.querySelector('.jumbotron').style.backgroundColor = '#f14444';
}, 1000);
.jumbotron {
height: 300px;
width: 300px;
background-color: black;
}
<div class="jumbotron"></div>
Note that above will select the first found element with the given class, so if you need to target a specific element, consider giving it an id and select it as #Phil shows above.
Html elements in the DOM have a style property.
document.getElementById('something').style.backgroundColor = '#ccc'
Note that hyphenated properties like background-color in CSS are typically camel-case (backgroundColor) in Javascript.
Also you can achieve it with keyframe animation
Here is a tutorial how to get random color
#-webkit-keyframes changeColors {
0% {
background-color: red;
}
50% {
background-color: blue;
}
100% {
background-color: green;
}
}
#-moz-keyframes changeColors {
0% {
background-color: red;
}
50% {
background-color: blue;
}
100% {
background-color: green;
}
}
#-ms-keyframes changeColors {
0% {
background-color: red;
}
50% {
background-color: blue;
}
100% {
background-color: green;
}
}
.jumbotron {
-webkit-animation: changeColors 3s infinite;
-moz-animation: changeColors 3s infinite;
-ms-animation: changeColors 3s infinite;
background-color: #f14444;
}
<div class="jumbotron">
Some text here
</div>
So a while back I think i saw an effect on some site that was transitioning between different background colors (changing background colors).
The color changed like every 2-3 seconds.
The transitions were pretty smooth as well. I found it pretty cool.
I'm redesigning my services website and would like to add that effect to my site.
There are 2 variables that need to be controlled: time and color.
P.S. Not trying to get anyone to write the code for me, but could you please refer me to some links where I can find out about this effect.
Would be great if you could tell me the name of this effect and the library it exists in.
Here's JS Fiddle that shows you some #keyframes in combo with the js to slow down timing via click. Hope that helps!
.body {
width: 100%;
height: 1000px;
animation-name: colorChange;
animation-duration: 10s;
animation-iteration-count: infinite;
text-align: center;
}
#keyframes colorChange {
0% {
background: red;
}
20% {
background: blue;
}
40% {
background: green;
}
60% {
background: orange;
}
80% {
background: purple;
}
100% {
background: red;
}
}
.button {
padding: 10px;
margin-top: 40px;
font-size: 20px;
}
$( ".button" ).on( "click", function () {
$( ".body" ).css( "animation-duration", "20s" )
})
Edit
Added snippet.
$( ".button" ).on( "click", function () {
$( ".body" ).css( "animation-duration", "20s" )
})
.body {
width: 100%;
height: 1000px;
animation-name: colorChange;
animation-duration: 10s;
animation-iteration-count: infinite;
text-align: center;
}
#keyframes colorChange {
0% {
background: red;
}
20% {
background: blue;
}
40% {
background: green;
}
60% {
background: orange;
}
80% {
background: purple;
}
100% {
background: red;
}
}
.button {
padding: 10px;
margin-top: 40px;
font-size: 20px;
}
<div class="body">
<button class="button">Change Timing</button>
</div>
To change your website background color in a defined time interval you can follow the bellow link.
http://www.cakephpexample.com/html/add-gradient-effect-to-your-website-by-javascript/
Where a complete example given with source code.
You can possibly do it with CSS3 animation keyframes.
Take a look at this Fun With Pulsing Background Colors in CSS3.