Can I apply a CSS transition to the overflow property? - css

I'm trying to set a transition-delay to the overflow property of body when a div is clicked by adding a class to the body as follows:
$("div").click(function(){
$("body").addClass("no_overflow");
});
div{
background:lime;
height:2000px;
}
.no_overflow{
overflow:hidden;
}
body{
overflow:auto;
transition: overflow 0 2s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>I'm div</div>
However, this doesn't seem to work (there's no delay). Am I doing anything wrong here?
I know this can be achieved by using setTimeout function, but was wondering why can't this be achieved using css transitions? Are there any specific style properties to which css transitions can be applied?

There are many properties that can't be transitioned. overflow is among them; the render engine has no idea how to transition between "hidden" and "shown", because those are binary options, not intervals. This is the same reason why you can't transition between display: none; and display: block; (for example): there are no in-between phases to use as transitions.
You can see a list of properties you can animate here on Mozilla Developer Network.

You can simulate a delay with animation:
$("div").click(function() {
$("body").addClass("no_overflow");
});
div {
background: lime;
height: 2000px;
}
.no_overflow {
overflow: hidden;
/* persist overflow value from animation */
animation: 7s delay-overflow;
}
body {
overflow: auto;
}
#keyframes delay-overflow {
from { overflow: auto; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>I'm div</div>
You'll have to apply a separate animation to .body if you want a delay on removeClass, and also to take care that the two animations don't overlap or they'll cancel each other out.

overflow isn't CSS animatable property. You can see full list of animatable CSS properties there.

In case someone is looking at the answer, like I was, for a way to animate the cropping of an element which requires overflowing - here is the solution that worked for me: the clip-path css property which is animatable and very versatile.
Here is a cool tool to play around with, in order to get the proper start / end values for an animation: https://bennettfeely.com/clippy/.

Dmitry's answer should be the only accepted answer, as it is a pure CSS solution applying delay to "non-animatable" properties. However it's worth to mention, that the CSS rule applying animation should be "triggerable" each time when it is needed.
For instance, the following code does not work:
#keyframes show-overflow {
from { overflow: hidden; }
}
.hideable, .overlay {
font-size: 36px;
height: 50px;
}
.hideable {
transition: height 2s;
overflow: visible;
animation: show-overflow 2s; /* this line should be in separate "triggerable" CSS rule to work */
}
.hideable.hidden {
height: 0;
overflow: hidden;
}
<button onclick="document.getElementById('hideable').classList.toggle('hidden')">
Clik HERE to hide/show the text below
</button>
<div id='hideable' class='hideable'>
This is the text to hide and show.
</div>
<div class='overlay'>
This is overlaying text
</div>
But after moving the marked property to a separate CSS rule, everything works as expected:
#keyframes show-overflow {
from { overflow: hidden; }
}
.hideable, .overlay {
font-size: 36px;
height: 50px;
}
.hideable {
transition: height 2s;
overflow: visible;
}
.hideable:not(.hidden) {
animation: show-overflow 2s; /* now this works! */
}
.hideable.hidden {
height: 0;
overflow: hidden;
}
<button onclick="document.getElementById('hideable').classList.toggle('hidden')">
Clik HERE to hide/show the text below
</button>
<div id='hideable' class='hideable'>
This is the text to hide and show.
</div>
<div class='overlay'>
This is overlaying text
</div>

It makes sense that you can't transition between binary attributes for example overflow: hidden; and overflow: visible but it would have been really nice if instead of "transitioning" then it would be like (in js pseudo code:
setTimeout("applyOverflowVisible()", transitionTime);
But of course you can do this yourself in JavaScript but then you are splitting the code between places and it can make it difficult to understand by someone else. I guess using things like React helps but even there I would want to avoid mixing css into the js.

Related

CSS Animate button to appear

