How can the widths/heights of child elements with translateZ
be calculated within a parent container that has a specified perspective
value (keyword: "parallax") in relation to its parents width/height?
I am working on a website design that incorporates a parallax effect on both axes. While I have figured out most aspects of my mockup, there is one issue remaining - determining the widths/heights of the children when they exceed 100%. Due to the parent's perspective and the children's translateZ values, the visual alignment of their widths/heights is distorted.
The formula for scaling the child elements is:
1 + (translateZ * -1) / perspective
. However, I have been unable to find a formula for calculating width/height. It should be noted that everything works correctly when children's widths/heights are <= 100%.Please refer to the image below to see the result when width >= 100% (containers have top offset for visibility).
https://i.sstatic.net/9GaM8.png
In my case, it is crucial for all child elements to visually have consistent widths/heights.
When working in SASS (preferred): PEN or SassMeister
In CSS: PEN
Relevant links from the specifications that may provide assistance:
https://www.w3.org/TR/css-transforms-1/#recomposing-to-a-3d-matrix
https://www.w3.org/TR/css-transforms-1/#mathematical-description
I have searched extensively but have not found any information leading me in the right direction. Thank you in advance...
html, body {
height: 100%;
overflow: hidden;
width: 100%;
}
#projection {
perspective: 1px;
perspective-origin: 0 0;
height: 100%;
overflow: auto;
width: 100%;
}
.pro {
transform: scale(1) translate(0px, 0px) translateZ(0px);
height: 100%;
position: absolute;
transform-origin: 0 0;
transform-style: preserve-3d;
width: 100%;
}
.pro--1 {
transform: scale(4) translate(0px, 0px) translateZ(-3px);
width: 110%;
}
.pro--2 {
transform: scale(3) translate(0px, 50%) translateZ(-2px);
width: 110%;
}
.pro--3 {
transform: scale(2) translate(0px, 100%) translateZ(-1px);
width: 110%;
}
.pro {
background: #333;
box-shadow: inset 0 0 0 5px orange;
color: orange;
font-size: 4em;
line-height: 1em;
text-align: center;
}
.pro--2 {
background: rgba(75, 75, 75, 0.5);
box-shadow: inset 0 0 0 5px green;
color: green;
line-height: 4em;
}
.pro--3 {
background: rgba(75, 75, 75, 0.5);
box-shadow: inset 0 0 0 5px white;
color: white;
line-height: 7em;
}
<div id="projection">
<div class="pro pro--1">pro--1</div>
<div class="pro pro--2">pro--2</div>
<div class="pro pro--3">pro--3</div>
</div>
SASS
@mixin projection($translateZ: 0, $translateX: 0, $translateY: 0, $width: 0, $height: 0, $perspective: $perspective)
// strip and sanitize units for further calculations
// units must be "px" for both $translateZ and $perspective
$unit: unit( $translateZ )
@if '' != $unit
$translateZ: $translateZ / ($translateZ * 0 + 1)
@if 'px' != $unit
@warn '$translateZ must have "px" as unit!'
$unit: unit( $perspective )
@if '' != $unit
$perspective: $perspective / ($perspective * 0 + 1)
@if 'px' != $unit
@warn '$perspective must have "px" as unit!'
$unit: 0px // yeah - technically this is no unit
// calculate scaling factor
$scale: 1 + ($translateZ * -1) / $perspective
// sanitize units for translateX, translateY, translateZ
$translateZ: $translateZ + $unit
@if unitless( $translateX )
$translateX: $translateX + $unit
@if unitless( $translateY )
$translateY: $translateY + $unit
// render css "transform: scale() translate(x, y) translateZ()"
transform: scale( $scale ) translate($translateX, $translateY) translateZ( $translateZ + $unit )
$width: 110% // 100% works perfectly
$translateZ--1: -3 // "px" will be added in mixin
$translateZ--2: -2
$translateZ--3: -1
$perspective: 1
html, body
height: 100%
overflow: hidden
width: 100%
#projection
perspective: $perspective + 0px
perspective-origin: 0 0
height: 100%
overflow: auto
width: 100%
.pro
@include projection()
height: 100%
position: absolute
transform-origin: 0 0
transform-style: preserve-3d
width: 100%
.pro--1
@include projection( $translateZ--1 )
width: $width
.pro--2
@include projection( $translateZ--2, 0, 50% )
width: $width
.pro--3
@include projection( $translateZ--3, 0, 100% )
width: $width