CSS3 equivalent to jQuery slideUp and slideDown?
Asked Answered
W

10

105

My application is performing poorly with jQuery's slideDown and slideUp. I'm looking to use a CSS3 equivalent in browsers which support it.

Is it possible, using CSS3 transitions, to change an element from display: none; to display: block; while sliding the item down or up?

Weaponeer answered 21/2, 2011 at 23:37 Comment(1)
I think you would keep the display:block, but just adjust the width from the desired amount to 0.Enright
C
42

You could do something like this:

#youritem .fade.in {
    animation-name: fadeIn;
}

#youritem .fade.out {
    animation-name: fadeOut;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
        transform: translateY(startYposition);
    } 
    100% {
        opacity: 1;
        transform: translateY(endYposition);
    }
}

@keyframes fadeOut {
    0% {
        opacity: 1;
        transform: translateY(startYposition);
    } 
    100% {
        opacity: 0;
        transform: translateY(endYposition);
    }
}

Example - Slide and Fade:

This slides and animates the opacity - not based on height of the container, but on the top/coordinate. View example

Example - Auto-height/No Javascript: Here is a live sample, not needing height - dealing with automatic height and no javascript.
View example

Catching answered 21/2, 2011 at 23:47 Comment(6)
Can you make a demo on jsFiddle?Malm
@Šime From my first look at it, I'd say just give your element class="fade" and add class in when you'd like a fade in, out when you'd like a fade out.Sidwel
@Šime - I've included two samples for you to useCatching
I modified the second example (auto-height/no JavaScript) so only the barebones styles to get the effect were in place. jsfiddle.net/OlsonDev/nB5Du/251Camarena
to newer readers, don't waste your time with theseTraditional
@Traditional Can we have the reason?Di
C
20

I changed your solution, so that it works in all modern browsers:

css snippet:

-webkit-transition: height 1s ease-in-out;
-moz-transition: height 1s ease-in-out;
-ms-transition: height 1s ease-in-out;
-o-transition: height 1s ease-in-out;
transition: height 1s ease-in-out;

js snippet:

    var clone = $('#this').clone()
                .css({'position':'absolute','visibility':'hidden','height':'auto'})
                .addClass('slideClone')
                .appendTo('body');

    var newHeight = $(".slideClone").height();
    $(".slideClone").remove();
    $('#this').css('height',newHeight + 'px');

here's the full example http://jsfiddle.net/RHPQd/

Coquelicot answered 12/2, 2013 at 16:24 Comment(3)
Not sure who -2 this, after 7 years, still work like a charm. Except that I recreate this with Vanilla JS. +1 from me.Patentor
Hi @JensT, I always thought jQuery made a 0-second auto-height or a clone as you did to measure the real default height, is it so? I think the clone could not be 100% perfect, as appending it to the body doesn't guarantee to keep the same layout of the cloned element.Daegal
It seems that clone is not always needed with newer jQuery versions: Although the div has not set a height (i.e. height: auto), this.css("height") returns a pixel value, e.g. "90px". So it seems $("#this").css("height") seems to call $("#this").height() internally withouth displaying it (so maybe height() does a clone?)? tested with jQuery 3.7.0 and 3.4.1, here's a fiddle: jsfiddle.net/2yp9n3z8 Anyone know the reason? One can use this to only do the clone part if a computed height is not available.Sauropod
W
9

So I've gone ahead and answered my own question :)

@True's answer regarded transforming an element to a specific height. The problem with this is I don't know the height of the element (it can fluctuate).

I found other solutions around which used max-height as the transition but this produced a very jerky animation for me.

My solution below works only in WebKit browsers.

Although not purely CSS, it involves transitioning the height, which is determined by some JS.

$('#click-me').click(function() {
  var height = $("#this").height();
  if (height > 0) {
    $('#this').css('height', '0');
  } else {
    $("#this").css({
      'position': 'absolute',
      'visibility': 'hidden',
      'height': 'auto'
    });
    var newHeight = $("#this").height();
    $("#this").css({
      'position': 'static',
      'visibility': 'visible',
      'height': '0'
    });
    $('#this').css('height', newHeight + 'px');
  }
});
#this {
  width: 500px;
  height: 0;
  max-height: 9999px;
  overflow: hidden;
  background: #BBBBBB;
  -webkit-transition: height 1s ease-in-out;
}

