3

I'm designing a website that makes use of both parallax scrolling and modal boxes. When you open one of the modal boxes, I'm using jQuery and CSS to add a class to the popup's DIV element so that its opacity goes from 0 to 100; I'm using a transition to make this look pretty. When you close the box, jQuery strips the class out to set the opacity back to 0.

So that the modal boxes are more readable, I've put an overlay behind them (actually a containing DIV) that overlays a transparency over the rest of the screen using a width and height of 100%. I also use the same trick to take the opacity of this from 0 to 100 when the box is opened, and vice versa when it's closed.

The problem lies in that even at opacity 0, the overlay is still "above" some of the screen, rendering links and text viewable but not selectable. I've tried setting the Z-Index to 0 and -1 when the overlay is meant to be hidden, but because the parallax scrolling (I'm using a customised version of the SCRN template, for reference http://rodrigob.com/themes/scrn/) uses Relative, Fixed and Absolute positioning, the Z-Index only applies to some of the site.

As a workaround, styling the overlay with Visibility:Hidden works (as does Display:None, but I want to avoid that for accessibility reasons), but this can't be managed by a transition, so when the modal closes, it just disappears instead of fading out nicely.

Is there any way around this? I thought setting the Visibility to Hidden after the transition from 100 opacity to 0 had happened would work, but I don't know how to do this, if it can even be done at all.

Thanks in advance.

Sinister Beard
  • 3,570
  • 12
  • 59
  • 95
  • 1
    If I correctly understood, you problem is that your overlay once hidden blocks the access to the underlying elements, right? If so, you can't only set its `opacity` to 0 and/or `visibility` to `hidden` because in this way elements aren't visible but still present in your layout, preventing underlying elements to be reached. You **must** also set `display` to `none` to remove the overlay from the top of your elements. – Ragnarokkr Jan 15 '13 at 15:32
  • Yes - effectively I need to set Display to None after the transitions have run. – Sinister Beard Jan 16 '13 at 14:28

6 Answers6

1

Use setTimeout to start the animation after the overlay appears, and hide the overlay after the animation is finished

to show overlay:

// show the overlay (in whatever manner you like) BEFORE the animation starts
// opacity is 0
$('#overlay').show();
setTimeout(function() {
  // fade in the opacity AFTER the overlay is there
  $('#overlay').addClass('opaque');
}, 0);

to hide overlay:

// fade out the opacity BEFORE the overlay goes away
$('#overlay').removeClass('opaque');
setTimeout(function() {
  // hide the overlay (in whatever manner you like) AFTER the animation is done
  // opacity is 0
  $('#overlay').hide();
}, 250);
newtron
  • 5,938
  • 1
  • 23
  • 19
1

Setting "opacity: 100" or "visibility: hidden" on the overlay isn't actually removing the overlay. What you want to do is remove the element.

Conceptually speaking the overlay is still there. Its like glass above your content, you can see but you can't touch, the invisible overlay glass is still there. It's like super transparent glass window thats been washed with windex That guy is the user trying to click on those links below the overlay.

What you want to do is either remove the element from the DOM or set it to "display: none" after the transition.

The best solution that is cross browser I would use is to set display: none after the animation.

$(".overlay").animate({"opacity": "0"}, function(){
    $(this).hide();
    // OR REMOVE it
    // $(this).remove();
});

Personally I like to wrap my modals in a container and give it a fixed postion and remove the container along with the modal contents on hide but thats me.

I also like jeffery's fancy css transition end method too, if you want to be fancy with css3 but the caveat is you'd probably have to detect which vendor prefix you have to listen to.

Here are the vendor prefixed transition ends:

var transitionEnd = {
  'WebkitTransition' : 'webkitTransitionEnd'
  ,  'MozTransition'    : 'transitionend'
  ,  'OTransition'      : 'oTransitionEnd'
  ,  'msTransition'     : 'transitionend'
  ,  'transition'       : 'transitionend'
}

You'd have to write something to detect it which one is relevant to the user.

$(".overlay").on(transitionEnd, function() {
    $(this).hide();
    // OR REMOVE it
    // $(this).remove();
}
patrickskim
  • 183
  • 7
0

You can listen for a transition end event to set visibility: hidden after the opacity transition.

Community
  • 1
  • 1
Jeffery To
  • 11,836
  • 1
  • 27
  • 42
0

Working only with opacity put the element in a context that can't be positioned via z-index because the element must be mixed with the other elements into the layout (W3C).

Further consideration is that elements with only opacity or visibility, doesn't come extracted from the layout flow so, even if not visible, they still occupy its position and size, and this will prevent every element underlying the one invisible to be reached (clicks are inhibited, buttons aren't clickable, and so on).

To solve your problem, you need to set display to none. In this way, the element will be invisible and no more occupy space into the layout flow.

Ragnarokkr
  • 2,328
  • 2
  • 21
  • 31
0

jQuery's function animate accepts a callback function, which executes when the animation is complete. Example:

$('.overlay').animate({
    opacity: 0
}, 300 /* animation duration in ms */, function () {
    // This will execute when the animation is complete
    $(this).css({
        visibility: 'hidden'
    });
});
Thomas
  • 20,731
  • 6
  • 22
  • 23
0

I think that you CAN use z-index, and you don't need to look for work-arounds. The only thing that you probably need is to put the layout higher in the DOM tree. It's difficult to say without looking at your code, but if you could go to something like

<body>
    <div id="everyting-else">
       ...
    </div>
    <div id="overlay"/>
</body>

and then give #everyting-else a z-index of 2 and #overlay a z-index of 1, that should work whatever the content of "everything-else", because they are in a different stacking context.

It doesn't matter if you use "Relative, Fixed and Absolute positioning" inside the div

vals
  • 61,425
  • 11
  • 89
  • 138