Can't trigger transition by toggling classes with jQuery - javascript

I want to make a simple transition but struggle doing it with jQuery.
I create the element that is to be transformed in JS in an eventListener like so:
const searchHint = `
<h3 id="search_hint" class="invizible">
Enter a search term to continue!
</h3>
`
$('#search_label').append(searchHint)
$('#search_hint').removeClass('invizible').addClass('make_vizible')
In my stylesheet I've got those styles for the classes 'invizible' and 'make_vizible':
#search_hint.invizible {
color: white;
transition: color 1s ease;
}
#search_hint.make_vizible {
color: #404040;
}
As I understand, this should result in the search hint element slowly fading in. I create it with the invizible class, where a transition attribute is present and also a start value for the attribute to be transformed. Then I switch the classes, to a class with a different color value.
What happens, is that the element is just displayed, not animated.
Any ideas?

There are two issues:
The transition property is set in invizible class. So once you remove it, that property is not applicable. To resolve this, associate the transition to the element id.
The removeClass and addClass are probably getting applied to the same frame that appends #search_hint while rendering. To mitigate this you could wait for the frame to render, and then add/remove the class. I've done this using setTimeout with timeout value zero.
const searchHint = `
<h3 id="search_hint" class="invizible">
Enter a search term to continue!
</h3>
`;
$('#search_label').append(searchHint);
setTimeout(function() {
$('#search_hint').removeClass('invizible').addClass('make_vizible');
},0);
#search_hint {
color: white;
transition: color 1s ease;
}
#search_hint.invizible {
color: white;
}
#search_hint.make_vizible {
color: #404040;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="search_label">
</div>

Related

How can I figure out what size an HTML Element will be? (tween size as element added)

I'm pretty sure this is currently infeasable.
I have an animation that involves an element moving from an absolute position to an inline one. For reasons, I can not know how the container is sized, nor how the element I'm animating is sized.
What I need to know is what the size of the HTML Element will be after the transformation, without any jittery drawing.
This makes the problem very difficult (likely undoable) because I have no way to know if adding the element will resize the parent, or resize the element itself.
What I need is a means of looking into the future.
const byId = (id) => document.getElementById(id);
#container {
height: 3em;
min-width: 50%;
background: teal;
}
#mystery {
background: purple;
}
<div id="container">
<div id="mystery">Some Text</div>
</div>
<button onClick='byId("mystery").style.position = "relative"'>Position Relative</button>
<button onClick='byId("mystery").style.position = "absolute"'>Position Absolute</button>
Currently, these are the only solutions I can imagine (they're all absurd):
Clone the entire webpage HTML, make the clone have opacity: 0; pointer-events: none and render what the future will be secretly.
Capture the paint data of the current page (basically screenshot), overlay that while secretly modifying the page, get my future, revert, and remove the screenshot overlay.
Similar to number 2, is there a way to ❄️freeze❄️ rendering of a page for 3-4 frames?
I remember seeing a "sizing worker" something-or-rather a long time ago. Couldn't find any information on it now, but it seems like it might be useful?
You can simply change the property, measure the sizes you want and then change the property back. JS is fast enough to do it all between renderings, as long as you keep it all in the same thread. Have you tried that at all?
Asker Edit:
Here's the code to prove it works.
function byId(id){ return document.getElementById(id); }
const tweenyEl = byId("tweeny");
function appendTweeny() {
tweenyEl.style.opacity = "1";
const startingWidth = tweenyEl.clientWidth + "px"
tweenyEl.style.position = "relative";
const targetWidth = tweenyEl.clientWidth + "px";
console.log(startingWidth, targetWidth);
tweenyEl.style.width = startingWidth;
requestAnimationFrame(() =>
requestAnimationFrame(() =>
tweenyEl.style.width = targetWidth
)
);
}
function resetTweeny() {
tweenyEl.style.position = "";
tweenyEl.style.width = "";
tweenyEl.style.opacity = "0.1";
}
#container {
display: inline-block;
height: 3em;
min-width: 150px;
background: teal;
}
#tweeny {
font-family: arial;
color: white;
position: absolute;
background: purple;
transition: all 0.5s ease;
opacity: 0.1;
}
<div id="container">
<div id="tweeny">I'm Tweeny</div>
</div>
<br>
<button onClick='appendTweeny()'>Append Tweeny</button>
<button onClick='resetTweeny()'>Reset Tweeny</button>
I would suggest cloning the page into an iframe and then positioning the iframe off the screen.
<iframe style="width:100vw;height:100vh;left:-101vw;positionabsolute"><iframe>
Also bear in mind that the user can zoom in-and-out at will! Different browsers might render the same thing in different ways. You really don't know how big an element will be until it does so.
I don't know if you can get anywhere by specifying display: none; ... whether or not the browser would bother to make these calculations for an object that isn't visible.
You can clone on the fly an element with same transformation with delay 0 and then calculate it's width and height, then do what you want with your actual element it's still animating

