CSS 3D transform to make trapezoid of given edge l

2020-03-23 18:34发布

问题:

I have an element of given dimensions (say, 100x300 px) living in a container of the same height and variable width that I want to transform using rotateX around -webkit-transform-origin: top center; while picking the -webkit-perspective of the container so that it appears that the bottom line of the image stays where it is but only expands to fill the entire container.

Wow, that sounds confusing. Here's a picture:

So basically, I want to create a trapezoid with a fixed upper width and a variable lower width. I can't however quite figure out the math behind the relations... Javascript welcome. Following example works IF the body is 600px wide: http://jsfiddle.net/24qrQ/

Now the task is to change the perspective and rotation continuously with the body width. Any Ideas?

回答1:

Okay, after a glass of wine the maths came back to me:

First, let's look at the perspective / rotation ratio. Viewed from the side, it looks like this:

The red element is rotated around its upper edge, if we project its lower edge to the lower edge of the container, the intersection between the projection line and the line perpendicular to the container at its upper edge is the required viewpoint. We get this by simple trigonometry (notice phi here is in radians, not in degree).

If we apply this, the lower edge of the element will always appear on the lower edge of the container. Now the free parameter is rotation. This seems to have the relation

rad = pi/2 - element.width / container.width

for sufficiently large widths, however I can't quite wrap my head around the actual relationship. Here is a fiddle: http://jsfiddle.net/24qrQ/6/



回答2:

Basically, you are trying to figure out how to put an object in 3D space, so it lines up with a 2D viewport. That's always a tricky thing.

I don't know what the math is, and most other probably don't either. This is hardly a common problem. But here's how I would go about figuring it out.

The only variable here is width. And the 2 values that would need to change based on the width is -webkit-perspective on the container and -webkit-transformon the inner element. So I would manually edit the values for a few different widths and record the 3D values that you had to enter to make things look right. (I'd use the web inspector to edit the values in realtime so you get immediate feedback)

One you have a few data points, plot them out on a graph and then try to figure out how they change. I have a hunch it's a parabolic curve, but it may but hyperbolic or sinusoidal too, my 3D math isn't good enough to know for sure.

Then you can try figure out an equation where when you input the widths you've sampled, you get back the manual 3D values you set previously. Then use JS to read the width of the container and set the CSS values to make it look right.


I've done that with 3 widths 300, 450, 600:

http://jsfiddle.net/24qrQ/3/

Some trends are obvious. As width increases, perspective goes up at an increasing reate, and rotation goes down at an increasing rate.

Figuring out the exact formula, is now up to you.


As a simpler alternative, if figuring out a formula becomes too difficult, you could manually curate a handful of widths and 3D values that look nice and store them in JS somewhere. Then you could just linearly interpolate between them. It wouldn't be exact, but it might be close enough.

It would also be less fun!