Warface
Warface

Reputation: 5119

How would you achieve this 3d hover effect?

I'm trying to do a 3d mouseover effect when you're over a DIV. Here's what it's look like for now

http://jsfiddle.net/6TNBU/

I would like to know how I could make in sort that the lower-left and top-right corner would have a cleaner shadow, oblique style. I thought maybe load a triangle on those corners but I would like to know if there's any other way I could achieve that.

Thanks

Upvotes: 3

Views: 1228

Answers (2)

Jared Farrish
Jared Farrish

Reputation: 49198

I thought it would be fun to try the "blocklets" approach, ie, use divs to create the appearance of 3D by layering divs between the background and the box, with the in-betweens being offset from the parent by one pixel top and left to create the appearance of depth.

Note, I'm not suggesting this a great approach, as a number of issues could impact performance. However, I was pleasantly surprised to see that I could get relatively good performance with the below code, and yes, it appears to work (as-is) in IE7/8/9, as well as FF10 and Chrome 17.

So if it's useful to you, I'm glad to hear that, although I would hasten to add it's really just a jumping-off/starting point. There are some known issues I have observed, such as multiple boxes cause the animation to kind've fall apart. But it appears to work alright with a single box, and I imagine with some work it could be made to work better, and could even be ported to a plugin (if someone so desired).

Let me know if you have any questions or if you see anything that can/should be fixed, or if you think it's stupid/pointless/just turrible and can explain why.

HTML

Basic markup:

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

CSS

I added the borders because I thought it looked better:

.shadow {
    position: relative;
    float: left;
}
.threed {
    background: black;
    position: absolute;
    top: 0;
    left: 0;
}
.box {
    width: 298px;
    height: 298px;
    background: #cacaca;
    position: relative;
    border: 1px solid #aaa;
    border-left: 1px solid #acacac;
    border-top: 1px solid #acacac;
}​

jQuery

$(function(){
    var $threed = $('<div class="threed">'),
        $shadow = $('<div class="shadow">'),
        offset = 0;

    var init = function($jq, distance, speed){
        $jq.each(function(){
            var $this = $(this),
                $threeds,
                $shadow_clone = $shadow.clone(),
                $threed_clone,
                borderlw = parseInt($this.css('border-left-width')),
                borderrw = parseInt($this.css('border-right-width')),
                bordertw = parseInt($this.css('border-top-width')),
                borderbw = parseInt($this.css('border-bottom-width')),
                width = parseInt($this.innerWidth()) + borderlw + borderrw,
                height = parseInt($this.innerHeight()) + bordertw + borderbw,
                dimensions = {height: height, width: width};

            $shadow_clone.css({
                height: height + distance, 
                width: width + distance}
            );

            $this.data('distance', distance).wrap($shadow_clone);

            for (var i = 0; i <= distance; i++) {
                var $threed_clone = $threed.clone();

                $this.before($threed_clone);
                $threed_clone.css(dimensions).data('dimensions', {
                    left: i, top: i
                });
            }

            $this.data('threeds', $this.siblings('.threed'));

            $this.mouseenter(function(){
                var offset = 0,
                    properties = {
                        left: distance, 
                        top: distance
                    },
                    options = {
                        duration: speed, 
                        step: goUp, 
                        complete: finishThreeD
                    };

                $(this).stop().animate(properties, options);
            })
            .mouseleave(function(){
                var properties = {
                        left: 0, 
                        top: 0
                    },
                    options = {
                        duration: speed, 
                        step: goDown, 
                        complete: finishTwoD
                    };

                $(this).stop().animate(properties, options);
            });
        });
    };

    var goUp = function(){
        var _offset = parseInt(this.style.left);

        if (_offset > offset) {
            offset = _offset;

            $($(this).data().threeds[offset - 1])
                .prevAll('.threed').each(function(){
                    $(this).css($(this).data().dimensions);
                });
        }
    };

    var finishThreeD = function() {
        $(this).data().threeds.each(function(){
            $(this).css($(this).data().dimensions);
        });
    };

    var goDown = function (){
        var _offset = parseInt(this.style.left);

        if (_offset < offset) {
            offset = _offset;

            $($(this).data().threeds[offset - 1])
                .nextAll('.threed').css({top: 0, left: 0});

            if (offset === 0) {
                $(this).data().threeds.css({top: 0, left: 0});
            }
        }
    };

    var finishTwoD = function (){
        $(this).data().threeds.css({top: 0, left: 0});

        offset = 0;
    };

    var inc = 1;

    $('.box').each(function(){
        init($(this), 10 * inc, 100 * (2.5 * inc));
        inc++;
    });
});​

http://jsfiddle.net/zuppm/

Upvotes: 1

David Thomas
David Thomas

Reputation: 253318

If you don't mind using pseudo-elements, there's the ::before and ::after (although note that, as I recall, IE doesn't recognise the double-colon declaration, so you'd really have to use :before and :after):

#box::before {
    content: ' ';
    position: absolute;
    top: -10px;
    left: -10px;
    bottom: 0;
    height: 100%;
    background-color: #f90;
    border-bottom: 10px solid white;
    border-right: 10px solid black;
}

#box::after {
    content: ' ';
    position: absolute;
    top: -10px;
    left: -10px;
    right: 0;
    width: 100%;
    border-bottom: 10px solid black;
    border-right: 10px solid white;
}

JS Fiddle demo.

Upvotes: 3

Related Questions