CSS 容器的 TranslationX 在 Safari 中不工作
CSS TranslationX of container not working in Safari
今天我注意到 Safari (9.0) 的一个奇怪行为,当时 我将过渡应用到在 X 轴上平移的元素,同时宽度也在增加。
我已经重现了这个 JsFiddle 中的行为。这是为那些更喜欢它的人准备的嵌入代码。在 Firefox 和 Chrome 中看起来很流畅,但在 Safari 中却不是,有没有人有解决方案或最好的方法来达到同样的效果?
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() { container.classList.toggle('open'); });
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, transform 1s;
}
.open ul {
width: 200%;
transform: translateX(-50%);
}
li {
/* Just some style first */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
padding: 1em 0;
display: inline-block;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
通过动画 margin-left
而不是 translateX
结果在 Safari 中是可以接受的:
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, margin-left 1s;
}
.open ul {
width: 200%;
margin-left:-100%;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
使用 scaleX
而不是动画 width
更流畅,但可能不是您想要的。
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: transform 1s;
}
.open ul {
transform: translateX(-50%) scaleX(2);
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
重新发布作为回答。
Here 是 jsFiddle 结果和片段如下:
var button = document.getElementsByTagName('button')[0];
var container = document.getElementsByTagName('div')[0];
var timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50, ease: Power2.easeInOut });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
希望这对您有所帮助。
P.S。我使用 GSAP 已经有一段时间了,我不记得遇到过任何特定于浏览器的问题,除非浏览器会做一些不同的事情。对 GSAP 进行一些研究,它会告诉您浏览器兼容性是他们的主要卖点之一。
因此,我将尝试在这里总结两个最佳解决方案:一个使用 CSS 变换,另一个使用 Javascript 动画 (GSAP)。
CSS 转换
在性能方面,建议仅对变换(平移、缩放、旋转)和不透明度设置动画。如果您对更多优化细节感兴趣,可以 have a look at this article by Anna Migas.
因此,正如@Meiko 所建议的那样,最好的解决方案是仅对缩放和平移属性设置动画。这是一个代码示例 (and the JSFiddle)
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
})
.container,
ul {
width: 100%;
}
ul {
overflow: hidden;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
position: relative;
transition: transform 1s;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li::before {
content: '';
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
background-color: red;
z-index: -1;
transition: transform 1s;
}
li:first-child::before {
background-color: green;
}
.open li:first-child {
transform: translateX(-100%);
}
.open li:nth-of-type(2) {
transform: translateX(-50%);
}
.open li:nth-of-type(2)::before {
transform: scaleX(2);
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
优点:
- 只用一点点Javascript来切换class,
- 浏览器支持非常好(需要特定于供应商的属性和一些测试),
- 在 GPU 内存上非常快速和轻便。
缺点:
- 在使用方面非常有限(第二个单元格的实际宽度保持不变),
- 需要更多行CSS。
JS 动画(使用 GSAP)
此解决方案已由@Tahir Ahmed 建议并使用 GSAP library. As a side note, I really think that this is the best js library out there for this kind of animation. Here is a snippet of how it works (and the JSFiddle):
var button = document.getElementsByTagName('button')[0],
timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50 });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
})
.container {
width: 100%;
overflow: hidden;
}
ul {
width: 100%;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
background-color: red;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li:first-child {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
优点:
- 真灵活,天马行空!
- 您可以为属性设置动画,例如
display
(在 CSS 中不能),
- 兼容所有浏览器(低至 IE6)。
缺点:
- 需要第三方库(约30kb),
- GPU 似乎有点难(尽管需要更多测试才能确定)。
最后它确实取决于您需要的动画,但如果它比移动容器稍微复杂一点,那么我会选择 GSAP。
今天我注意到 Safari (9.0) 的一个奇怪行为,当时 我将过渡应用到在 X 轴上平移的元素,同时宽度也在增加。
我已经重现了这个 JsFiddle 中的行为。这是为那些更喜欢它的人准备的嵌入代码。在 Firefox 和 Chrome 中看起来很流畅,但在 Safari 中却不是,有没有人有解决方案或最好的方法来达到同样的效果?
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() { container.classList.toggle('open'); });
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, transform 1s;
}
.open ul {
width: 200%;
transform: translateX(-50%);
}
li {
/* Just some style first */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
padding: 1em 0;
display: inline-block;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
通过动画 margin-left
而不是 translateX
结果在 Safari 中是可以接受的:
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, margin-left 1s;
}
.open ul {
width: 200%;
margin-left:-100%;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
使用 scaleX
而不是动画 width
更流畅,但可能不是您想要的。
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: transform 1s;
}
.open ul {
transform: translateX(-50%) scaleX(2);
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
重新发布作为回答。
Here 是 jsFiddle 结果和片段如下:
var button = document.getElementsByTagName('button')[0];
var container = document.getElementsByTagName('div')[0];
var timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50, ease: Power2.easeInOut });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
希望这对您有所帮助。
P.S。我使用 GSAP 已经有一段时间了,我不记得遇到过任何特定于浏览器的问题,除非浏览器会做一些不同的事情。对 GSAP 进行一些研究,它会告诉您浏览器兼容性是他们的主要卖点之一。
因此,我将尝试在这里总结两个最佳解决方案:一个使用 CSS 变换,另一个使用 Javascript 动画 (GSAP)。
CSS 转换
在性能方面,建议仅对变换(平移、缩放、旋转)和不透明度设置动画。如果您对更多优化细节感兴趣,可以 have a look at this article by Anna Migas.
因此,正如@Meiko 所建议的那样,最好的解决方案是仅对缩放和平移属性设置动画。这是一个代码示例 (and the JSFiddle)
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
})
.container,
ul {
width: 100%;
}
ul {
overflow: hidden;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
position: relative;
transition: transform 1s;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li::before {
content: '';
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
background-color: red;
z-index: -1;
transition: transform 1s;
}
li:first-child::before {
background-color: green;
}
.open li:first-child {
transform: translateX(-100%);
}
.open li:nth-of-type(2) {
transform: translateX(-50%);
}
.open li:nth-of-type(2)::before {
transform: scaleX(2);
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
优点:
- 只用一点点Javascript来切换class,
- 浏览器支持非常好(需要特定于供应商的属性和一些测试),
- 在 GPU 内存上非常快速和轻便。
缺点:
- 在使用方面非常有限(第二个单元格的实际宽度保持不变),
- 需要更多行CSS。
JS 动画(使用 GSAP)
此解决方案已由@Tahir Ahmed 建议并使用 GSAP library. As a side note, I really think that this is the best js library out there for this kind of animation. Here is a snippet of how it works (and the JSFiddle):
var button = document.getElementsByTagName('button')[0],
timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50 });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
})
.container {
width: 100%;
overflow: hidden;
}
ul {
width: 100%;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
background-color: red;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li:first-child {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
优点:
- 真灵活,天马行空!
- 您可以为属性设置动画,例如
display
(在 CSS 中不能), - 兼容所有浏览器(低至 IE6)。
缺点:
- 需要第三方库(约30kb),
- GPU 似乎有点难(尽管需要更多测试才能确定)。
最后它确实取决于您需要的动画,但如果它比移动容器稍微复杂一点,那么我会选择 GSAP。