Transition doesn' t work when class been removed by javascript - javascript

I am new with html, css and js and working on some baby projects to take more experience. This time I am learning how to use javascript on my site but I have a problem. I have an error-msg-block that I want to change its height with transition. Also in js I add the class that gives its properties and after 3s I remove it. When I add the class the transition works but when the class is been removed the transition stops working.
.transition-msg {
max-height: 0;
overflow: hidden;
-webkit-transition: max-height 0.5s ease-in-out;
-moz-transition: max-height 0.5s ease-in-out;
-o-transition: max-height 0.5s ease-in-out;
transition: max-height 0.5s ease-in-out;
}
.error-window {
max-height: 200px;
background-color: rgb(241, 128, 128);
border: #888 solid 0.04rem;
border-radius: 0.2rem;
}
<input type="submit" name="submit" value="Sign In" class="btn">
<div id="form-msg" class="transition-msg"></div>
function onSubmit(e) {
e.preventDefault();
if(firstnameInput.value === '' || lastnameInput.value === '' || passwordInput.value === '' || emailInput.value === '' || !termsBox.checked) {
//alert('Please enter all fields');
msg.classList.add('error-window');
msg.innerHTML = '<p>Please enter all fields</p>';
// Remove error after 3 seconds
setTimeout(() => {msg.innerHTML = ''; msg.classList.remove('error-window')}, 3000);

There are two problems with your code.
The first is that in your CSS you've placed the background-color property on modifier class (your .error-window) and as soon as that class is removed the background is instantly disappeared because of the transition is set only for max-height. To fix this, simply move the background-color to the parent class, the .transition-msg class.
The second problem with animating the max-height is that within your JS code you're removing the HTML before the transition is done so the height of that div instantly becomes zero (if there's no content there's no height).
The solution would be to wait until the transition of max-height property is done and then remove the HTML.
Here's working DEMO
Basically, what it shows is that you can use another setTimeout() method inside of your current but one with a delay of 500 milliseconds to match the CSS transition and then remove the HTML.
setTimeout(() => {
msg.classList.remove('error-window');
setTimeout(() => {
msg.innerHTML = '';
}, 500);
}, 3000);

Please use the transition to the main class
Here:
.transition-msg {
max-height: 0;
overflow: hidden;
}
.error-window {
max-height: 200px;
background-color: rgb(241, 128, 128);
border: #888 solid 0.04rem;
border-radius: 0.2rem;
-webkit-transition: max-height 0.5s ease-in-out;
-moz-transition: max-height 0.5s ease-in-out;
-o-transition: max-height 0.5s ease-in-out;
transition: max-height 0.5s ease-in-out;
}

Related

ngAnimate max-height not working on certain element

I've implemented ngAnimate into a project to help with animations, but I'm getting really odd behaviour with a certain element.
To add some background, we have a shop with categories and products inside the categories. I'm doing an ng-repeat with: data-ng-repeat="product in currentProductCategory.Products" and I have data-ng-class="{ 'open': product.ShowDetails == true }" on my root element.
My root element also has an id of product-{{product.Id}}-{{currentProductCategory.Id}} and I have a child element with id product-options-{{product.Id}}-{{currentProductCategory.Id}} which products expected results.
When clicking a button, I call a function that sets the max-height on the parent element to a desired height, and the animation is handled in the CSS. Here's the function code:
var reg = /\d+/g;
var productParentElement = $('#product-' + product.Id + '-' + $scope.currentProductCategory.Id);
var optionsElement = $('#product-options-' + product.Id + '-' + $scope.currentProductCategory.Id);
var productParentPaddingTop = parseInt(productParentElement.css("padding-top").match(reg));
var productParentPaddingBottom = parseInt(productParentElement.css("padding-bottom").match(reg));
var productParentTotalHeight = productParentPaddingTop + productParentPaddingBottom + productParentElement.height() + optionsElement.height();
var optionsElementPaddingTop = parseInt(optionsElement.css("padding-top").match(reg));
var optionsElementPaddingBottom = parseInt(optionsElement.css("padding-bottom").match(reg));
var optionsElementTotalHeight = optionsElementPaddingTop + optionsElementPaddingBottom + optionsElement.height();
var totalHeight = productParentTotalHeight + optionsElementTotalHeight;
if (product.ShowDetails) {
product.ShowDetails = true;
productParentElement.css("max-height", totalHeight);
} else {
product.ShowDetails = false;
productParentElement.removeAttr('style');
}
And my CSS for the closed and open classes:
Closed:
.products-list .product {
margin-bottom: 20px;
max-height: 200px;
overflow: hidden;
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
}
Open:
.products-list .product.open {
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
max-height: 200px;
}
The issue is that out of the many products over 4 categories, the same one which is the same product in each category is not animating open. It animates the close/shrink, but when opening, it just instantly appears open.
This has been gating on us for a long time now and it's becoming a real issue, any help is greatly appreciated.
UPDATE: Now none of the "products" will animate open, but they do animate closed. Could this be because I'm setting the max-height on the style rather than a class?
Sorry but this might sound like I am pointing out the obvious and I can't see the rest of your code but in your CSS, you have;
.products-list .product {
margin-bottom: 20px;
max-height: 200px;
overflow: hidden;
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
}
for your closed list which has a 'max-height: 200px' but is also the same in your open list;
.products-list .product.open {
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
max-height: 200px;
}
Which also has a max-height of 200px. So in this case you're asking it to transition from 200px to 200px. try changing the height of open classes to be bigger or smaller. Then it will transition.

Hide scrollbars, if not necessary - Ace editor

I've been experimenting with Ace Editor and I've been trying to automatically "hide" (= not use the system defaults) the vertical/horizontal scrollbars, when not in use.
Is there a way? Any ideas?
Just add overflow:auto css to the right element. I think that could be .ace_scroller. Give me example with scrollers or find by yourself using Object Inspector (Ctrl + Shift + I ; Chrome, FF, Opera).
Edit:
There is your code:
body .ace_scrollbar-v {
overflow-y: auto;
}
body .ace_scrollbar-h {
overflow-x: auto;
}
Edit2:
Hide scrollbar If editor isn't hovered:
body .ace_scrollbar {
display: none;
}
body .ace_editor:hover .ace_scrollbar {
display: block;
}
Or with animation:
body .ace_scrollbar {
-webkit-transition: opacity .3s ease-in-out;
-moz-transition: opacity .3s ease-in-out;
-ms-transition: opacity .3s ease-in-out;
-o-transition: opacity .3s ease-in-out;
transition: opacity .3s ease-in-out;
opacity: 0;
}
body .ace_editor:hover .ace_scrollbar {
opacity: 1;
}
You may want to set the word wrap too.
editor.getSession().setUseWrapMode(true)

How to add css transitions to js scroll in header?

I have a header that appears when the page scrolls down. I am trying to add css transitions to make it fade in and out because I've read that using javascript for fading is not as efficient.
.header-wrapper {
top:0;
left:0;
right:0;
position: fixed;
display:none;
height: 60px;
border-top: 1px solid #000;
background: red;
z-index: 1;
}
.header-wrapper.active {
display:block;
}
.header {
background-color:#000;
height:80px;
}
Here is the js fiddle
$(window).scroll(function () {
var y = $(window).scrollTop();
// if above 300 and doesn't have active class yet
if (y > 300 && !$('.header-wrapper').hasClass('active')) {
$('.header-wrapper').addClass('active');
// if below 300 has still has active class
} else if(y <= 300 && $('.header-wrapper').hasClass('active')) {
$('.header-wrapper').removeClass('active');
}
});
Transitions are added with the css3 property transition.
One common reason for confusion: you can only transition properties that accept numeric values. Thus, you can't transition between display: block and display: none.
However you can transition between opacity: 0 and opacity: 1 with:
transition: 0.5s opacity
That would look something like this:
.bottomMenu {
...
opacity: 0;
transition: 0.5s opacity;
...
}
.bottomMenu.active {
opacity: 1;
}
For your particular case, I might recommend transitioning the height between 0 and 60px.
For that you can use:
transition: 0.5s height
So:
.bottomMenu {
...
height: 0;
transition: 0.5s height;
...
}
.bottomMenu.active {
height: 80px;
}
To animate the opacity the element must be visible. So remove the display:none and make it fully transparent (opacity:0). You can then use CSS transitions to animate the opacity when the classname changes:
.bottomMenu {
...
display:block;
opacity: 0;
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.bottomMenu.active {
opacity:1
}
http://jsfiddle.net/oL9ro4gL/6/
Furthermore, you're not restricted to just animating the opacity:
.bottomMenu {
...
transition: all .25s ease-in-out;
}
.bottomMenu.active {
opacity:1;
height: 60px;
background-color: blue;
transform:rotate(180deg);
color:white;
font-size:40px;
etc...
}
http://jsfiddle.net/oL9ro4gL/8/
Unfortunately, you can't animate the display property. See this question and its suggestions for workarounds.

Slide down animation from display:none to display:block?

Is there a way to animate display:none to display:block using CSS so that the hidden div slides down instead of abruptly appearing, or should I go about this a different way?
$(document).ready(function() {
$('#box').click(function() {
$(this).find(".hidden").toggleClass('open');
});
});
#box {
height:auto;
background:#000;
color:#fff;
cursor:pointer;
}
.hidden {
height:200px;
display:none;
}
.hidden.open {
display:block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="box">
Initial Content
<div class="hidden">
This is hidden content
</div>
</div>
And a JSFiddle
Yes, there is a way:
http://jsfiddle.net/6C42Q/12/
By using CSS3 transitions, and manipulate height, rather than display property:
.hidden {
height: 0px;
-webkit-transition: height 0.5s linear;
-moz-transition: height 0.5s linear;
-ms-transition: height 0.5s linear;
-o-transition: height 0.5s linear;
transition: height 0.5s linear;
}
.hidden.open {
height: 200px;
-webkit-transition: height 0.5s linear;
-moz-transition: height 0.5s linear;
-ms-transition: height 0.5s linear;
-o-transition: height 0.5s linear;
transition: height 0.5s linear;
}
More here: Slide down div on click Pure CSS?
Since you're already using jQuery, the simplest thing is just to use slideDown(). http://api.jquery.com/slidedown/
There's also slideToggle().
Then you don't need to manually do all the browser-specific transition css.
I like the idea of CSS transitions, but it's still very jumpy. Sometimes the max-height has to be set to a very high number because of dynamic content which renders the transition useless as it's very jumpy. So, I went back to jQuery, but it had its own faults. inline elements are jumpy.
I found this to work for me:
$(this).find('.p').stop().css('display','block').hide().slideDown();
The stop stops all previous transitions.
The css makes sure it's treated as a block element even if it's not.
The hide hides that element, but jquery will remember it as a block element.
and finally the slideDown shows the element by sliding it down.
What about
$("#yourdiv").animate({height: 'toggle'});
Toggle will switch your div on/off, and the animate should make it appear from below. In this scenario, you don't need the specific CSS to "hide" it.
We can use visibility: hidden to visibility: visible instead of display: none to display: block property.
See this example:
function toggleSlide () {
const div = document.querySelector('div')
if (div.classList.contains('open')) {
div.classList.remove('open')
} else {
div.classList.add('open')
}
}
div {
visibility: hidden;
transition: visibility .5s, max-height .5s;
max-height: 0;
overflow: hidden;
/* additional style */
background: grey;
color: white;
padding: 0px 12px;
margin-bottom: 8px;
}
div.open {
visibility: visible;
/* Set max-height to something bigger than the box could ever be */
max-height: 100px;
}
<div>
<p>First paragraph</p>
<p>Second paragraph</p>
</div>
<button
onclick="toggleSlide()"
>
toggle slide
</button>
I did this workaround for the navigation header in my React site.
This is the regular visible css class
.article-header {
position: fixed;
top: 0;
transition: top 0.2s ease-in-out;
}
This is the class that is attached to the div (when scrolled in my case)
.hidden {
top: -50px !important;
transition: top 0.5s ease-in-out;
}
You can use also
$('#youDiv').slideDown('fast');
or you can tell that the active div goes up then the called one goes down
$('.yourclick').click(function(e) {
var gett = $(this).(ID);
$('.youractiveDiv').slideUp('fast', function(){
$('.'+gett).slideDown(300);
});
});
Something like that.

apple style expanding search field in menu bar

I'm coding a website and I'm trying to replicate the effect on the apple.com where when you click to focus the search field in the menu bar, and the search field expands and the rest of the menu bar shrinks to accommodate it.
I've been trying various tricks with jquery kwicks, and also simply expanding a text field using the animate function in jquery but the effect is not the same. If someone could get me on the right track I'd very much appreciate it!
Best
Daniel
this can be done by css only no need for javascript or anything...
#search input {
width: 100px;
-moz-transition: width 0.5s ease-out;
-webkit-transition: width 0.5s ease-out;
transition: width 0.5s ease-out;
}
#search input:focus {
width: 200px;
-moz-transition: width 0.5s ease-out;
-webkit-transition: width 0.5s ease-out;
transition: width 0.5s ease-out;
}
voila, thats it ;)
Taking a quick look at how Apple did it, it looks like their big move is this (I could be wrong - I'm rushing):
#globalheader #globalnav li {
display: table-cell;
width: 100%;
overflow: hidden;
}
This is a pretty unusual CSS display value, and clever on their part, forcing the <li>'s to work like <td>'s. This means that changing the width of one of the "cells" causes the others in the same "row" to adjust how much room they take out.
Long live (fake) table-based layout!
So, assuming that CSS is possible for you, and I'm not off base with my quick glance at their code, your only task is to animate the width of the search box - the rest should follow suit.
Not to over simplify things but what if in your css you float:right; this input box and then on focus you animate the box to the appropriate width like so:
CSS:
#inputtext{
float:right;
width:150px;
}
jQuery:
$("div#inputtext").focus(function(){
$(this).animate({width:'300px'}, 1000);
});
This is a fiddle for this.
http://jsfiddle.net/MenuSo/r4xq9gz2/
HTML:
<form id="expanding-form">
<input type="text" id="expanding-input" placeholder="">
<button type="submit">Search</button>
</form>
and CSS:
#expanding-form input{
width: 30px;
height: 30px;
-o-transition: width .5s ease;
-ms-transition: width .5s ease;
-moz-transition: width 0.5s ease-out;
-webkit-transition: width 0.5s ease-out;
transition: width 0.5s ease-out;
}
#expanding-form input:focus{
width: 200px;
}
CSS would be enough.

Categories