Pure CSS Slide Up and Slide Down
If I can avoid using JavaScript for element animations, I'm incredibly happy and driven to do so. They're more efficient, don't require a JavaScript framework to manage steps, and they're more elegant. One effect that is difficult to nail down with pure CSS is sliding up and down, where the content is hidden when "up" and slides in when "down". The reason it's difficult is because you may not know the content height. After playing around with different CSS properties, I've found a way to make a pure CSS sliding effect.
The HTML
The effect really only requires one element, so we'll stick to that:
<div class="slider">Some content here....</div>
Add as much content as you'd like.
The CSS
Before we get into the trick, let's set the few obvious properties: overflow-y and the CSS animation properties:
.slider { overflow-y: hidden; max-height: 500px; /* approximate max height */ transition-property: all; transition-duration: .5s; transition-timing-function: cubic-bezier(0, 1, 0.5, 1); }
So now the fun: the trick we'll use to make the height play nice is the max-height
property. We'll set that property value to a reasonable default and then create another class to set that max-height
to 0
, thus sliding the element in:
.slider.closed { max-height: 0; }
After some tinkering, I really liked the cubic-bezier
transition timing function above, though there may be a more scientific method for the animation. At this point the only thing we need to do is toggle the closed class to slide the element in an out!
Not Perfect
So there comes the case where the height of the element could be 100px
or 100000px
. In that case, we're at a bit of a loss because the element isn't fixed-height. In that case, you have two options. The first is admitting defeat and using a CSS framework. The second is measuring the height of the DIV with JavaScript and injecting a max-height rule into a stylesheet so the animation is perfectly measured. Also remember that 100% as a max-height rule will be unreliable as 100% is relative to width, not height.
Let me know if you've found a better solution!
I’d obviously love to give an example, but I have literally 60 seconds of free time right now. My first thought to avoid JS would be to use a checkbox to toggle the “up” and “down” states. If I have some time later I’ll mess with an example, although I’d be surprised if someone doesn’t beat me to the punch.
That works but the idea isn’t necessarily that you want it to be click-to-slide.
The trick I use is to use a
max-height
value that’s unlikely to be exceeded. This does cause a delay in closing that I overcome by making the transition to the “closed” state quite short compared to the opening.Love that cubic-bezier transition! Stealin’. :)
Nice trick David.
Although remember transitioning the
max-height
property is hitting the CPU which is produce less smooth animations than hitting the GPU. A 2D transform transition would be better for repaints/reflow. Something likefrom: transform(0, -100%) to: transform(0, 0%)
Let me tweak something with a jsFiddle or so…
Nailed it, works like a charm :)
http://jsfiddle.net/jkneb/9uRKt/
The thing even cooler is that the slider has no height, it takes the height of its parent.
Enjoy!
Cheers
It’s a very similar effect, although on David’s example, the text doesn’t move with the animation.
I updated a little bit your code:
http://jsfiddle.net/9uRKt/11/
instead of adding new class
.opened
this would minimize@David – how come you aren’t using
height:auto;
for the parent container?Got it to work dynamically modfying jkneb’s post
https://jsfiddle.net/wuq91s6j/
Such as jkneb, I like using translate(), too. Here the example I use translateY for this demo:
http://codepen.io/dangvanthanh/pen/BsDbg
With translate(), you can don’t need care about height.
I think the mixed JS/CSS solution is a good compromise. There are two things that bother me about solely using the max height property — 1st, you get a slight delay (depending on how much higher your max height is set than the visible height of the element. 2nd, if you are setting a height that could be shorter than the content you are forced to set overflow: auto; and then get some wobble in the slide-open animation as the browser adds and removes the scrollbar. This was an awesome guide! Thanks.
What am I doing wrong here: http://jsfiddle.net/Dfswg/ ? I need it to start off hidden, then slide down on click….
Slide down doesn’t work, it’s just showing like I was only toggling display hidden/block… Slides up fine though…
Thanks…
Transitioning to and from “auto” is one of those things that needs to just work. It’s too valuable in too many cases to not be supported, even if it is pretty difficult to get right. Same goes for transitions to/from display: none;
Hm why is this “pure css” if you need JS to make it work?
Because there needs to be a trigger…
… Then it’s not pure css.
PURE css:
http://jsfiddle.net/gregmatys/4x9Tf/
Thank you. PURE css.
I love that there seems to be a for-real pure-CSS way to to achieve this, but gregmatys’s example doesn’t animate down, only up.
actually, it is animating down, but the bezier function is like an easeIn, so going out looks fast and jumpy. Slow the animation down and you can see it perfectly.
I tried using hover to trigger, but ran into issues with the infinite loop. Otherwise cool idea, since you are using JS to trigger you can do it in any direction and use absolute positioning,
z-index
, and overflow hidden trickeryNice!
Hi there,
I’m trying to setup a website where pages slide in and out, onlyt that they slide in from one idrection and slide out to the opposite direction. Any idea on how to do that?
Thanks
Avoiding JS and using CSS for animations as much as possible is high on my development criteria. Whilst it might not currently be perfect this article has caused me to revisit a little project I was working on to try some of the ideas. Great stuff, thanks David.
As #Paul mentioned, how to make your window slide from closed to open where you could do it by mouseOver or by Toggle. I am having that problem that I have some field in the middle of page and want when I put my mouse over it to open, from up to down, much bigger window of same width but with full info about that Read more field. How to do that, it is easy with left-right transition where you can hide it with big – or + px, but I need it to be hidden positioned on some point and than just to appear when activated.
Hope you can understand me.
I have one div slider with 3 links. The Content in that div will be fetched using Ajax. I want that if i click 1st link the div slide down with that content and when i click other 2 links the div slide down with their respective content. Example is given below:
The Problem is when i click on anyone link it opens or slide down but when i click on other link due to slideToggle it slides Up.
Please help me through this problem….Sorry for my Bad English
Thanks in Advance
this is good thanks PURE css.but anyway you make the botton bellow the wrap and slide?thank you
There are two things that bother me about solely using the max height property — 1st, you get a slight delay .Otherwise cool idea, since you are using JS to trigger you can do it in any direction and use absolute positioning
Great work! This is exactly what I was looking for. How would I have to modify the code to start out with the div closed and slide open when I click?
Brandon – change this:
to this
Thanks Scott!
I’ve come across this dynamic height issue before, one solution I’ve found can be really useful is transitioning between
transform: scaleY(0);
andtransform: scaleY(1);
This way you can avoid hacking your way around the delay in animation caused by using an arbitrary value on the max-height property.
Made a codepen to demonstrate: http://codepen.io/madad123/full/VYdggw/
Thank David Walsh, thank you jkneb, thank you gregmatys, thank you Adam Hollister, this is a great demonstration.
I think that by combining all your inputs, it should even be possible to get a pure CSS parallax effect (i.e. trigger animation on two divs that are positioned one above the other with different z-index and have different transition-duration).
I’ll try to put my hands at it if I some time to do it.
Unfortunately, the major issue with all of the CSS translate solutions is that you aren’t actually changing the height — you simply create a container that takes up the full height of the content even when the content is hidden! This ends up pushing any content below further down the page, which is usually not what you want in the case of something like an accordion form.
I like David’s solution, although a fixed max-height is problematic, especially if you’re setting duration values for your transitions…you could end up with wildly-fast transitions that don’t end up looking all that pleasing to the eye…the stylesheet injection sounds promising though if a little complex.
Thank you for this!
I reversed it (initial state with height of 0px then applied height to the div to reveal) and used it to create pure CSS reveal on click search box for my minimal style theme. Also used it to create a click to reveal social share widget as well. Works beautifully and helped keep my theme’s JavaScript footprint as small as possible.
I totally agree with trying to avoid JavaScript for element animations and am so in love with CSS3.
Thanks again!
Here is my funky css solution to emulate height auto transition:
http://codepen.io/LasyAsCat/pen/KdxLRj#0
Drawback is that you should use additional inner wrapper to hide content with overflow and use two transform properties instead one, but it works as it should.
Hey guys….you’re all amazing and thank you david for this site – it has helped me out a hell of a lot with my very first website I have to code! :)
I do have a question though – saw this online and it’s what is requested for what I have to do: http://jsfiddle.net/9cdYR/
but is it in any way possible to create this same effect using only with CSS, no JavaScript?
Sorry for a possible stupid question – first time coder amongst you pros
You can quite easily make the max-height approach work for content of all heights with very little JavaScript.
The trick is to have an outer sliding div with an inner content div. When the outer div is to slide, set the max-height property to the scrollHeight property and everything is fine.
See my very basic example here… https://jsfiddle.net/j8da050k/4/
Jorgen,
That solution is awesome. Thank you so much.
Somebody mentioned the main example not being pure CSS and someone else posted a version with “actually pure CSS” but let’s get it straight CSS can’t really be pure in that sense because it needs HTML to work.
Now. I needed couple elements to slide up and down into a box so I made a pure HTML version
https://codepen.io/anon/pen/qmGNWQ
Nice, but not accessible. Why? Because
max-height
doesn’t hide content from screen readers.“pure css”? Ahhh … except the bit in your
onclick
? :/