22

CSS3 using Webkit in Safari; I have a button that, when clicked, causes a div to fade in. That div is just a big filled rectangle and it has a few buttons in it, one of whichcauses the same div to fade out.

The problem is this: When the element has faded out (opacity:0), and I click where one of the buttons was, the onClick is still being fired. In otherwords, even though the button can't be seen (opacity:0) it's still there and is part of the event model. I don't want that.

The buttons call the following functions:

//  This displays the overlay (popup)
function showCategoryPopup() {

 // Was playing with the following, but with no success.
 //  popupCategory.style.display = "block";
 //  popupCategory.style.visibility = "visible";

 // Change the attributes that will be animated.
 popupCategory.style.opacity = 1; 
 popupCategory.style.webkitTransform = "scale(1.0)";
}

function hideCategoryPopup() {
 // Change the animated attributes
 popupCategory.style.opacity = 0; 
 popupCategory.style.webkitTransform = "scale(0.7)"; 


// Even if opacity is 0, we still get mouse events.  So, make it hidden?
//    popupCategory.style.visibility = "hidden";
//    popupCategory.style.display = "none";     

}

The CSS class for the overlay is this:

.popupContainer {
    opacity: 0;
    -webkit-transform: scale(0.7);
    -webkit-transition-duration: 0.3s;
    -webkit-transition-timing-function: ease-in-out;
    -webkit-transition-delay: initial;
}

If I don't use the visibility or display settings at all, the animation is fine, but the mouseClick events are triggered for the invisible items.

If I use the blocks, then it toggles on/off with no animation.

If I use the display style, then it sort of works but instead of having the animation display immediately, it only triggers once some other event in the page is triggered, like another button elsewhere on the page.

I thought maybe of adding the "pointer-events:none" to the style used by the pop-up div after it's hidden, but what I'm asking for seems like something you'd often encounter with opacity so it must be a semi-frequent problem.

Thoughts?

Woodster
  • 3,451
  • 3
  • 17
  • 19

3 Answers3

90

A clean(er?) solution for the problem you are having - which is a common problem for things like tooltips and modal popups with a 'fade-in' effect - is to not only transition between opacity, but also the "visibility" property. Unlike 'display', 'visibility' is an actual animatable property, and it will do the right thing in that it makes the element invisible (and non-responsive to input events) only before a transition begins, and only after a transition returns to the initial state.

The previously given answer does work, but depends on JavaScript to manipulate properties which may be less desirable. By having all this done through pure CSS, your JavaScript has to do nothing other than set and unset a class on the element that needs to be shown. If you're creating a tooltip, it can be done without any JS at all by making the tooltip a child element and using the 'hover' pseudo-selector on the parent.

So for for a popup triggered by clicking on something, you would style it like so:

#popup
{
  /* ...cosmetic styling, positioning etc... */

  -webkit-transition: all 0.2s ease-in-out 0s;
  -moz-transition: all 0.2s ease-in-out 0s;
  -ms-transition: all 0.2s ease-in-out 0s;
  transition: all 0.2s ease-in-out 0s;

  opacity: 0;
  visibility: hidden;
}

#popup.shown
{
  opacity: 1;
  visibility: visible;
}

Then your JavaScript can simply toggle the "shown" class.

A live example: http://jsfiddle.net/y33cR/2/

aphax
  • 2,815
  • 3
  • 19
  • 12
  • 1
    This is great. http://www.taccgl.org/blog/css-transition-visibility.html#Appearance_CSS_Visibility explains well the visibility transition semantics. http://www.greywyvern.com/?post=337 goes into great detail (but over-complicates by using a transition delay). – Beni Cherniavsky-Paskin May 25 '15 at 12:47
  • Fine use of visibility, thank you, I didn't know elements hidden by visibility don't trigger events. – George Dimitriadis Jun 27 '17 at 13:08
  • I appreciate the opacity in the code. Based on the wording of the answer I was understanding it to mean I could animate just visibility and it would do what you would expect. – aaaaaa Jun 03 '18 at 02:48
24

What you could do is disable the button while the opacity is set to 0 with the following styles:

pointer-events: none;
cursor: default;

This way they aren't clickable and the cursor doesn't change when it hovers over where the button was. I needed a CSS only solution and this worked for me.

ConorJohn
  • 637
  • 2
  • 11
  • 24
  • While this is one way of doing it, I ran into some strange Safari bugs when using it on a popup with a video element inside, better to go with the animation of the visibility parameter, that seems to work better on all current browsers. – Larzan Aug 26 '18 at 20:36
  • 1
    This should be the accepted answer as it's the most elegant way to do what OP is asking for (+worked for me). – Tomer Gal May 11 '19 at 21:59
12

If you're setting your div to have an opacity of zero, you're still going to be able to interact with the "invisible" item. You want to set it to display:none instead. You could do both, allowing the div to fade out to zero and then tack on the display:none when the animation has finished.

Michael Irigoyen
  • 22,513
  • 17
  • 89
  • 131
  • 3
    True. You should think of an opacity:0 element as if it was made of glass :) – Dennis Kreminsky Jan 13 '11 at 01:39
  • 7
    The display:none // display:block works to resolve the problem with the mouse click, but then opacity doesn't animate from 1 to 0. The div just pops on and off. This was the problem with the display: attribute. I've tried setting the display:none before and after setting opacity:0, but I believe (?) the results of the function are applied en-mass after the function is called and that gives a net result of the block disappearing instead of fading out. Is there something else I need to do so it sets the block after the opacity animation finishes? – Woodster Jan 13 '11 at 03:35
  • @Woodster I could recommend you look into using jQuery for something like this. The built in animation effects (like `fadeOut`) are easy to use. `fadeOut` fades whatever out and then sets it to `display:none` out of the box. – Michael Irigoyen Jan 13 '11 at 03:38
  • @mririgo I accept that as a good tip. I've never used jQuery before, but just read the first tutorial, it looks like the right tool for this task so I'll give it a go. Thanks for the lead! – Woodster Jan 13 '11 at 04:03
  • 1
    Update: jQuery was totally a great solution to this problem. So. Much. Easier. Voted-Up. – Woodster Jan 20 '11 at 15:34
  • 7
    `display` is not a supported property for CSS transitions, and changing the display property will cause the toggle effect instead of transition effect. `visibility` is what you want to work with. – joanwolk Jan 09 '12 at 11:23