workaround for display block and css transitions not triggering
Based on the code you present in your question I'm going on a completely different way here, and use animation
instead, which will make the whole repaint issue go away
Updated with a script the set the div to display: block
var dom = {};dom.creative = document.getElementById('creative');dom.creative.style.display = 'none';
var butt = document.getElementById('button');butt.addEventListener('click', function(e) { if (dom.creative.style.display == 'block') { dom.creative.style.display = 'none'; } else { dom.creative.style.display = 'block'; }
})
#creative { display: none; opacity: 0; animation: opac 1s forwards; margin: 20px;}@keyframes opac { 100% { opacity: 1; }}button { margin: 20px;}
<button id="button">Toggle display</button>
<div id="creative"> <span>Sample text</span></div>
Transitions on the CSS display property
You can concatenate two transitions or more, and visibility
is what comes handy this time.
div { border: 1px solid #eee;}div > ul { visibility: hidden; opacity: 0; transition: visibility 0s, opacity 0.5s linear;}div:hover > ul { visibility: visible; opacity: 1;}
<div> <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul></div>
css transition not working for display: none
You can use transition for opacity but not display. A great, and complete, answer here: CSS3 transition doesn't work with display property
CSS3 transition doesn't work with display property
display:none;
removes a block from the page as if it were never there.
A block cannot be partially displayed; it’s either there or it’s not.
The same is true forvisibility
; you can’t expect a block to be half
hidden
which, by definition, would bevisible
! Fortunately, you can
useopacity
for fading effects instead.
- reference
As an alternatiive CSS solution, you could play with opacity
, height
and padding
properties to achieve the desirable effect:
#header #button:hover > .content {
opacity:1;
height: 150px;
padding: 8px;
}
#header #button .content {
opacity:0;
height: 0;
padding: 0 8px;
overflow: hidden;
transition: all .3s ease .15s;
}
(Vendor prefixes omitted due to brevity.)
Here is a working demo. Also here is a similar topic on SO.
#header #button { width:200px; background:#ddd; transition: border-radius .3s ease .15s;}
#header #button:hover, #header #button > .content { border-radius: 0px 0px 7px 7px;}
#header #button:hover > .content { opacity: 1; height: 150px; padding: 8px; }
#header #button > .content { opacity:0; clear: both; height: 0; padding: 0 8px; overflow: hidden;
-webkit-transition: all .3s ease .15s; -moz-transition: all .3s ease .15s; -o-transition: all .3s ease .15s; -ms-transition: all .3s ease .15s; transition: all .3s ease .15s;
border: 1px solid #ddd;
-webkit-box-shadow: 0px 2px 2px #ddd; -moz-box-shadow: 0px 2px 2px #ddd; box-shadow: 0px 2px 2px #ddd; background: #FFF;}
#button > span { display: inline-block; padding: .5em 1em }
<div id="header"> <div id="button"> <span>This is a Button</span> <div class="content"> This is the Hidden Div </div> </div></div>
Css transition from display none to display block, navigation with subnav
As you know the display
property cannot be animated BUT just by having it in your CSS it overrides the visibility
and opacity
transitions.
The solution...just removed the display
properties.
nav.main ul ul { position: absolute; list-style: none; opacity: 0; visibility: hidden; padding: 10px; background-color: rgba(92, 91, 87, 0.9); -webkit-transition: opacity 600ms, visibility 600ms; transition: opacity 600ms, visibility 600ms;}nav.main ul li:hover ul { visibility: visible; opacity: 1;}
<nav class="main"> <ul> <li> <a href="">Lorem</a> <ul> <li><a href="">Ipsum</a> </li> <li><a href="">Dolor</a> </li> <li><a href="">Sit</a> </li> <li><a href="">Amet</a> </li> </ul> </li> </ul></nav>
css transition doesn't work if element start hidden
To understand plainly the situation, you need to understand the relation between the CSSOM and the DOM.
In a previous Q/A, I developed a bit on how the redraw process works.
Basically, there are three steps, DOM manipulation, reflow, and paint.
- The first (DOM manipulation) is just modifying a js object, and is all synchronous.
- The second (reflow, a.k.a layout) is the one we are interested in, and a bit more complex, since only some DOM methods and the paint operation need it. It consists in updating all the CSS rules and recalculating all the computed styles of every elements on the page.
Being a quite complex operation, browsers will try to do it as rarely as possible. - The third (paint) is only done 60 times per seconds at max (only when needed).
CSS transitions work by transitioning from a state to an other one. And to do so, they look at the last computed value of your element to create the initial state.
Since browsers do recalculate the computed styles only when required, at the time your transition begins, none of the DOM manipulations you applied are effective yet.
So in your first scenario, when the transition's initial state is calculated we have
.b { computedStyle: {display: none} }
... and that's it.
Because, yes, that's how powerful display: none
is for the CSSOM; if an element has display: none
, then it doesn't need to be painted, it doesn't exist.
So I'm not even sure the transition algorithm will kick in, but even if it did, the initial state would have been invalid for any transitionable value, since all computed values are just null.
Your .a
element being visible since the beginning doesn't have this issue and can be transitioned.
And if you are able to make it work with a delay (induced by $.animate
), it's because between the DOM manip' that did change the display
property and the execution of this delayed DOM manip' that does trigger the transition, the browser did trigger a reflow (e.g because the screen v-sync kicked in between and that the paint operation fired).
Now, it is not part of the question, but since we do understand better what happens, we can also control it better.
Indeed, some DOM methods do need to have up-to-date computed values. For instance Element.getBoundingClientRect
, or element.offsetHeight
or getComputedStyle(element).height
etc. All these need the entire page to have updated computed values so that the boxing are made correctly (for instance an element could have a margin pushing it more or less, etc.).
This means that we don't have to be in the unknown of when the browser will trigger this reflow, we can force it to do it when we want.
But remember, all the elements on the page needs to be updated, this is not a small operation, and if browsers are lenient to do it, there is a good reason.
So better use it sporadically, at most once per frame.
Luckily, the Web APIs have given us the ability to hook some js code just before this paint operation occurs: requestAnimationFrame.
So the best is to force our reflow only once in this pre-paint callback, and to call everything that needs the updated values from this callback.
$('button').on('click',function(){ $('.b').show(); // apply display:block synchronously requestAnimationFrame(() => { // wait just before the next paint document.body.offsetHeight; // force a reflow // trigger the transitions $('.b').css('right','80%'); $('.a').css('right','80%'); });})
body { width:800px; height:800px;}
div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1); color: white;}
.a { display:block; top:60px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><div class='a'>A</div><div class='b'>B</div><button>Launch</button>
How do you transition between display:none and display:block?
If you use visibility
and opacity
in conjunction with max-height
, you can achieve a nice transition from visible to hidden or vice-versa. Setting the element's max-height
to 0
when it's hidden, and max-height
to Xpx
(larger than your element will ever be) when visible, prevents the element from messing with your layout in any way (as you mentioned in your question).
Here's a quick example:
var visible = document.querySelector(".visible");
function hide() { visible.classList.add("hidden");}
visible.addEventListener("click", hide);
div { background-color: blue; padding: 40px; color: white; cursor: pointer; transition: all .1s ease;}
.visible { visibility: visible; opacity: 1; max-height: 1000px;}
.hidden { visibility: hidden; opacity: 0; max-height: 0;}
<div class="visible">Click to hide</div>
CSS Transition not firing with Opacity + Display
Toogling display property it's bad way for fade element, Similar topics were already processed e.g: CSS3 transition doesn't work with display property
"display:none; removes a block from the page as if it were never there. A block cannot be partially displayed; it’s either there or it’s not. The same is true for visibility; you can’t expect a block to be half hidden which, by definition, would be visible! Fortunately, you can use opacity for fading effects instead."
quotation author:
Hashem Qolami
You should try to do this by deelay like here Animating from “display: block” to “display: none”
or try toogling class like here: http://jsfiddle.net/eJsZx/19/
CSS:
.Modal {
display: block;
opacity: 0;
transition: all 300ms ease 0s;
height: 0px;
overflow: hidden;
}
.ModalVisible {
display: block;
opacity: 1;
height: 50px;
}
Jquery:
$('button').on('click', function () {
$('#ModalId').addClass('ModalVisible');
});
Html:
<div id='ModalId' class="Modal" > content <br> content </div>
<button>show</button>
Related Topics
Pause/Resume CSS Animations When Switching Tabs
Why Do Arabic Characters Behave as Separate Characters When Styling Single Arabic Character
How to Over-Ride CSS with User-CSS on Mobile Safari
How to Make the Whole Card Component Clickable in Material UI Using React Js
Why Do Developers Append a Query String in JavaScript Files' Stylesheet Links
Scale the Contents of a Div by a Percentage
How to Override Inline CSS Through JavaScript
JavaScript Not Working in Android Webview
How to Remove an Existing Class Name and Add a New One with Jquery and Cookies
Prevent Scroll Bounce for the Body Element, But Keep It for Child Elements in iOS
How to Set Width of <Div> to Fit Constant Number of Letters in Monospace Font
How to Show the Only Part of the Image
Absolute and Flexbox in React Native
Using CSS Transform Property in Jquery
Uncaught Domexception: Failed to Read the 'Rules' Property from 'Cssstylesheet'