Skip to content

Instantly share code, notes, and snippets.

@ufologist
Created March 31, 2016 12:03
Show Gist options
  • Save ufologist/e7eea01c876f9b4a8d3322319a36fed3 to your computer and use it in GitHub Desktop.
Save ufologist/e7eea01c876f9b4a8d3322319a36fed3 to your computer and use it in GitHub Desktop.
Mask unfold css animation 蒙板展开动画
<!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