#click-me {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>

<p id="click-me">click me</p>
<div id="this">here<br />is<br />a<br />bunch<br />of<br />content<br />sdf</div>
<div>always shows</div>

View on JSFiddle

Weaponeer answered 22/2, 2011 at 1:28 Comment(4)
Yeah, my code below doesn't require height as it uses the y-coordinate. But you didn't mention that you needed something with a height dependency :) You could always do a margin transition, etc.. But it appears you have what you're looking for, no?Catching
@True do you think you could explain what you mean by a margin transition?Weaponeer
Added sample for positioning, will add the marginingCatching
Also added margin/no javsacript exampleCatching
B
9

Getting height transitions to work can be a bit tricky mainly because you have to know the height to animate for. This is further complicated by padding in the element to be animated.

Here is what I came up with:

use a style like this:

    .slideup, .slidedown {
        max-height: 0;            
        overflow-y: hidden;
        -webkit-transition: max-height 0.8s ease-in-out;
        -moz-transition: max-height 0.8s ease-in-out;
        -o-transition: max-height 0.8s ease-in-out;
        transition: max-height 0.8s ease-in-out;
    }
    .slidedown {            
        max-height: 60px ;  // fixed width                  
    }

Wrap your content into another container so that the container you're sliding has no padding/margins/borders:

  <div id="Slider" class="slideup">
    <!-- content has to be wrapped so that the padding and
            margins don't effect the transition's height -->
    <div id="Actual">
            Hello World Text
        </div>
  </div>

Then use some script (or declarative markup in binding frameworks) to trigger the CSS classes.

  $("#Trigger").click(function () {
    $("#Slider").toggleClass("slidedown slideup");
  });

Example here: http://plnkr.co/edit/uhChl94nLhrWCYVhRBUF?p=preview

This works fine for fixed size content. For a more generic soltution you can use code to figure out the size of the element when the transition is activated. The following is a jQuery plug-in that does just that:

$.fn.slideUpTransition = function() {
    return this.each(function() {
        var $el = $(this);
        $el.css("max-height", "0");
        $el.addClass("height-transition-hidden");
    });
};

$.fn.slideDownTransition = function() {
    return this.each(function() {
        var $el = $(this);
        $el.removeClass("height-transition-hidden");

        // temporarily make visible to get the size
        $el.css("max-height", "none");
        var height = $el.outerHeight();

        // reset to 0 then animate with small delay
        $el.css("max-height", "0");

        setTimeout(function() {
            $el.css({
                "max-height": height
            });
        }, 1);
    });
};

which can be triggered like this:

$("#Trigger").click(function () {

    if ($("#SlideWrapper").hasClass("height-transition-hidden"))
        $("#SlideWrapper").slideDownTransition();
    else
        $("#SlideWrapper").slideUpTransition();
});

against markup like this:

<style>
#Actual {
    background: silver;
    color: White;
    padding: 20px;
}

.height-transition {
    -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;
    overflow-y: hidden;            
}
.height-transition-hidden {            
    max-height: 0;            
}
</style>
<div id="SlideWrapper" class="height-transition height-transition-hidden">
    <!-- content has to be wrapped so that the padding and
        margins don't effect the transition's height -->
    <div id="Actual">
     Your actual content to slide down goes here.
    </div>
</div>

Example: http://plnkr.co/edit/Wpcgjs3FS4ryrhQUAOcU?p=preview

I wrote this up recently in a blog post if you're interested in more detail:

http://weblog.west-wind.com/posts/2014/Feb/22/Using-CSS-Transitions-to-SlideUp-and-SlideDown

Benkley answered 24/2, 2014 at 21:35 Comment(1)
This is the most elegant solution as to me. And if needed jQuery can be easily removed. One can toggle a class in vanila JS as: document.getElementById("Slider").classList.toggle("slidedown");Mccallion
B
8

why not to take advantage of modern browsers css transition and make things simpler and fast using more css and less jquery

Here is the code for sliding up and down

Here is the code for sliding left to right

Similarly we can change the sliding from top to bottom or right to left by changing transform-origin and transform: scaleX(0) or transform: scaleY(0) appropriately.

