26

Basically, a "highlight" class is added to elements with class "edge" dynamically through javascript on mouseenter. The highlight class is removed on mouseleave. I want to transition the border-color of these elements. However, this "highlight" class also modifies the stack order. I want a z-index of 1 to be set on all highlighted edges before the transition begins (on mouseenter) and I want the z-index of 1 to be removed after the transition completes (on mouseleave). Currently the z-index property is reset immediately after the "highlight" class is removed.

Basic set up:

.edge {

    border-color: hsl(0, 0%, 40%);
    border-style: solid;
    border-width: (set appropriately in another selector);

    transition-duration: 1s;
    -moz-transition-duration: 1s;
    -o-transition-duration: 1s;
    -webkit-transition-duration: 1s;

    transition-property: border-color;
    -moz-transition-property: border-color;
    -o-transition-property: border-color;
    -webkit-transition-property: border-color;
}

.edge.highlight {
    border-color: hsl(0, 0%, 85%);
    z-index: 1;
}

First attempt (obviously the delay fixes the timing on one end and messes it up on the other):

.edge {
    border-color: hsl(0, 0%, 40%);
    border-style: solid;
    border-width: (set appropriately in another selector);

    transition-duration: 1s, 0;
    -moz-transition-duration: 1s, 0;
    -o-transition-duration: 1s, 0;
    -webkit-transition-duration: 1s, 0;

    transition-delay: 0, 1s;
    -moz-transition-delay: 0, 1s;
    -o-transition-delay: 0, 1s;
    -webkit-transition-delay: 0, 1s;

    transition-property: border-color, z-index;
    -moz-transition-property: border-color, z-index;
    -o-transition-property: border-color, z-index;
    -webkit-transition-property: border-color, z-index;
}

Any and all help is very much appreciated. Thanks in advance.

edit: Please keep in mind that the user can mouseenter/mouseleave on several different edges before the transitions have a chance to complete. Thanks.

4 Answers 4

68

You can use a delay, as Jcubed suggested, or the timing functions step-end and step-start. The trick is to use two different timing functions: stepped for z-index, and linear for opacity and other continuous properties.

edge {
    z-index: -1;
    opacity: 0;
    transition: z-index 0.5s step-end, opacity 0.5s linear;
}

edge.highlight {
    z-index: 1;
    opacity: 1;
    transition: z-index 0.5s step-start, opacity 0.5s linear;
}

Example: http://jsfiddle.net/cehHh/8/

4
4

Use transition-delay. You can make it so it rises on hover but waits a while before sinking on hover out by assigning a different delay time to the element when it is in its hover state.

Example: http://jsfiddle.net/vQqzK/1/

This works in chrome, not sure if it will work in other browsers.

https://developer.mozilla.org/en/CSS/transition-delay

1
  • I adapted your example to my particular circumstances. It's close but no cigar. The issue is that there are overlapping edges and it's possible to have many different transitions running at once. Your technique works as long as the user doesn't cascade transitions over overlapping edges (i.e. waits until the mouseleave transition completes before commencing another mouseenter transition on an overlapping edge). Thanks though. Almost! I'd vote up your answer because it's still useful, but I don't have the rep for it.
    – Shane
    Commented May 14, 2012 at 20:36
1

You could use two classes, one for each transition (the first one for the color, then for the z-index). Note that the following is made using jQuery for convenience, and it's only for one edge. To do so for multiple edge, you'd need to store one timer per edge.

Given the following markup:

​<div class="edge"></div>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

CSS:

.edge {
    width:40px;
    height:40px;
    border-color: hsl(0, 0%, 40%);
    border-style: solid;
    border-width: (set appropriately in another selector);

    transition-duration: 1s;
    -moz-transition-duration: 1s;
    -o-transition-duration: 1s;
    -webkit-transition-duration: 1s;

    transition-property: border-color;
    -moz-transition-property: border-color;
    -o-transition-property: border-color;
    -webkit-transition-property: border-color;
}

.edge.highlight {
    border-color: hsl(0, 0%, 85%);
    z-index: 1;
}
.edge.endHl{
    border-color: hsl(0, 0%, 65%);
    z-index: 1;
}

(I added a little color change on the second transition just to show it).

And the following JS:

var myTime = null;
function resetTime() {
    if (myTime !== null) {
        clearTimeout(myTime);
        myTime = null;
    }
}
$(".edge").mouseenter(function() {
    resetTime();
    $(this).addClass("highlight");
    $(this).removeClass("endHl");
});
$(".edge").mouseleave(function() {
    resetTime();
    myTime = setTimeout(function() {
        $(".edge").removeClass("endHl");
    },1000);
    $(this).removeClass("highlight");
    $(this).addClass("endHl");
});

It will remove the z-index only after 1 sec, and will apply only on the exit.

You can see it in action here: http://jsfiddle.net/TptP8/

0

If you're having troubles with z-index transition solution from @z0r - you can postpone z-index change via animation as an alternative, but transition worked better for me in Safari

.hasDelayedZIndex {
  animation: setZIndexWithDelay 0.01s 1s forwards;      
}

@keyframes setZIndexWithDelay {
  to {
    z-index: 1;
  }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.