Reputation: 616
When using transform with percent value on container that has float width (for ex. 800.63px) Chrome always rounds position in pixels incorrectly. This typically happens with em/rem width in combination with percent (see example below):
HTML:
<div class="container">
<div class="wrap">
<div class="slider">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</div>
SCSS:
.container {
width: 38rem;
}
.wrap {
width: 33%;
overflow: hidden;
}
.slider {
white-space: nowrap;
font-size: 0;
transform: translate3d(-1000%,0,0);
}
.item {
display: inline-block;
height: 8rem;
width: 100%;
background: limegreen;
&:nth-child(even) {
background: orangered;
}
}
The result is some part of next slide is always visible. Looks like Chrome first rounds the item width and then multiplies it by percent value.
Is there any known workaround for this? If I do the math in JS and use px values in transform then everything is (almost) perfect, but shouldn't it "just work" with percents too?
Please, see fiddle for working example: https://jsfiddle.net/Lumh07te/37/
Upvotes: 0
Views: 212
Reputation: 64244
Change the way you set your sizes.
Instead of the slider having width 100%, and needing a maximum transform of 1000%, set it to a width of 1000%, and a needed maximum transform of 100%.
And the items width is now 10% instead of 100%
in your original code, wrap has a width that is not integer, but than in the layout is forced to render as an integer value in pixels. Then , translating a 1000% of this value multiplies the rounding errors by 10. If you instead set the width to 1000%, the rounding to pixels is done on this size, and then it is mutiplyed by values less than 1 (0.5, 0.6, 0.7.. ) or 1 at a maximum
.container {
width: 38rem;
}
.wrap {
width: 33%;
overflow: hidden;
}
.slider {
width: 1300%;
white-space: nowrap;
font-size: 0;
transform: translateX(calc(-500% / 13));
transition: transform 0.4s;
}
.test {
height: 50px;
}
.test:hover ~ .wrap .slider {
transform: translateX(calc(-800% / 13));
}
.item {
display: inline-block;
height: 8rem;
width: calc(100% / 13);
background: limegreen;
font-size: 30px;
}
.item:nth-child(even) {
background: orangered;
}
<div class="container">
<div class="test">test</div>
<div class="wrap">
<div class="slider">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
</div>
</div>
</div>
Upvotes: 1