Created
March 31, 2016 12:03
-
-
Save ufologist/e7eea01c876f9b4a8d3322319a36fed3 to your computer and use it in GitHub Desktop.
Mask unfold css animation 蒙板展开动画
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Mask unfold css animation</title> | |
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> | |
<style> | |
body { | |
background-color: #ccc; | |
} | |
.mask-example button { | |
height: 44px; | |
width: 44px; | |
/*-webkit-appearance: none;*/ /* 去掉 iOS button 默认圆角样式 */ | |
} | |
</style> | |
<script> | |
function setAnimation(el, keyframesName) { | |
el.style.webkitAnimation = ''; | |
el.style.animation = ''; | |
// 强制 reflow | |
el.clientWidth; | |
el.style.webkitAnimation = keyframesName + ' 1s forwards'; | |
el.style.animation = keyframesName + ' 1s forwards'; | |
} | |
</script> | |
</head> | |
<body> | |
<h1>Mask unfold css animation</h1> | |
<p><a href="https://www.douban.com/note/548583429/" target="_blank">蒙板展开动画</a>, 效果类似有一层蒙板遮盖着内容, 随着蒙板的水平或垂直移动, 内容部分一点点出现, 一般可以从 4 个方向展开</p> | |
<ul> | |
<li>从左到右</li> | |
<li>从右到左</li> | |
<li>从上到下</li> | |
<li>从下到上</li> | |
</ul> | |
<p>以下是多种实现方式</p> | |
<ul class="mask-example"> | |
<li style="height:350px"> | |
<h2>展开 width/height</h2> | |
<p>推荐指数: ★★★</p> | |
<p>实现简单, 但只能从左到右/从上到下, 而且必须确定宽高值, 如果不固定容器的高度, 会有副作用(界面会出现挤压)</p> | |
<style> | |
.mask--width-height { | |
overflow: hidden; | |
} | |
@-webkit-keyframes left2RightByWidth { | |
0% { width: 0; } | |
100% { width: 160px; } /* 必须定宽 */ | |
} | |
@-webkit-keyframes top2BottomByHeight { | |
0% { height: 0; } | |
100% { height: 120px; } /* 必须定高 */ | |
} | |
</style> | |
<div> | |
<button class="js-left2RightByWidth" title="从左到右">→</button> | |
<button class="js-top2BottomByHeight" title="从上到下">↓</button> | |
</div> | |
<hr> | |
<div class="mask--width-height"> | |
<img src="https://img3.doubanio.com/icon/ul5310023-1.jpg" width="160" height="120" alt=""> | |
</div> | |
<script> | |
document.querySelector('.js-left2RightByWidth').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--width-height'), 'left2RightByWidth'); | |
}, false); | |
document.querySelector('.js-top2BottomByHeight').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--width-height'), 'top2BottomByHeight'); | |
}, false); | |
</script> | |
</li> | |
<li> | |
<h2><a href="http://bennettfeely.com/clippy/" target="_blank">clip-path</a> 裁剪</h2> | |
<p>推荐指数: ★★★★</p> | |
<p><a href="http://caniuse.com/#feat=css-clip-path" target="_blank">兼容性不高</a>: iOS 7+, Android 4.4+, 但实现简单灵活不需要确定宽高值</p> | |
<style> | |
.mask--clip-path { | |
display: inline-block; | |
} | |
@-webkit-keyframes left2RightByClipPath { | |
/* keyframes 不支持 inset 动画帧 */ | |
/* 例如: inset(0 100% 0 0) -> inset(0 0% 0 0) */ | |
0% { -webkit-clip-path: polygon(0 0, 0 0, 0 100%, 0 100%); } | |
/* | | */ | |
100% { -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } | |
} | |
@-webkit-keyframes right2LeftByClipPath { | |
0% { -webkit-clip-path: polygon(100% 0, 100% 0, 100% 100%, 100% 100%); } | |
/* | | */ | |
100% { -webkit-clip-path: polygon( 0 0, 100% 0, 100% 100%, 0 100%); } | |
} | |
@-webkit-keyframes top2BottomByClipPath { | |
0% { -webkit-clip-path: polygon(0 0, 100% 0, 100% 0, 0 0); } | |
/* | | */ | |
100% { -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } | |
} | |
@-webkit-keyframes bottom2TopByClipPath { | |
0% { -webkit-clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%); } | |
/* | | */ | |
100% { -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } | |
} | |
</style> | |
<div> | |
<button class="js-left2RightByClipPath" title="从左到右">→</button> | |
<button class="js-right2LeftByClipPath" title="从右到左">←</button> | |
<button class="js-top2BottomByClipPath" title="从上到下">↓</button> | |
<button class="js-bottom2TopByClipPath" title="从下到上">↑</button> | |
</div> | |
<hr> | |
<div class="mask--clip-path"> | |
<img src="https://img3.doubanio.com/icon/ul5310023-1.jpg" width="160" height="120" alt=""> | |
</div> | |
<script> | |
document.querySelector('.js-left2RightByClipPath').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip-path'), 'left2RightByClipPath'); | |
}, false); | |
document.querySelector('.js-right2LeftByClipPath').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip-path'), 'right2LeftByClipPath'); | |
}, false); | |
document.querySelector('.js-top2BottomByClipPath').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip-path'), 'top2BottomByClipPath'); | |
}, false); | |
document.querySelector('.js-bottom2TopByClipPath').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip-path'), 'bottom2TopByClipPath'); | |
}, false); | |
</script> | |
</li> | |
<li style="height:350px"> | |
<h2><a href="http://www.w3cplus.com/css3/clip.html" target="_blank">clip</a> 裁剪</h2> | |
<p>推荐指数: ★★★</p> | |
<p>实现简单, 但必须确定宽高值, 而且必须 position: absolute/fixed</p> | |
<style> | |
.mask--clip { | |
position: absolute; /* clip 只对 absolute/fixed 元素有效 */ | |
/* XXX 在 iOS/Android 上测试时均发现必须先设置一个 clip 初始值 keyframes 动画才能生效, 这是要激活吗? */ | |
clip: rect(0,auto,auto,0); | |
} | |
@-webkit-keyframes left2RightByClip { | |
0% { clip: rect(auto, 0, auto, auto); } | |
100% { clip: rect(auto, 160px, auto, auto); } | |
} | |
@-webkit-keyframes right2LeftByClip { | |
0% { clip: rect(auto, auto, auto, 160px); } | |
100% { clip: rect(auto, auto, auto, 0); } | |
} | |
@-webkit-keyframes top2BottomByClip { | |
0% { clip: rect(auto, auto, 0, auto); } | |
100% { clip: rect(auto, auto, 120px, auto); } | |
} | |
@-webkit-keyframes bottom2TopByClip { | |
0% { clip: rect(120px, auto, auto, auto); } | |
100% { clip: rect( 0, auto, auto, auto); } | |
} | |
</style> | |
<div> | |
<button class="js-left2RightClipByClip" title="从左到右">→</button> | |
<button class="js-right2LeftClipByClip" title="从右到左">←</button> | |
<button class="js-top2BottomClipByClip" title="从上到下">↓</button> | |
<button class="js-bottom2TopClipByClip" title="从下到上">↑</button> | |
</div> | |
<hr> | |
<div class="mask--clip"> | |
<img src="https://img3.doubanio.com/icon/ul5310023-1.jpg" width="160" height="120" alt=""> | |
</div> | |
<script> | |
document.querySelector('.js-left2RightClipByClip').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip'), 'left2RightByClip'); | |
}, false); | |
document.querySelector('.js-right2LeftClipByClip').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip'), 'right2LeftByClip'); | |
}, false); | |
document.querySelector('.js-top2BottomClipByClip').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip'), 'top2BottomByClip'); | |
}, false); | |
document.querySelector('.js-bottom2TopClipByClip').addEventListener('click', function() { | |
setAnimation(document.querySelector('.mask--clip'), 'bottom2TopByClip'); | |
}, false); | |
</script> | |
</li> | |
<li> | |
<h2>真蒙板 - 移动(伪)元素</h2> | |
<p>推荐指数: ★★</p> | |
<p>简单粗暴, 但蒙板元素需要填充颜色和背景色配合才能达到效果, 灵活度大打折扣</p> | |
<p><strong>注意: <a href="http://bbs.mb.qq.com/thread-1119829-1-1.html" target="_blank">Android 微信内置浏览器不支持伪元素动画</a></strong></p> | |
<style> | |
.mask--pseudo-element { | |
position: relative; | |
display: inline-block; | |
overflow: hidden; | |
} | |
.mask--pseudo-element img { | |
vertical-align: bottom; /* 去除图片间隙 */ | |
} | |
.mask--pseudo-element::after { | |
content: " "; | |
position: absolute; | |
top: 0; | |
left: 0; | |
display: none; | |
width: 100%; | |
height: 100%; | |
background-color: #fff; | |
/*background-color: #ccc;*/ /* 需要和背景色一样, 否则就会很突兀 */ | |
} | |
.mask--pseudo-element.left2right::after { | |
display: block; | |
-webkit-animation: left2RightByPseudoElement 1s forwards; | |
} | |
.mask--pseudo-element.right2left::after { | |
display: block; | |
-webkit-animation: right2LeftByPseudoElement 1s forwards; | |
} | |
.mask--pseudo-element.top2bottom::after { | |
display: block; | |
-webkit-animation: top2BottomByPseudoElement 1s forwards; | |
} | |
.mask--pseudo-element.bottom2top::after { | |
display: block; | |
-webkit-animation: bottom2TopByPseudoElement 1s forwards; | |
} | |
@-webkit-keyframes left2RightByPseudoElement { | |
0% { -webkit-transform: translateX(0%); } | |
100% { -webkit-transform: translateX(100%); } | |
} | |
@-webkit-keyframes right2LeftByPseudoElement { | |
0% { -webkit-transform: translateX(0%); } | |
100% { -webkit-transform: translateX(-100%); } | |
} | |
@-webkit-keyframes top2BottomByPseudoElement { | |
0% { -webkit-transform: translateY(0%); } | |
100% { -webkit-transform: translateY(100%); } | |
} | |
@-webkit-keyframes bottom2TopByPseudoElement { | |
0% { -webkit-transform: translateY(0%); } | |
100% { -webkit-transform: translateY(-100%); } | |
} | |
</style> | |
<div> | |
<button class="js-left2RightByPseudoElement" title="从左到右">→</button> | |
<button class="js-right2LeftByPseudoElement" title="从右到左">←</button> | |
<button class="js-top2BottomByPseudoElement" title="从上到下">↓</button> | |
<button class="js-bottom2TopByPseudoElement" title="从下到上">↑</button> | |
</div> | |
<hr> | |
<div class="mask--pseudo-element"> | |
<img src="https://img3.doubanio.com/icon/ul5310023-1.jpg" width="160" height="120" alt=""> | |
</div> | |
<script> | |
function setPseudoElementMaskClass(className) { | |
// Modify pseudo element styles with JavaScript | |
// https://pankajparashar.com/posts/modify-pseudo-elements-css/ | |
var el = document.querySelector('.mask--pseudo-element'); | |
el.classList.remove('left2right'); | |
el.classList.remove('right2left'); | |
el.classList.remove('top2bottom'); | |
el.classList.remove('bottom2top'); | |
el.clientWidth; | |
el.classList.add(className); | |
} | |
document.querySelector('.js-left2RightByPseudoElement').addEventListener('click', function() { | |
setPseudoElementMaskClass('left2right'); | |
}, false); | |
document.querySelector('.js-right2LeftByPseudoElement').addEventListener('click', function() { | |
setPseudoElementMaskClass('right2left'); | |
}, false); | |
document.querySelector('.js-top2BottomByPseudoElement').addEventListener('click', function() { | |
setPseudoElementMaskClass('top2bottom'); | |
}, false); | |
document.querySelector('.js-bottom2TopByPseudoElement').addEventListener('click', function() { | |
setPseudoElementMaskClass('bottom2top'); | |
}, false); | |
</script> | |
</li> | |
</ul> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment