I'm building a "3D carousel" from scratch.
The carousel contains 3 slides, which are stacked on-top on each other using CSS Grid (they all have the same grid-area: 1/1
).
The slide 1 stays at the center of the carousel.
I'm using a translate to offset slides 2 (to the left) and 3 (to the right), which gives a basic 3D effect.
I would like the container of my carousel to perfectly fit the content (the 3 slides), so I'm setting a padding on the left and right side of my carousel, to compensate from the "overflow" of slides 2 and 3.
So far, my padding is just equal to the offset from slides 2 and 3. (If I translateX(-100px)
my slide 2, a padding-left: 100px
works fine.
It gets trickier when I scale(0.5)
my slides 2 and 3: the value of the padding is off, I can manually find a value that works but I can't find the formula which would pfit everytime I want to change either the main slide width, the offset or the scale factor.
I have made a Codepen to illustrate the issue, which occurs at less than 1024px (you have to resize the window to see the problem.
https://codepen.io/AymarTissedre/pen/gOKMEwa
window.onload = function (event) {
document.querySelector("span").innerHTML = window.innerWidth 'px'
};
window.onresize = function (event) {
document.querySelector("span").innerHTML = window.innerWidth 'px';
};
* {
box-sizing: border-box;
}
div {
--offset: 100px;
--scaling: 0.75;
--width: 200px;
--padding: calc(
var(--width) / 2 * var(--scaling)
);
border: 1px dashed black;
background: lightgrey;
display: inline-flex;
width: var(--width);
padding: 0 var(--padding);
box-sizing: content-box;
}
div ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
}
@media screen and (max-width: 1025px) {
div ul {
--offset: 75px;
--scaling: 0.75;
--width: 150px;
}
}
div ul li {
grid-area: 1/1;
border: 1px solid black;
width: 200px;
height: 200px;
}
div ul li:nth-child(1) {
background-color: red;
z-index: 1;
}
div ul li:nth-child(2) {
background-color: blue;
transform: translateX(var(--offset)) scale(var(--scaling));
}
div ul li:nth-child(3) {
background-color: green;
transform: translateX(calc(var(--offset) * -1)) scale(var(--scaling));
}
<div>
<ul>
<li>Card 1</li>
<li>Card 2</li>
<li>Card 3</li>
</ul>
</div>
<p>At less than 1024px resolution wide, padding is not correctly calculated (width of the Card 1 changes, offset of Cards 2 and 3 too.)</p>
<p>The padding (lightgrey zone) should <strong>NOT</strong> be visible at the left / right side under 1024 pixels </p>
<p> Current viewport width: <span></span> </p>
Here is a list of padding values that I found manually, that perfectly fit with the corresponding width, offset and scaling. I didn't manage to find the common formula that links them. Beware as the values may be rounded (e.g. 68px = 67.5px).
// width(px) offset(px) scaling padding(px)
// 150 50 0.50 = 12
// 300 100 0.50 = 25
// 200 100 0.50 = 50
// 150 100 0.50 = 62
// 350 150 0.50 = 62
// 250 100 0.75 = 68
// 300 175 0.50 = 100
// 300 200 0.50 = 125
// 300 200 0.75 = 162
Happy to provide more details if needed.
CodePudding user response:
The formula should be:
--padding: calc(var(--offset) - var(--width)*(1 - var(--scaling))/2)
From the offset your remove the difference between the non scaled element and the scaled one (1 - var(--scaling)
) then you divide by 2 because we only remove one side.
Also make sure to update the variables on the div
not the ul
because the padding and width are defined on the div
window.onload = function (event) {
document.querySelector("span").innerHTML = window.innerWidth 'px'
};
window.onresize = function (event) {
document.querySelector("span").innerHTML = window.innerWidth 'px';
};
* {
box-sizing: border-box;
}
div {
--offset: 100px;
--scaling: 0.75;
--width: 200px;
--padding: calc(var(--offset) - var(--width)*(1 - var(--scaling))/2);
border: 1px dashed black;
background: lightgrey;
display: inline-flex;
width: var(--width);
padding: 0 var(--padding);
box-sizing: content-box;
}
div ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
width: 100%;
}
@media screen and (max-width: 1025px) {
div {
--offset: 75px;
--scaling: 0.75;
--width: 150px;
}
}
div ul li {
grid-area: 1/1;
border: 1px solid black;
aspect-ratio:1;
}
div ul li:nth-child(1) {
background-color: red;
z-index: 1;
}
div ul li:nth-child(2) {
background-color: blue;
transform: translateX(var(--offset)) scale(var(--scaling));
}
div ul li:nth-child(3) {
background-color: green;
transform: translateX(calc(var(--offset) * -1)) scale(var(--scaling));
}
<div>
<ul>
<li>Card 1</li>
<li>Card 2</li>
<li>Card 3</li>
</ul>
</div>
<p>At less than 1024px resolution wide, padding is not correctly calculated (width of the Card 1 changes, offset of Cards 2 and 3 too.)</p>
<p>The padding (lightgrey zone) should <strong>NOT</strong> be visible at the left / right side under 1024 pixels </p>
<p> Current viewport width: <span></span> </p>