Change Link Visibility -- Event Listener with mouseover and getElementsByClassName

I am relatively new to JavaScript.
I've searched the internet over and found what people are calling solutions and correct scripts and fixes etc., but none of them seem to work for me so I'm clearly missing something. Been troubleshooting for hours now. Please help!
CSS: I have created a simple two-column div (out of 12, it's floated left). I have a CSS transition in place to pull it from 2% width to 15% width (nearly the full two columns) on hover.
HTML: I created a few test links in the div which I've hidden with a CSS class.
JS: I am trying to use JavaScript to make them visible when the mouse is over the div.
HTML:
<div id="linkpopout" class="col-2 popout">
Bing
Yahoo
Google
</div>
CSS:
.col-2 {width: 16.66%;}
.popout {
background:lightblue;
transition:width 0.5s, height 0.5s;
transition-timing-function:ease-out;
width:2%;
height:300px;
float:left;
}
.popout:hover {
width:15%;
height:300px;
}
.menulinks {
visibility:hidden;
}
JS:
var linkpop = document.getElementById("linkpopout");
var popoutlinks = document.getElementsByClassName("menulinks");
linkpop.addEventListener("mouseover", makeVisible);
function makeVisible() {
popoutlinks.style.visibility="visible";
}
For what it's worth, I've also tried document.getElementsByClassName(menulinks").style.visibility="visible";
without any luck and I've tried accomplishing the same thing using opacity instead of visibility and that made no difference.
Thank you.
No need for JavaScript.
.col-2 {width: 16.66%;}
.popout {
background:lightblue;
transition:width 0.5s, height 0.5s;
transition-timing-function:ease-out;
width:2%;
height:300px;
float:left;
}
.popout:hover {
width:15%;
height:300px;
}
.menulinks {
visibility:hidden;
}
.popout:hover .menulinks {
visibility: visible;
}
<div id="linkpopout" class="col-2 popout">
Bing
Yahoo
Google
</div>
If you want to toggle the visibility of the links depending on whether the menu is showing or not. You can do it like this;
JS:
<script>
var linkpop = document.getElementById("linkpopout");
var popoutlinks = document.getElementsByClassName("menulinks");
linkpop.addEventListener("mouseover", makeVisible);
linkpop.addEventListener("mouseout", makeVisible);
function makeVisible() {
for (let i = 0; i < popoutlinks.length; i++) {
popoutlinks[i].classList.toggle("vis");
}
}
</script>
The 'toggle' method of 'classList' which is bound to an element will add or remove the class from the element depending on its current state. If the class is there, it will remove it, otherwise, it will add it. Very useful for popout menus like this. We have to loop through all of the elements, in this case your menulinks and toggle the class per element.
Then have a class to toggle on or off. Default state is bound to the default class you want for the element.
CSS:
.menulinks { visibility:hidden; }
.vis { visibility:visible }
You need to loop through the DOM elements:
getElementsByClassName
Returns an array-like object of all child elements which have all of the given class names. When called on the document object, the complete document is searched, including the root node. You may also call getElementsByClassName() on any element; it will return only elements which are descendants of the specified root element with the given class names.
function makeVisible() {
popoutlinks.forEach(function(e) {
e.style.visibility="visible";
});
}

Opacity transition works on fade out, but not fade in

This is frustrating me to no end. Before I post the code, here's a summary:
The goal, in simple terms: when I double click X, I want it to fade out; when I click Y, I want X to fade in.
The method: I'm using CSS to create the actual fade-in and fade-out "animations." I'm using JavaScript to apply the classes when necessary using a little trickery.
The problem: the fade-in transition doesn't work -- the element just appears instantly. What is driving me insane is the fact that the fade-in, when instantly added back onto a faded-out object, works perfectly. I'll explain this better as a comment in the JS code.
(Yes, I've added opacity: 1 and transition: opacity onto the base elements. It had no effect at all.)
The code:
CSS
*.fade-out {
opacity: 0;
transition: opacity 400ms;
}
*.fade-in {
opacity: 1;
transition: opacity 400ms;
}
*.hide {
display: none;
visibility: hidden;
}
JavaScript
$( '#ArtistEmblem' ).on( 'dblclick', function() {
fadeOut($( '#ArtistEmblem' ));
fadeIn($( '#btnShowLogo' ));
});
$( '#btnShowLogo' ).on( 'click', function() {
fadeOut($( '#btnShowLogo' ));
fadeIn($( '#ArtistEmblem' ));
});
function fadeOut(element) {
element.addClass( 'fade-out' );
setTimeout( function () {
element.addClass( 'hide' );
/*
* I tried immediately adding the 'fade-in' class here
* and it worked -- as soon as the element faded out, it faded
* back in (using the CSS transition). However, outside of this,
* it REFUSES to work; everything appears instantly
*/
console.log('timer triggered');
}, 400);
}
function fadeIn(element) {
element.removeClass( 'hide' );
element.removeClass( 'fade-out' );
element.addClass( 'fade-in' );
}
Relevant HTML
<div id="ArtistEmblem">
<img src="img/logo_artist_2.png" />
</div>
<div id="PopMenu" class="collapse">
<article>
<header>
<b>Debug Menu</b>
</header>
<section>
<button id="btnOpenOverlay">Open Overlay</button>
<button id="btnShowLogo" class="hide">Show Logo</button>
<button id="btnClose">Close Menu</button>
</section>
</article>
</div>
I apologize if this is something obvious but I've wasted far too much time trying to solve it. I am also open to better, faster, or more efficient solutions if that would be the best answer. Thanks in advance!
The problem is that the initial opacity of "hidden" element is 1 by default. You just need to set it to 0. And also remove display: none –
*.hide {
opacity: 0;
}
Also I would do a little refactoring and remove setTimeout:
$('#ArtistEmblem').on('click', function() {
fade($('#btnShowLogo'), $(this));
});
$('#btnShowLogo').on('click', function() {
fade($('#ArtistEmblem'), $(this));
});
function fade(inElement, outElement) {
inElement.removeClass('hide');
inElement.addClass('fade-in');
outElement.removeClass('fade-in');
outElement.addClass('fade-out');
}
If you don't want the hidden element to occupy space and you want it to be displayed-none, then you need to set display: block before starting the fadeOut.
I know you're asking for a JS heavy answer, but I highly recommend toggling a class of "active", "open" or something similar and using CSS with the transition. Less is more here.
Here's an example fiddle of something I've transitions not only the opacity, but also the z-index. That's the key with these transitions if you intend on having any elements below such as buttons that require hovering, clicking, etc.
JS Fiddle
Key parts:
.container {
z-index: -1;
opacity: 0;
transition: z-index .01s 1s, opacity 1s;
}
.container.active {
transition: z-index 0s, opacity 1s;
z-index: 500;
opacity: 1;
}
EDIT
I was just messing around with this type of thing for my own project, and observing how beautiful Stripe handles their navigation bar. Something so simple changes everything, and that's pointer-events. If you're okay with its support, (notable no ie. 10) this is infinitely easier to integrate. Here's another fiddle of the simulation in a nav bar.
The key part is pointer-events: none, as it ignores click events if set to none, almost as if it wasn't there, yet visibly it is. I highly recommend this.
https://jsfiddle.net/joshmoxey/dd2sts7d/1/
Here is an example using Javascript Animate API. Animate API is not supported in IE/Edge though.
var element = document.getElementById("fade-in-out")
var button = document.getElementById("x")
button.addEventListener("click", function(event) {
element.animate([{opacity: 1, visibility: "visible"},{opacity: 0, visibility: "hidden"}], {duration: 2000})
setTimeout(function() { element.remove() }, 2000)
})
button.addEventListener("dblclick", function(event) {
element && element.animate([{opacity: 0}, {opacity: 1}], {duration: 2000})
})
<input id="x" type="button" value="Click here" />
<div id="fade-in-out"> FADE ME </div>

can't understand this jquery code

I am new to web development and am referring following link-
tic tac toe javascript
Please find below js, css and html file respectively.
We are not having any element with class="selected" but still project is running perfectly
$(".level").each(function() {
var $this = $(this);
$this.click(function() {
$('.selected').toggleClass('not-selected');
$('.selected').toggleClass('selected');
$this.toggleClass('not-selected');
$this.toggleClass('selected');
ai.level = $this.attr("id");
});
});
.level {
margin: 0 15px;
color: lightskyblue;
cursor: pointer;
}
.not-selected {
opacity: 0.5;
text-decoration:none;
}
.not-selected:hover {
opacity:1;
}
<div class='difficulty'>
<span class='level not-selected' id="blind">Blind</span>
<span class='level not-selected' id="novice">Novice</span>
<span class='level not-selected' id="master">Master!</span>
</div>
I am unable to understand this js.
Please clear my two doubts- 1.use of click inside each 2.how .selected work in jquery
The snippet won't work cause i didn't add jquery to it.
Toggle behavior - if the element has a class, the class will be removed. If the element hasn't got the class, the class will be added. In this case there are no elements with .select class, but it will be added after toggleClass('selected') executes. I commented every js line for you.
$(".level").each(function() { // for each element with class .level
var $this = $(this); // save the current jQuery object in the loop in the $this variable
$this.click(function() { // add a click event to the current object
$('.selected').toggleClass('not-selected'); // for the elements with .selectd class toggle .not-selectd class
$('.selected').toggleClass('selected'); // for the elements with .selectd class toggle .selectd class
$this.toggleClass('not-selected'); // for the current elements toggle .not-selectd class
$this.toggleClass('selected'); // for the current elements toggle .selectd class
ai.level = $this.attr("id"); // ai not defined in current context, will give an error, but if was defined you would save current element id in ai.level
});
});
This code could be written much easier and do the same. You don't need .selected class since there is no style for it in css
$(".level").click(function(){ // click event for elements with class .level
$(".level").addClass("not-selected"); // add .not-selected class to all .level elements
$(this).removeClass("not-selected"); // remove not-selected class from the CURRENT clicked element
});
.level {
margin: 0 15px;
color: lightskyblue;
cursor: pointer;
}
.not-selected {
opacity: 0.5;
text-decoration:none;
}
.not-selected:hover {
opacity:1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='difficulty'>
<span class='level not-selected' id="blind">Blind</span>
<span class='level not-selected' id="novice">Novice</span>
<span class='level not-selected' id="master">Master!</span>
</div>
Edit duo comments:
1.use of click inside each
In your case you are getting objects $(".level") and iterating through them. Inside the loop you are assigning to the current element a click event listener. this is unneeded you can just do $('.level').click(function(){}); with out iterating.
how .selected work in jquery
This is just a HTML class with no special behavior. You can just manage elements by it class. You can use any class you want like .my-super-class-name and use it. It's just a HTML attribute.

Trying to fade and slide text out of initials on mouse over with jQuery

I'm trying to create an effect with jQuery where on mouse over of my initials on the page in the header, the div they are in expands (using jQuery animate) and the text of my full name fades in from each initial.
I have tried a variety of things but am not sure what is the best way to do this. I'm a bit stuck. I'm currently trying to get it going by having the initials of my name "OW" in two separate divs and then the remainder of my name to make up "wen" and "illiams" in between those initals. Like so:
<div class="initialF inlinediv">O</div>
<div class="fullF inlinediv">wen</div>
<div class="initialL inlinediv">W</div>
<div class="fullL inlinediv">illiams</div>
I thought it would work to use jQuery slideLeft and .fadeIn to get the text to slide in from the left as well as fading to look like the text is emerging from the initials but the animations was jumpy and would go onto a second line while the div was still expanding. I am using the below jQuery to detect the mouseIn/Out events:
<script>
$(".brand").mouseenter(function() {
$('.brand').animate({width: '160px'});
$('.fullF').fadeIn("slow");
});
$(".brand").mouseout(function() {
$('.brand').animate({width: '36px'});
$('.fullF').fadeOut("slow");
});
</script>
The alternatives I have tried were using jquery.lettering.js to help with it but there seemed to be some issues with that. Any suggestions to push me in the right direction would be useful and my site with a partially working example is here:
http://192.241.203.146/
Here's one using css transitions rather than jquery animate: http://jsfiddle.net/S58Se/2/
<div class='branding'>
<span class='initial'>O</span><span class='hidden nameFull wen'>wen</span>
<span class='initial'>W</span><span class='hidden nameFull illiams'>illiams</span>
</div>
span {
display: inline-block;
overflow: hidden;
transition: all 1s;
-moz-transition: all 1s;
-webkit-transition: all 1s;
}
.wen { width: 36px; }
.illiams { width: 160px; }
span.hidden {
width: 0px;
opacity: 0;
}
$('.branding').hover(
function() { $('.nameFull').removeClass('hidden'); },
function() { $('.nameFull').addClass('hidden'); }
);
Or you can do away with the javascript altogether with this: http://jsfiddle.net/S58Se/3/
remove the js and add these css statements:
.branding:hover .wen {
width: 36px;
opacity: 1;
}
.branding:hover .illiams {
width: 160px;
opacity: 1;
}
... just because I think it's neat.
A good way to go about this is to just expand the use of your call to the animation method by adding another property to the object you are passing in. So instead of calling an extra method (fadeIn) you just handle it all in one fell swoop:
$('.brand').on({
'mouseenter' : function () {
$('.nameFull').stop().animate({
'width' : '200px',
'opacity' : '1'
}, 500);
},
'mouseleave' : function () {
$('.nameFull').stop().animate({
'width' : '0',
'opacity' : '0'
}, 500);
}
});
You'll notice I'm also using 'on' instead of the 'hover' or 'mouseenter' and 'mouseleave' methods. In most recent versions of jQuery those methods just reference 'on', so it's better to just cut out the middle man and do it all in one place.
I'm not sure if this exactly fits your design, but I made a Codepen to demonstrate the code in action: http://codepen.io/Tristan-zimmerman/pen/lnDGh
Style the hidden divs position:absolute, and when show them:
'show' them first, to set them visible
then position them (next to your 'launching' div), using jQuery.position();
set the animation going.
Essentially you want them 'absolute' to avoid them thunking in/out & changing your existing flow. position() must be called after making the element visible, and then you should have appropriate starting conditions to kick off your animation.
Or you could try using <span>' for the incoming text and/or displaying as inline-block, which may help avoid the "incoming" kicking things down a line. HTH.
I think what you are looking for is something like this: JSFiddle
html:
<div class="brand">
<div>O<span class="full">wen </span>W<span class="full">illiams</span></div>
</div>
jq:
$('.brand').hover(function(){
$(this).stop().animate({width: '160px'},'slow',function(){
$(this).children('div').children('.full').stop().fadeIn('slow');
});
},function(){
$(this).children('div').children('.full').stop().fadeOut('slow',function(){
$(this).parent().parent().stop().animate({width: '36px'},'slow');
});
});
css:
.full{
display: none;
}
note: there is a simple bug that happens in a specific case and I'm working on it.
regards,

Categories