Reliable way to trigger one-way CSS transition? - javascript

I have designed a transition that changes instantly background color, then slowly recovers to original color:
body, html {margin: 0px;padding: 0px;}
div {
padding: 3px;
margin: 1px 0 1px 0;
border: 1px solid black;
background-color: #3377FF;
transition: background-color .9s ease-in;
}
div:hover {
background-color: #33FF11;
transition-duration: 0s;
}
<div> Hello</div>
<div> Hello</div>
This is designed for row in a table to notify user of a change. I'd like to trigger effect this programmatically, but by using the actual CSS.
Row.prototype.blink = function() {
... ?
}
I tried to use setTimeout to add and remove class name from the nodes:
$("div").on("click", function() {
$(this).addClass("updated");
var _this = this;
setTimeout(function(){$(_this).removeClass("updated");}, 30);
});
body, html {margin: 0px;padding: 0px;}
div {
padding: 3px;
margin: 1px 0 1px 0;
border: 1px solid black;
background-color: #3377FF;
transition: background-color .9s ease-in;
}
div.updated {
background-color: #33FF11;
transition-duration: 0s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click div to activate the blink effect:</p>
<div> Hello</div>
<div> Hello</div>
I also tried to use the transitioned event, but the event doesn't ever trigger:
$("div").on("click", function() {
$(this).one("transitionend", function(){$(this).removeClass("updated");}); // never happens
$(this).addClass("updated");
});
I don't like the setTimeout method, can't you think of better trick to trigger the blink effect?

The reason the transitionend event isn't being triggered is because transition-duration is set to 0s. In other words, the transition never begins until the class is removed (but the class isn't removed because the event isn't fired).
It really sounds like an animation would be better suited for this. Just listen to the animationend event and remove the class in the callback when the animation ends:
$('div').on('click', function() {
$(this).addClass('updated').one('animationend', function() {
$(this).removeClass('updated');
});
});
body, html {margin: 0px;padding: 0px;}
div {
padding: 3px;
margin: 1px 0 1px 0;
border: 1px solid black;
background-color: #3377FF;
cursor: pointer;
}
div.updated {
animation: updatedFade .9s ease-in forwards;
}
#keyframes updatedFade {
0% { background-color: #33FF11; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Hello</div>
<div>Hello</div>
As a work-around to your initial solution, you could change the transition-duration to something extremely short, like 1ms, so that the initial transition is actually started, thereby allowing the transitionend event to be fired:
$("div").on("click", function() {
$(this).addClass("updated").one("transitionend", function() {
$(this).removeClass("updated");
});
});
body, html {margin: 0px;padding: 0px;}
div {
padding: 3px;
margin: 1px 0 1px 0;
border: 1px solid black;
background-color: #3377FF;
transition: background-color .9s ease-in;
cursor: pointer;
}
div.updated {
background-color: #33FF11;
transition-duration: 1ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Hello</div>
<div>Hello</div>

Related

Display:inline-block before transition with pure Javascript

I am trying to animate a hidden menu box to appear and slide down when the mouse is over the button. It works properly, but when adding the transition display:inline-block -> display:none -> display:inline-block the transition disappears.
I already saw a few posts with solutions in jQuery, but none is pure JavaScript, if not for one using EventListener (that I was not able to apply to my case).
I tried to separate the JS in two functions, one to show the block, and and one to change the class. It did not work. One way would be to add something like an EventListener that would call a function after the display property is changed (just adding it in JS seems not sufficient). Any help is appreciated.
Here the code:
function overbutton(divname) {
element = document.getElementById(divname);
if (element.className == "menu_hidden menu_about") {
//element.style.display ="inline-block";
element.className = "menu_shown menu_about";
} else {
//element.style.display ="none";
element.className = "menu_hidden menu_about";
}
}
function onmenu(divname) {
//element.style.display ="inline-block";
element = document.getElementById(divname);
element.className = "menu_shown menu_about";
}
function outmenu(divname) {
//element.style.display ="none";
element = document.getElementById(divname);
element.className = "menu_hidden menu_about";
}
.menu_about {
background-color: white;
height: 100px;
width: 100px;
top: 20px;
left: 50px;
border-radius: 10px;
box-shadow: 0px 0px 10px #2B2B2B40;
-webkit-box-shadow: 0px 0px 10px #2B2B2B40;
-moz-box-shadow: 0px 0px 10px #2B2B2B40;
position: absolute;
padding: 20px;
}
.menu_hidden {
-webkit-transform: translate(0%, -5px);
transform: translate(0%, -5px);
transition: transform 0.3s;
-webkit-transition: -webkit-transform 0.3s;
}
.menu_shown {
-webkit-transform: translate(0%, 5px);
transform: translate(0%, 10px);
transition: transform 0.3s;
-webkit-transition: -webkit-transform 0.3s;
}
<div style="padding-left:100px">
<button class="button-menu" onmouseover="overbutton('about_menu_div')" onmouseout="overbutton('about_menu_div')">
menu Button
</button>
<!-- add style="display:none;"-->
<div id="about_menu_div" class="menu_hidden menu_about" onmouseover="onmenu('about_menu_div')" onmouseout="outmenu('about_menu_div')">
Menu
</div>
</div>
JSfiddle: https://jsfiddle.net/g0ktx574/
No need for any JavaScript in this case. You can solve this by using CSS, and more specifically, the :hover pseudo-class and the + adjacent sibling selector.
Also, the display property cannot be animated. Instead use opacity in combination with visibility.
.wrapper {
position: relative;
}
.menu_about {
position: absolute;
top: 100%;
left: 0;
background-color: white;
height: 100px;
width: 100px;
padding: 20px;
border-radius: 10px;
box-shadow: 0px 0px 10px #2B2B2B40;
opacity: 0;
visibility: hidden;
transition-property: opacity visibility transform;
transition: 0.3s;
}
.button-menu:hover + .menu_about,
.menu_about:hover {
opacity: 1;
visibility: visible;
transform: translate(0%, 5px);
}
<div class="wrapper">
<button class="button-menu">
menu Button
</button>
<div class="menu_about">
Menu
</div>
</div>
With reference to the solution posted here Transition translate animation immediately after display block, I have modified your code accordingly. One thing to keep in mind is that you cannot animate display property. So the below solution makes use of setTimeout function to achieve the start and end point of the transform property. I have also removed some css as well. You can have a look. You can adjust the transition timing, and transform property according to your need.
function overbutton(divname) {
element = document.getElementById(divname);
if (element.className == "menu_hidden menu_about") {
element.style.display ="inline-block";
element.className = "menu_shown menu_about";
element.style.transform = "translate(0%, 10px)";
element.style.transition = "transform .7s";
setTimeout(function() {
element.style.transform = 'translate(0%, 30px)';
element.style.transition = "transform .7s";
}, 0)
}else{
element.style.display ="none";
element.className = "menu_hidden menu_about";
}
}
function onmenu(divname) {
element.style.display ="inline-block";
element = document.getElementById(divname);
element.className = "menu_shown menu_about";
}
function outmenu(divname) {
element.style.display ="none";
element = document.getElementById(divname);
element.className = "menu_hidden menu_about";
}
.menu_about{
background-color:white;
height:100px;
width:100px;
top:20px;
left:50px;
border-radius: 10px;
box-shadow: 0px 0px 10px #2B2B2B40;
-webkit-box-shadow: 0px 0px 10px #2B2B2B40;
-moz-box-shadow: 0px 0px 10px #2B2B2B40;
position: absolute;
padding: 20px;
}
/* hide menu initially */
.menu_hidden {
display: none;
}
<div style="padding-left:100px">
<button class="button-menu" onmouseover="overbutton('about_menu_div')" onmouseout="overbutton('about_menu_div')">
menu Button
</button>
<!-- add style="display:none;"-->
<div id="about_menu_div" class="menu_hidden menu_about" onmouseover="onmenu('about_menu_div')" onmouseout="outmenu('about_menu_div')">
Menu
</div>
</div>

JQuery add class after another one was added and is visible

I have a button. I want to add to this button class: space and after this class was added and is visible in browser I want to add another class: spinner
I have tried with:
$("button").on("click", function(){
$(this).addClass("space");
$(this).addClass("spinner");
}
CSS:
.spacer{
transition: .3s !important;
padding-right: 3.1rem !important;
}
.spinner{
border: 5px solid #f3f3f3;
border-radius: 50%;
border-top: 5px solid #3498db;
width: 10px;
height: 10px;
animation: spin 2s linear infinite;
}
But it, obviously, doesn't work. Why?
Can a class be added to an element only after a class was added and has made its effect?
you could add the second class with a short timeout.this gives you also the possibility to add some animations if needed.
window.setTimeout(function() {
button.addClass("spinner");
},500);
promises will work to
You can add event listener to check if the transition is completed.
Consider the code below:
var el = document.getElementById('someelement');
debugger;
function transitionCallback(){
var t;
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
}
for(t in transitions){
if( el.style[t] !== undefined ){
return transitions[t];
}
}
}
/* Listen for transition */
var transitionEvent = transitionCallback();
transitionEvent && el.addEventListener(transitionEvent, function() {
console.log('Transition complete.');
});
/*transition example is from w3schools*/
#someelement {
width: 100px;
height: 100px;
background: red;
transition: width 2s;
-webkit-transition: width 2s; /* Safari 3.1 to 6.0 */
}
#someelement:hover {
width: 300px;
}
<html>
<head>
</head>
<body>
<div id="someelement"></div>
</body>
</html>
Use animation-delay to set a delay before it starts to run. I set it to a big number just so you can see the delay.
document.querySelector('button')
.addEventListener('click', event => {
event.preventDefault()
const classList = event.target.classList
classList.toggle('spacer')
classList.toggle('spinner')
})
.spacer{
transition: .3s !important;
padding-right: 3.1rem !important;
}
.spinner{
border: 5px solid #f3f3f3;
border-radius: 50%;
border-top: 5px solid #3498db;
width: 10px;
height: 10px;
animation: spin 2s linear infinite;
animation-delay: 2s;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<button></button>

Detect property of the transition end

I sought to detect the property of which the transition is completed in the case of several transitions of the same element with different delay, like:
var cssTransitionEnd = 'webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend';
$('div').on(cssTransitionEnd, function(e) {
var borderColorEnd, backgroundColorEnd;
// Detect if this is border or background who ended ?
if(borderColorEnd) {
}
if(backgroundColorEnd) {
}
});
div {
width: 200px;
height: 200px;
background-color: red;
border: 4px solid yellow;
transition: border-color 1s, background-color 2s;
}
div:hover {
border-color: green;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
You can use the propertyName property that comes with the transtionend event to find the name of the property whose transition has ended.
One thing to note with this property is that it will not return the shorthand property names. Instead it will return the following longhand names for the border-color property:
border-left-color
border-right-color
border-top-color
border-bottom-color
Note: For some reason, accessing the propertyName property of the JS event object does not seem to work on Firefox (but works on Chrome). Using jQuery's event object instead of it seems to work as expected. Can only assume that there is some browser inconsistencies that jQuery does a good job of solving for us.
var cssTransitionEnd = 'webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend';
$('div').on(cssTransitionEnd, function(event) {
/* Just to make the output obvious :) */
$('div').html($('div').html() + event.originalEvent.propertyName + '<br>');
});
div {
width: 200px;
height: 200px;
background-color: red;
border: 4px solid yellow;
transition: border-color 1s, background-color 2s;
}
div:hover {
border-color: green;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>

How do I change the colour of an SVG shape using jQuery?

Hi, folks! New here! Hoping to contribute a fair amount to the community in the future. But first, I need a hand with something I imagine to be fairly simple!
I've always been all about the design aspect of the web, so mainly concentrated on HTML and CSS. I've only recently started looking in to learning JavaScript/jQuery, so bear with me, haha!
I'm having a little trouble with changing the colour of an SVG shape using jQuery. The basic idea is that when the user scrolls down the page, certain elements will change colour. The HTML elements change as expected, but the SVG properties don't. I've read something about SVG DOM being different to HTML DOM, but can't really make much sense of it? A small explanation along with any help wouldn't be ignored!
Here is my HTML:
<header>
<div id="headercontainer">
<object id="logo" type="image/svg+xml" data="images/kennyheardlogo.svg"></object>
<nav><a id="homelink" href="index.html">HOME</a> | <a id="aboutlink" href="index.html">ABOUT</a> | <a id="worklink" href="index.html">WORK</a> | <a id="sociallink" href="index.html">SOCIAL</a></nav>
</div>
</header>
Here is my CSS:
header {
position: fixed;
z-index: 1;
width: 100%;
height: 150px;
background-color: #ffffff;
-webkit-box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5);
-moz-box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5);
box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5);
opacity: 0.8;
-webkit-transition: background-color 0.5s ease;
-moz-transition: background-color 0.5s ease;
transition: background-color 0.5s ease;
}
.headerfade {
background-color: #000000;
}
nav {
position: absolute;
top: 65px;
right: 40px;
width: 480px;
height: auto;
color: #000000;
text-align: center;
letter-spacing: 10px;
font-size: 10px;
}
nav, nav a {
-webkit-transition: color 0.5s ease;
-moz-transition: color 0.5s ease;
transition: color 0.5s ease;
}
.navfade {
color: #ffffff !important;
}
#icon {
fill: #000000;
}
.iconfade {
fill: #ffffff;
}
#letterk, #letterh {
fill: #ffffff;
}
#text path {
fill: #000000;
}
Here is my jQuery:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 350) {
$("header").addClass("headerfade");
$("nav, nav a").addClass("navfade");
$("#icon").addClass("iconfade");
} else {
$("header").removeClass("headerfade");
$("nav, nav a").removeClass("navfade");
$("#icon").removeClass("iconfade");
}
});
The initial colour of "#icon" is black, but when the user scrolls 350px from the top of the page, I want the colour to change to white. That is what I have done with the "header" and "nav" elements, which worked perfectly. So, any ideas?
I'm hoping I've not missed something embarrassingly obvious, haha!
Thanks for any help you can provide, guys!
There are two things wrong here.
You can't directly access the contents of an <object> like that. You need to get the contentDocument and access it that way.
CSS doesn't work across document boundaries. Even once you add the iconfade class to #icon, it won't be able to see it because the CSS is in a different document.
What you can do is inline the SVG file in your HTML. It should work then.