In the React app I'm building, I would like a button to be hidden until certain conditions are met. Then I'd to animate it in from underneath another element.
At the moment I am always rendering the button and adding a class of "hidden" when I'd like it hidden.
The SASS looking something like this:
button {
display: inline-block;
width: 100%;
height: 63px;
transition: height 250ms ease-in-out;
font-size: 24px;
&.hidden {
height: 0;
}
}
But when the button hides, the element gets smaller, but the text is still visible. Similar to this: https://jsfiddle.net/dtu56e1j/
What am I doing wrong?
Or is there a better way to get a button to animate in?
IMO the other answers provide working, but complicated solutions to your problem. Simply put, you're missing a single CSS property - overflow: hidden.
I created this StackBlitz to illustrate the point.
However, the only modification necessary to the original code is this:
button {
overflow: hidden;
[...]
}
Fiddle to better match use-case: https://jsfiddle.net/smn6xgv2/
Because the button element has some internal padding, setting height: 0 doesn't completely remove the element from the display. To address that issue, we wrap the button inside a div and then animate the height of the div.
Additionally, the div should be left with the default display: block. In the original example, the display: inline-block causes the browser to reserve a minimum height of line-height. More info in this SO question
With a little work you could use translateY to get this done nicely
const el = document.querySelector("#testButton");
setInterval(() => {
el.classList.toggle("hidden");
}, 2000);
button {
display: inline-block;
background-color: darkblue;
color: white;
width: 100%;
height: 63px;
transition: transform 250ms ease-in-out;
font-size: 24px;
}
button.hidden {
transform: translateY(63px); /* or -63px to invert */
}
/* Make a wrapper class so that your button disappears on transform */
.wrapper {
height: 63px;
overflow: hidden;
}
<div class="wrapper">
<button id="testButton">My Button!</button>
</div>

AngularJS: Animate ng-hide / ng-show height of li by using css transitions

I am using Angular to hide/show items of a unordered list. Since the effect is a bit too fast for the user to notice the disappearance/appearance of my lis, I want to add a transition on the height.
li {
transition: height 1s linear;
overflow: hidden;
}
li.ng-hide {
height: 0;
}
This is where my problem is : the transition does not affect the lis, unless I set them a height, which I don't want, since I don't exactly know how big they are.
Here is a plunker to illustrate that. I've made the test on lis and divs and I've also tried without Angular which does not seem to be the responsible.
How can I make the transition work without setting the height of my elements ?
Just do it by animate max-height instead of height like in this DEMO PLNKR. In that way you are able to have a dynamic height of your element between 0 and your max-height property. There is no need for jQuery. You should avoid using jQuery or direct DOM-Injections in AngularJS applications.
li,
div {
transition: all 1s linear;
-webkit-transition: all 1s linear;
border: 1px solid;
overflow: hidden;
}
.work {
border-color: green;
max-height: 500px;
}
.no-work {
border-color: red;
max-height: 500px;
}
li.ng-hide,
div.ng-hide {
max-height: 0;
}
I have come across the same problem myself in the past and discovered as you have that the height must be set, this is in order for the transition to calculate what needs to happen. Two ways I have managed to get round the problem:
CSS way:
li {
transition: max-height 1s linear;
overflow: hidden;
max-height: 500px; // Any value above what you expect to be the biggest
}
li.ng-hide {
max-height: 0;
}
The above method has a two drawbacks in that, one you'll need to know an upper limit and two there will be a slight jump in animation. A better way might be to calculate the height with javascript:
** UPDATE FROM JQUERY **
var listItems = document.getElementsByTagName("li")
for (var i = 0; i < listItems.length; i++) {
listItems[i].style.height = listItems[i].clientHeight + 'px';
}
Then you'd need the css:
li.ng-hide {
height: 0 !important;
}
To override the style attribute. Here is a pen of this example with a little bit extra in to illustrate the solution.
You don't necessarily need to set your transition on height.
You can set it on the ng-hide or ng-show property.
Here is your example with this feature :
https://plnkr.co/edit/pD4sQNGqpqrINJlZwE3q?p=preview
Simply assign the class to the element you want to animate.
.animate.ng-hide-add,
.animate.ng-hide-remove {
transition: all linear 2s;
}
You'll find more infos here : https://docs.angularjs.org/api/ng/directive/ngShow
nb: You can seperate the animation for ng-hide-add and ng-hide-remove in your css. of course.
Hope it helps !

Change content property of pseudo element within CSS animation

