beggs
beggs

Reputation: 4195

CSS3 matrix3d rectangle to trapezoid transformation

I am trying to use webkit's support for CSS3 transform: matrix3d(<matrix>) to create a 'falling card' effect. (The only target for the output of this is Chrome)

The end effect should transition through the 4 stages below and end up as just a horizontal line:

enter image description here

Here is the CSS I have now:

#test { 
            margin: auto auto;
            height: 200px;
            width: 200px;
            border:1px solid black;
            background-color: lightblue;
            -webkit-perspective: 1000; 
            -webkit-transform-origin: 50% 100%;
            -webkit-transform-style: preserve-3d;
            -webkit-animation-name: flip-card;        
            -webkit-animation-duration: 1s;        
            -webkit-animation-iteration-count: infinite;        
            -webkit-animation-timing-function: linear;
            -webkit-box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.5);
        }
         @-webkit-keyframes flip-card {
            0%    {-webkit-transform: ;}
            100%    {-webkit-transform:
                        matrix3d(1, 0, 0, 0,
                                 0, 1, 0, 0, 
                                 0, 0, 0, 0, 
                                 0, 0, 0.001, 1);}
        }    

And the HTML is simple for testing:

<body>
   <div id="test">this div should fall forward...</div>
</body>

The matrix3d in the above was based on reading this SO question, but it produces a shrinking square that flips around the x-axis defined by the bottom of the initial box.

I understand that CSS 2d matrix can only produce rectangles and parallelograms by transformation of a box and that irregular shapes need the matrix3d transform operation (this was helpful in refreshing my fading linear algebra!), but I seem to only be able to produce rectangles and parallelograms.

I've looked around at some of the SO questions tagged with matrix and transformation. Most of them are not CSS based and I have not been able to get the transformation I want.

Upvotes: 8

Views: 14881

Answers (3)

Michael Mullany
Michael Mullany

Reputation: 31715

-webkit-perspective doesn't work in Chrome yet (just Safari), so this won't work (try your code in Safari). Also 3D transforms in Chrome, in general, are a bit iffy, and don't combine well with gradients, for one.

Also rotate3d(1, 0, 0, 90deg) works just as well as a matrix to accomplish what you're doing. The matrix notation is just a short way of combining 3D rotate, skew, move and origin into a single array. Since you're only rotating around the x-axis, you don't need to go to these lengths.

webkit-transform: perspective(800) rotate3d(1, 0, 0, -90deg)

Is exactly what you need.

Update: Here is a link to a jsfiddle with exactly what you are looking for that works in both chrome and safari. Please note that its important to specify that the transform origin for the flip is the same as the origin for the perspective. Webkit-perspective origin specifies where the "camera" is in 3D space relative to any 3d transforms and it's easy to get unintuitive results if you're not careful.

2nd Update: Perspective is now supported in all edge browsers (although firefox's anti-aliasing has little to recommend it (and needs -moz obviously))

3rd Update: Updated the fiddle for cross browser for Firefox, IE and unprefixed.

Upvotes: 9

frantisek
frantisek

Reputation: 366

If you are using IE10, then the solution could be:

.up{
    -ms-transform-origin: 50% 100%;
    -ms-transform: perspective(100px) rotateX(7deg);
}

.down{
    -ms-transform-origin: 50% 0%;
    -ms-transform: perspective(100px) rotateX(-7deg) scale(1);
}

Upvotes: 0

methodofaction
methodofaction

Reputation: 72405

I was reading the CSS transition spec when I noticed border-width is animatable, and you can fake trapezoids using border widths. This means you can fake falling cards in Chrome, Opera and FF4!

#stage {
  margin-top: 200px;
  position: relative;
}

#trapezoid {
    position: absolute;
    bottom: 0;
    border: solid 1px #fff;
    border-bottom: solid 200px #c00;
    width: 200px;
    -webkit-transition: all ease 1s;

}

#stage:hover #trapezoid {
  border: solid 50px #fff;  
  border-bottom: solid 20px #f11;
  width: 100px;

}

Of course, this has major caveats: in your example the card is falling frontward, I tried but it seems this is not possible with this technique. Any content inside the shape won't be transformed, it's just the card shape. Oh, and the card shape can't have any borders. Major drawbacks that limit it's real-life application.

Still, it's pretty cool! Play with it here: http://jsfiddle.net/mxgAu/

Upvotes: 3

Related Questions