Barta answered 12/4, 2014 at 10:58 Comment(2)
I know this answers was placed in 2014 but I cannot recommend using this answer if you want to push elements below it down or up since the parent container will stake up the height in the browserWeidner
That can be solved by punting the element on position absolute @Ellisan, for example, is perfect for menu's effectsIsiah
T
5

I would recommend using the jQuery Transit Plugin which uses the CSS3 transform property, which works great on mobile devices due to the fact that most support hardware acceleration to give that native look and feel.

JS Fiddle Example

HTML:

<div class="moveMe">
    <button class="moveUp">Move Me Up</button>
    <button class="moveDown">Move Me Down</button>
    <button class="setUp">Set Me Up</button>
    <button class="setDown">Set Me Down</button>
 </div>

Javascript:

$(".moveUp").on("click", function() {
    $(".moveMe").transition({ y: '-=5' });
});

$(".moveDown").on("click", function() {
    $(".moveMe").transition({ y: '+=5' });
});

$(".setUp").on("click", function() {
    $(".moveMe").transition({ y: '0px' });
});

$(".setDown").on("click", function() {
    $(".moveMe").transition({ y: '200px' });
});
Teplica answered 11/3, 2013 at 16:10 Comment(3)
Does this enable you to transition to an element's natural height using auto? eg. $(".moveMe").transition({height: 'auto'})Issi
I wish they'd override the slideUp() and slideDown() methods with this plugin. That'd be really niceAridatha
This is awesome BTW. Thanks for adding this answer!Aridatha
A
2

Aight fam, after some research and experimenting, I think the best approach is to have the thing's height at 0px, and let it transition to an exact height. You get the exact height with JavaScript. The JavaScript isn't doing the animating, it's just changing the height value. Check it:

function setInfoHeight() {
  $(window).on('load resize', function() {
    $('.info').each(function () {
      var current = $(this);
      var closed = $(this).height() == 0;
      current.show().height('auto').attr('h', current.height() );
      current.height(closed ? '0' : current.height());
    });
  });

Whenever the page loads or is resized, the element with class info will get its h attribute updated. Then you could have a button trigger the style="height: __" to set it to that previously set h value.

function moreInformation() {
  $('.icon-container').click(function() {
    var info = $(this).closest('.dish-header').next('.info'); // Just the one info
    var icon = $(this).children('.info-btn'); // Select the logo

    // Stop any ongoing animation loops. Without this, you could click button 10
    // times real fast, and watch an animation of the info showing and closing
    // for a few seconds after
    icon.stop();
    info.stop();

    // Flip icon and hide/show info
    icon.toggleClass('flip');

    // Metnod 1, animation handled by JS
    // info.slideToggle('slow');

    // Method 2, animation handled by CSS, use with setInfoheight function
    info.toggleClass('active').height(icon.is('.flip') ? info.attr('h') : '0');

  });
};

Here's the styling for the info class.

.info {
  display: inline-block;
  height: 0px;
  line-height: 1.5em;
  overflow: hidden;
  padding: 0 1em;
  transition: height 0.6s, padding 0.6s;
  &.active {
    border-bottom: $thin-line;
    padding: 1em;
  }
}

I used this on one of my projects so class names are specific. You can change them up however you like.

The styling might not be supported cross-browser. Works fine in chrome.

Below is the live example for this code. Just click on the ? icon to start the animation

CodePen

Acceptant answered 1/7, 2016 at 17:53 Comment(0)
V
2

Variant without JavaScript. Only CSS.

CSS:

.toggle_block {
    border: 1px solid #ccc;
    text-align: left;
    background: #fff;
    overflow: hidden;
}
.toggle_block .toggle_flag {
    display: block;
    width: 1px;
    height: 1px;
    position: absolute;
    z-index: 0;
    left: -1000px;
}
.toggle_block .toggle_key {
    font-size: 16px;
    padding: 10px;
    cursor: pointer;
    -webkit-transition: all 300ms ease;
       -moz-transition: all 300ms ease;
        -ms-transition: all 300ms ease;
         -o-transition: all 300ms ease;
            transition: all 300ms ease;
}
.toggle_block .content {
    padding: 0 10px;
    overflow: hidden;
    max-height: 0;
    -webkit-transition: all 300ms ease;
       -moz-transition: all 300ms ease;
        -ms-transition: all 300ms ease;
         -o-transition: all 300ms ease;
            transition: all 300ms ease;
}
.toggle_block .content .toggle_close {
    cursor: pointer;
    font-size: 12px;
}
.toggle_block .toggle_flag:checked ~ .toggle_key {
    background: #dfd;
}
.toggle_block .toggle_flag:checked ~ .content {
    max-height: 1000px;
    padding: 10px 10px;
}

HTML:

<div class="toggle_block">
    <input type="checkbox" id="toggle_1" class="toggle_flag">
    <label for="toggle_1" class="toggle_key">clicker</label>
    <div class="content">
        Text 1<br>
        Text 2<br>
        <label for="toggle_1" class="toggle_close">close</label>
    </div>
</div>

For next block only change ID and FOR attributes in html.

Varve answered 20/10, 2020 at 14:34 Comment(0)
W
0

you can't make easisly a slideup slidedown with css3 tha's why I've turned JensT script into a plugin with javascript fallback and callback.

in this way if you have a modern brwowser you can use the css3 csstransition. if your browser does not support it gracefuly use the old fashioned slideUp slideDown.

 /* css */
.csstransitions .mosneslide {
  -webkit-transition: height .4s ease-in-out;
  -moz-transition: height .4s ease-in-out;
  -ms-transition: height .4s ease-in-out;
  -o-transition: height .4s ease-in-out;
  transition: height .4s ease-in-out;
  max-height: 9999px;
  overflow: hidden;
  height: 0;
}

the plugin

(function ($) {
$.fn.mosne_slide = function (
    options) {
    // set default option values
    defaults = {
        delay: 750,
        before: function () {}, // before  callback
        after: function () {} // after callback;
    }
    // Extend default settings
    var settings = $.extend({},
        defaults, options);
    return this.each(function () {
        var $this = $(this);
        //on after
        settings.before.apply(
            $this);
        var height = $this.height();
        var width = $this.width();
        if (Modernizr.csstransitions) {
            // modern browsers
            if (height > 0) {
                $this.css(
                    'height',
                    '0')
                    .addClass(
                        "mosne_hidden"
                );
            } else {
                var clone =
                    $this.clone()
                    .css({
                        'position': 'absolute',
                        'visibility': 'hidden',
                        'height': 'auto',
                        'width': width
                    })
                    .addClass(
                        'mosne_slideClone'
                )
                    .appendTo(
                        'body'
                );
                var newHeight =
                    $(
                        ".mosne_slideClone"
                )
                    .height();
                $(
                    ".mosne_slideClone"
                )
                    .remove();
                $this.css(
                    'height',
                    newHeight +
                    'px')
                    .removeClass(
                        "mosne_hidden"
                );
            }
        } else {
            //fallback
            if ($this.is(
                ":visible"
            )) {
                $this.slideUp()
                    .addClass(
                        "mosne_hidden"
                );
            } else {
                $this.hide()
                    .slideDown()
                    .removeClass(
                        "mosne_hidden"
                );
            }
        }
        //on after
        setTimeout(function () {
            settings.after
                .apply(
                    $this
            );
        }, settings.delay);
    });
}
})(jQuery);;

how to use it

/* jQuery */
$(".mosneslide").mosne_slide({
    delay:400,
    before:function(){console.log("start");},
    after:function(){console.log("done");}
});

you can find a demo page here http://www.mosne.it/playground/mosne_slide_up_down/

Wheelsman answered 4/10, 2013 at 11:0 Comment(3)
This isn't an answer, a answer contains more than just a link.Saltine
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post.Hescock
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Stocks
P
0
    try this for slide up slide down with animation 
give your **height

        @keyframes slide_up{
            from{
                min-height: 0;
                height: 0px;
                opacity: 0;
            }
            to{
                height: 560px;
                opacity: 1;
            }
        }

        @keyframes slide_down{
            from{
                height: 560px;
                opacity: 1;
            }
            to{
                min-height: 0;
                height: 0px;
                opacity: 0;
            } 
        }
Pricilla answered 29/4, 2020 at 4:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.