I was wondering if anyone knows a way to change the content of a pseudo element (:before or :after) within a CSS animation.
It doesn't seem to be working in my fiddle, but maybe there's another way: http://jsfiddle.net/xfrfnav1/
Interesting suggestion, but apparently the browser (Chrome in my case) ignores the content. Makes a little sense. After all, it is for an animation, and the property is 'morphed' from one value to another gradually, which is not possible with content. Still, it would be nice of it worked.
A possible solution: put all the dots in there already and change the width. If you like, you can put the text 'loading' in :before (or in the div itself) and the dots in :after, so you can easily animate it from 0 to any desired width:
div:before {
content:"Loading";
display: inline-block;
overflow: hidden; /* Weird baseline behavior without this */
}
div:after {
content:".......................";
display: inline-block;
overflow: hidden; /* Hide the dots */
-webkit-animation: loading 4s linear 0 infinite;
}
#-webkit-keyframes loading {
0% { width: 0;} /* Only from and to are needed */
100% { width: 3em;}
}
Fiddle
I have a solution for you : here
I have added a fixed width on parent div, and Loading directly in content, your problem was content:""; with no content is hard to show text
My css :
div { width: 61px; }
div:after {
content:"Loading...";
display: block;
overflow: hidden; /* animation gonna reduce content width so points gonna hide */
-webkit-animation:loading 1s linear 0 infinite;
}
#-webkit-keyframes loading { /* be careful you must add -moz and other browser prefixed versions */
0% { width:80% }
25% { width:85% }
50% { width:90% }
100% { width:100% }
}
Works fine (at least in Chrome) if you change to: -webkit-animation:loading 1s infinite linear;

How to hide/show the content of a div with dynamic height?

I am trying to develop a small module (like the collapse component of twitter bootstrap).
I don't know how to treat the content of the div which is growing up/down, it could take me many descriptions, nothing's better than an example: Collapse deployment.
You can see a div.container which is the block destined to grow up/down.
Here i declare height: 50px to illustrate a state of the deployment.
Is there a way to hide the content (here a part of the text) that is out of the height of a parent div ?
I like the idea that we can access a content only by deploying another one, but i don't really don't understand how to make it happen properly in CSS.
Like this? JSFiddle example: http://jsfiddle.net/SW86B/1/
Updated CSS
.header {
background-color: green;
height:20%;
}
.container {
background-color: red;
height: 0;
overflow: hidden;
-webkit-transition: height 0.2s ease;
-moz-transition: height 0.2s ease;
transition: height 0.2s ease;
}
.container.open { height: 50px;}
p { margin: 0; }
Use jQuery to toggle states
$('button').on('click', function(event){
$('.container').toggleClass('open');
});
I am not sure that i understand what you are trying but you can use
overflow:hidden;
Demo here - http://jsfiddle.net/JjPcy/1/
Set the div.container's overflow css properoty to hidden.
div.container { overflow: hidden; }
Also make a class for instance called auto-width that has auto width:
div.auto-width { width: auto !important; }
Then use jQuery to toggle the class and reveal the data inside the container:
$('div.header button').click(function() {
$('div.container').toggleClass('auto-width');
});
Here's the demo: http://jsfiddle.net/VE9WR/3/
It could be done in so many ways. it depends on what you're looking for ;)

animate inline element scroll full width

for the following paragraph, I want to animate to scroll span element upon mouse hover. It will scroll to the right until the end.
<div class="one_line">
<span>
NoMagic framework doesn't try to put anything into the blackbox. We hope you read the core source code and try to get fully understanding before you start to using it. And we hope you forking our project and creating your own database helper function sets based on your need.
Using NoMagic, you will turn the MySQL database into a schemaless solution, the schemaless database will save your time so that you don't need to spend to much time in planning database table structure.
</span>
</div>
the css I already have
.one_line {
line-height: 1.5em;
height: 1.5em;
position: relative;
width: 600px;
overflow-x: hidden;
span {
white-space: nowrap;
height: 100%;
display: inline-block;
position: absolute;
&:hover {
animation-name: scroll;
animation-duration: 6s;
}
}
}
#keyframes scroll {
50% {
left: 100%;
}
}
Up to my knowledge using CSS animate we can only animate the entire tag itself but not the content in it (i.e.) in this case we can move the entire span across the page dimension but not the text inside it. So i made it using transform property which is more flexible.
I have a jsfiddle here to demonstrate this.
CSS Animate code that i had changed:
#keyframes scroll {
0% {
transform:translateX(0);
}
100% {
transform:translateX(-100%);
}
}
Hope this will be useful.

Resources