JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://unpkg.com/rematrix"></script>
Both elements below should appear the same!<br/>
<div style="transform: rotateY(30deg) rotateX(-30deg) perspective(1000px);display:inline-block;width:300px;">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px);background:white">preserve-3d
</div>
</div>
</div>
</div>
</div>
</div>
<div style="transform: rotateY(30deg) rotateX(-30deg) perspective(1000px);display:inline-block;width:300px;vertical-align:top;">
<div style="transform:translateZ(30px)">
<div class="portal">
<div class="mover">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px)">
<div style="transform:translateZ(30px);background:white">flat
</div>
</div>
</div>
</div>
</div>
</div>
</div>
CSS
div:not(.mover){
transform-style: preserve-3d;
border: 2px solid red;
padding: 8px;
}
.portal{
/* `overflow: hidden` should be used here instead of `transform-style: flat !important`, but I have it removed for testing */
transform-style: flat !important;
transform: translateZ(30px);
background: #eee;
}
.mover{
transform-style: preserve-3d;
}
JavaScript
// I use https://github.com/jlmakes/rematrix for basic matrix math, however this library doesn't support complex operations like decomposition.
Object.assign(window, Rematrix)
// Utility to generate matrix based on transforms
function transform(...step) {
return step.reduce(multiply, identity())
}
// Calculate matrix of top-level div
const parentMatrix = transform(
rotateY(30),
rotateX(-30),
perspective(1000),
)
// Calculate matrix of the portal element
// We can ignore padding/border offset since that is alreadt applied before transform
const portalTransform = transform(
parentMatrix,
translateZ(30),
translateZ(30),
)
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// Given the transforms of it's parent element and itself What algorithm is needed here????
const final = identity()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
document.querySelector('.mover').style.transform = toString(final)