1

I'm trying to build a small modal plugin but I'm struggling to find a way to hide the modal and be able to fade it in/out using only CSS3 transitions.

Obviously, I can't animate display: none to inherit and using opacity and visibility isn't an option because the content is still technically there, it just can't be seen so it prevents elements beneath it from being used (buttons etc.)

So my thinking was to use jQuery to switch between display: hidden and inherit and then use jQuery to add a class of 'shown' which would trigger the transition. But it's not working. I'm just getting an instant show (as with the blackout element behind). The CSS transitions are working though, I've tested them without the 'display' stuff.

My jQuery so far:

// Modal open trigger
$('.modal-trigger').click(function() {
    modal = $('#' + $(this).data('modal-trigger'));
    modal.css({'display':'inherit'}).addClass('modal-show');
    $('#blackout').css({'display':'inherit'}).addClass('show');
});

Any ideas?

twistedpixel
  • 1,212
  • 4
  • 14
  • 33

4 Answers4

7

CSS transitions don't take effect if the element is hidden (display: none) when the transition is applied. Also, it doesn't matter what order the CSS changes are made in your JavaScript function, the browser will compute them all at once.

A quick solution is to force the browser to process the display change first, then the transition.

Try this:

modal.css({'display':'inherit'});
setTimeout(function(){ modal.addClass('modal-show'); }, 0);

Another way is to avoid using display: none at all. Use:

.hide
{
    opacity: 0;
    pointer-events: none;
}

.show
{
    opacity: 1;
    pointer-events: auto;
}

pointer-events allows the element to be invisible, but not interfere by swallowing mouse events. You should probably avoid using this except for small aesthetic things though, since the element might still interfere with e.g. form tab ordering. Also, IE support for the property is only from IE 11, if you care about that.

Nevett
  • 966
  • 6
  • 18
  • Very nice. I actually used pointer events in a similar problem (a "jump back to top" button). Maybe I'm just being pedantic but I just really don't like the idea of the element still being.. there! You know? However your timeout solution looks ace. I'm going to try that and see how I like it! – twistedpixel Feb 07 '14 at 17:39
  • I agree. I probably wouldn't use that option in your case. I'm sure it has some performance implications, too, since the browser still has to do most of the work of rendering it unless there's some clever optimisation going on. But it's a good option for the odd trivial effect here and there. – Nevett Feb 07 '14 at 17:46
  • Works like magic, very clean - many thanks! And I like the theory too - I didn't know about transitions not being applied to hidden elements. That really helped me understand *why* this problem occurred which I feel is a really important part of any solution to a problem. – twistedpixel Feb 07 '14 at 17:52
2

You can transition the 'visibility' property instead of the display property

see here: http://tympanus.net/codrops/2013/06/25/nifty-modal-window-effects/

.md-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    width: 50%;
    max-width: 630px;
    min-width: 320px;
    height: auto;
    z-index: 2000;
    visibility: hidden;
    backface-visibility: hidden;
    transform: translateX(-50%) translateY(-50%);
}

.md-show {
    visibility: visible;
}

.md-overlay {
    position: fixed;
    width: 100%;
    height: 100%;
    visibility: hidden;
    top: 0;
    left: 0;
    z-index: 1000;
    opacity: 0;
    background: rgba(143,27,15,0.8);
    transition: all 0.3s;
}

.md-show ~ .md-overlay {
    opacity: 1;
    visibility: visible;
}
ayal gelles
  • 2,829
  • 1
  • 21
  • 18
0

The best solution off the top of my head is using jQuery's built in animations

modal.fadeOut();

Using vanilla css will not be easy. Check out this question: Transitions on the display: property.

Community
  • 1
  • 1
KJ Price
  • 5,774
  • 3
  • 21
  • 34
0

My apologies in advance if I am being too simplistic, but have you tried to just use a fadeToggle()?

This is the stack that I use for showing and hiding modals:

function modalShow(){
    $(".modal-window").fadeToggle(200);
    return false;
}

function modalHide(){
    $(".modal-window").toggle();
    return false;
}

$(document).ready(function() {
    $("#close-modal").click(modalHide);
});

Hope it helps. Cheers.

Marcello
  • 156
  • 1
  • 3
  • I've been using jQuery for a while and I'm quite familiar with its Javascript transitions but I'm really trying to move forward and use only CSS3 transitions. Hardware accelerated transitions are so much nicer and as far as I know, jQuery doesn't use CSS3 transitions yet? – twistedpixel Feb 07 '14 at 17:35