jQuery - Click Add/Remove Class - Multiple Buttons

For some reason when I add the second click function it stops working completely. I was wondering if anybody could help pin point what the issue might be?
What I'm trying to do:
The default state is "day" and when "night" is clicked, it removes the day class and adds the night class. Which changes the background image. Which works... Sort of. However, when I add the function for the day button to add the day class and remove the night class is breaks and doesn't work.
Here's a fiddle of what I have: http://jsfiddle.net/790hqykq/3/
$(document).ready(function () {
$('.night').click(function () {
$('#room').addClass('night');
$('#room').removeClass('day');
});
$('.day').click(function () {
$('#room').addClass('day');
$('#room').removeClass('night');
});
});
Thanks!!
Edit: Also - Is there any way to fade this class change? Similar to fadeIn/fadeOut? Thanks!
jsFiddle Demo
The problem with your fiddle is that the #room element has the class day. So does the anchor element. When the event handler is setup
$('.day').click(function () {
It is also assigned to the room element, and as a result of that, #room ends up also having the event handler attached to it. This causes day to always be selected as the element's class, even when night is clicked.
You should consider changing the class name to something like daycolor and nightcolor
<div id="room" class="daycolor">
and
#room.daycolor {
background: #00CCFF;
}
The element with ID room has the class day, as one of the elements within it.
When you attach the handler, it's being attached to both elements.
This should solve your problem:
$(document).ready(function () {
$('.timeButton.day').click(function () {
$('#room').addClass('day').removeClass('night');
});
$('.timeButton.night').click(function () {
$('#room').addClass('night').removeClass('day');
});
});
As per your complement about fading, you can use CSS 3 to achieve this:
#room {
-webkit-transition: background 0.5s linear;
-moz-transition: background 0.5s linear;
-ms-transition: background 0.5s linear;
-o-transition: background 0.5s linear;
transition: background 0.5s linear;
}
Demo
Change the classnames on your children elements and use that selector for your events.
jsFiddle
HTML:
<div id="container">
<div id="room" class="day">
<a class="timeButton day1">Day</a>
<a class="timeButton night1">Night</a>
</div>
</div>
JS:
$(document).ready(function () {
$('.night1').click(function () {
$('#room').addClass('night');
$('#room').removeClass('day');
});
$('.day1').click(function () {
$('#room').addClass('day');
$('#room').removeClass('night');
});
});
Style:
#container {
width: 300px;
margin: 0 auto;
}
#container a, #container div {
float: left;
display: block;
}
#room {
width: 300px;
height: 200px;
position: relative;
}
#room.day {
background: #00CCFF;
}
#room.night {
background: #0000CC;
}
#room .day1 {
left: 30px;
border: 1px solid black;
}
#room .night1 {
right: 30px;
border: 1px solid black;
}
#room .timeButton {
position: absolute;
width: 80px;
height: 25px;
top: 30px;
cursor: pointer;
text-align: center;
}
#room .timeButton:hover {
background: #fff;
}
Here is another solution, where I just change the css-style via jquery.
Javascript:
$(document).ready(function () {
$('.day').click(function () {
$('#room').css("background-color", "#00CCFF");
});
$('.night').click(function () {
$('#room').css("background-color", "#0000CC");
});
});
Also you need to add a background-color to #room:
background: #00CCFF;
Fiddle:
http://jsfiddle.net/790hqykq/7/
In your script, you reference to ".night" instead ".nightButton".
$('.nightButton').click(function () {
$('#room').addClass('night');
$('#room').removeClass('day');
});
$('.dayButton').click(function () {
$('#room').addClass('day');
$('#room').removeClass('night');
});
To achieve the transition, you can add this CSS propertie to #room.
-webkit-transition: background 2s; /* For Safari 3.1 to 6.0 */
transition: background 2s;
http://jsfiddle.net/790hqykq/13/
you can add css3 for the transitions from day to night.
it wont working in older IE browsers 9 and under but is excellent in all modern browsers.
browser support. You can use this generator to make the code faster.
#room {
width: 300px;
height: 200px;
position: relative;
-webkit-transition: background 1000ms ease-in-out;
-moz-transition: background 1000ms ease-in-out;
-ms-transition: background 1000ms ease-in-out;
-o-transition: background 1000ms ease-in-out;
transition: background 1000ms ease-in-out;
}
Demo jsfiddle

Categories