这篇文章发布于 2012年10月19日,星期五,15:54,归类于 Web综合。 阅读 145333 次, 今日 4 次 30 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=2717
一、这是个平淡的开头
在web页面上,类似于“展开更多”、“显示全部”这类显隐效果,就跟大上海的私家车一样,随处可见。随便Open两个页面,就可见到影分身:
一般而言,且平心而论,这类交互效果应当就是这样子的——“唐突的显隐交互”,即内容“啪”一下子呈现或隐藏。
简洁明快,快速消费,且性能不错,实现以及后期维护成本也很低;对于功能性,多交互的商业站点而言,诸多权衡,确实是不错的选择。不过,类似广告宣传的展示性网站,更注重炫酷效果,唐突以及生硬的效果显然是接受不了的。
还有可能接受不了的是年轻气盛的交互设计师——其可能无法忍受一段内容唐突地出现在用户面前——而不是slideDown这类柔和的动画形式——因为前者可能会让用户觉得不舒服,体验不够好。
我突然想到了网上常常会出现的一句话:强奸着强奸着,也就习惯了~~
想到这句话,说明自己也矛盾,或者说自己还没有想明白:整站流畅交互固然不错,就像Apple的产品一样,会有非常不错的体验。但是,实际上,自己内心真正想法是:如果网站交互都带有动画性质,反而很不好;即使将实现以及性能等因素撇开不谈,也是不合适的;因为,网站可能需要自己的气质,过多的效果可能会显得浮躁~~
这种感觉就像是:一个中国妹子,全身上下都是扎眼的高档装饰品,不见得好看(Apple这样的名媛或贵妇另当别论);反而只有头上插了朵小花,更好看。所谓画龙点睛,1~2处惊艳即可,如果龙身上画满了眼睛——我勒个去,密集恐惧~~
听说有个“二八法则”的,如果应用在显隐toggle交互上,8分“啪”显隐,2分“呼”显隐??——我不确定,你怎么看呢?
二、“更多|收起”喜欢的动画
虽然,web世界中,交互动画效果N多多,但是,很多都是约定俗成的,或者称之为“有固定套路的”。
根据David Kaneda创建的Transitions动画CSS代码,我们可以将效果归结为这几大类:slide(滑来滑去), fade(淡入淡出), flip(飞来飞去), pop(大大小小).
如居中弹框呈现与隐藏,适合pop效果;绝对定位浮动层(如智能提示下拉框,自定义时间选择控件)等的呈现与隐藏使用fade效果;幻灯片播放的广告位效果一般为slide效果;点击某商品飞入页面右下角或左上角的购物车就是flip效果(类似最新FireFox浏览器关闭标签页效果)。
而对于页面上,“展开更多|收起更多”这类交互,由于元素默认隐藏,且显示内容就在点击区域附近,因此,想要避免唐突,适合的效果只能是从无到有慢慢“滑出来”-也就是slide效果。
正统的slide效果与伪slide效果
熟知jQuery的人应该都知道,其效果API中有slideDown()
, slideUp()
, slideToggle()
的动画效果API. 那这几个方法是正统的slide效果呢还是伪slide效果?
答案是:伪slide效果!
正统的slide效果,应该是元素整体位置的移动,如这个demo所示的效果,您可以狠狠地点击这里:正统slide效果演示demo
而jQuery slideDown()
/slideUp()
效果中,元素本身并没有移动,类似这个demo所示效果:伪slide效果演示demo
在我们实际制作页面的时候,采用的都是“伪slide效果”,为何?
因为更低的成本!归根结底是因为:一般的元素(都是非定位元素)是从上往下一次排下来的。因此,通过控制height
来实现slide效果的时候,都是元素的上半部分先显示。正统的slide效果的实现需要将动画呈现元素改成定位元素(应用position:absolute/fixed/…),这显然只适用于某些特殊的情况……
因此,作为API, 插件或公共方法,所实现的slide效果都是“伪slide效果”。
三、jQuery中滑动API
实现的原理
一图胜前言,下图为slideDown效果进行中的时候,对动画元素HTML代码的截图:
因此,可以知道,jQuery的slide效果是同时变更元素的height
/margin-top
/margin-bottom
/padding-top
/padding-bottom
/ + 设置overflow:hidden
值实现的。
注意:没有同时变更border-top
/border-bottom
的宽度值,因此,如果元素的边框较大,slide效果在结束的瞬间会有顿一下的感觉。在jQuery1.6版本中,宽边框元素无论是slideDown
效果还是slideUp
效果,在动画要结束的时候,都会有明显的顿感;在jQuery1.8版本中,slideDown
效果从头到尾都算流程;但是slideUp
效果结束时候有顿感。
您可以狠狠地点击这里:jQuery1.6以及jQuery1.8版本slide效果对比demo
应用局限
个人观点,jQuery中的slide滑动效果,看上去还那么回事,实际上,是个鸡肋API.
1. 依赖jQuery库。jQuery库本身越来越庞大,比方说jQuery1.8 gzip后居然还有30多K,个人觉得相当大,也相当笨重了。实际上,对于实际项目,选择器没有必要那么强大,有一半的API可以阉割掉,gzip后8~9K足矣,下图我最近某项目使用jQuery文件:
2. 效果本身不是很完美。如上面演示的,边框元素顿感,以及IE6/IE7浏览器下直接显示bug.
3. 性能问题。如果页面复杂,本身交互比较多。对于IE6这类浏览器,如此动画效果,必定会有卡、顿的感觉;甚至会浏览器扛不住直接崩掉。因此,在实际项目的时候,slide动画使用并不多。尤其对于“更多|收起”交互,因为切换元素都不是绝对定位元素,因此,强烈的重绘会让CPU激动不已!
4. 过分兼容。我觉得,就算应用slide效果,最好IE6~7下直接“唐突显示”,其他现代浏览器浏览器则动画什么的。什么样车有什么样的的马力,什么样的马力跑什么样的速度!……
因此,如果我们非得应用一些slide交互效果,我们可以需求其他更简单,更方便,更灵活的方法。例如,借助CSS3中的transition, 渐进实现一些动画效果。
五、transition实现 – 真的很简单
拿上面出现的“正统slide效果页面”同样效果举例,您可以狠狠地点击这里:transition实现正统slide效果demo
上demo IE10+, 最近版本的FireFox, Chrome, Opera浏览器都可以看到非常流畅的slide动画效果。
相比之前模拟动画demo,这里多了这么行CSS代码:
.container { transition: height 0.6s; }
然后,JS代码就基本上全部消灭了,只留下改变高度的几行代码:
var display = false;
button.onclick = function() {
display = !display;
container.style.height = display? "192px": "0px"
return false;
};
})();
简单,真好!我突然诗兴大发:“脱裤子般简单,拉大便般舒畅;啊!真好,真好!”
众人:“好诗!好诗!!”
六、transition实现的公共方法
在展示transition slide公共方法前,有必要讲下CSS3 transition
动画效果出现的条件:
- 动画属性前后不同值必须含数值,例如
height:0
→height: auto
是没有动画效果的 - 不能属性值的应用前后必须有时间差,例如:
element.style.height = "0px"; element.style.height = "100px";
虽然这里元素高度设置了
0
, 也设置了100
像素。但是,由于浏览器的性能机制,只会直接渲染后面100像素高度,因此,是不会出现动画效果的!
因此,考虑到在实际的交互中,显示元素的高度是不可能都已知的,我们要实现transition的公共方法的最难点,就是得到展开元素的精确高度值(height:auto是不会有动画效果的)。
本着简单,人人可以上手的指导思想,我们需要一些约定,关于CSS以及HTML结构的。
HTML结构:
container box list list
其中container以下CSS是必不可少的(如果内部子元素没有绝对定位元素,position:relative
可以省略),就是下面这样(私有前缀这里省掉了):
.container { height: 0; position: relative; overflow: hidden; transition: height 0.6s; }
其中,动画时间你自己控制,你还可以增加缓动类型,例如ease
:
.container { transition: height 0.3s ease; }
对于HTML结构,只有唯一一个要求,就是container的子元素只有一个(方便高度的获取,多子元素,高度计算麻烦多了)。
例如:
<div class="container"> <p>我是孤独的根号3...</p> </div>
或者:
<div class="container"> <ul> <li>列表1</li> <li>列表2</li> </ul> </div>
准备工作完毕,下面就是方法了(IE6~8浏览器直接设置height:auto
即可):
var slideToggleTrans = function(element, display) { // display表示默认更多展开元素是显示状态还是隐藏 if (typeof window.screenX === "number") { // 现代浏览器 element.addEventListener("click", function() { display = !display; var rel = this.getAttribute("data-rel"), eleMore = document.querySelector("#" + rel); eleMore && (eleMore.style.height = display? (function() { var height = 0; Array.prototype.slice.call(eleMore.childNodes).forEach(function(child) { if (child.nodeType === 1) { var oStyle = window.getComputedStyle(child); height = child.clientHeight + (parseInt(oStyle.borderTopWidth) || 0) + (parseInt(oStyle.borderBottomWidth) || 0); } }); return height; })() + "px": "0px"); }); } else { // IE6-IE8浏览器 element.attachEvent("onclick", function() { display = !display; var rel = element.getAttribute("data-rel"), eleMore = document.getElementById(rel); eleMore && (eleMore.style.height = display? "auto": "0px"); return false; }); } };
触发按钮,以及对应的显示隐藏元素,通过按钮元素上面自定义的”data-rel
“属性相关联。
您可以狠狠地点击这里:渐进使用transition的显隐公共方法demo
不支持transition的直接“啪啪”显示,支持transition的“呼呼”显示。渐进增强,简单又高性能。
需要额外说明的
- 以上公共的
slideToggleTrans
方法如果直接用在实际项目中,是有所欠缺的。缺在哪里呢?就是没有添加回调。因此,您可能需要添加一个额外的参数以及两行代码:var slideToggleTrans = function(element, display, callback) { // click事件中: ...; callback.call(element, eleMore, display); }
- 我们平时显隐更多地是通过
display
属性控制。然而,display
无法触发transition动画。如果我们先设置display:block
,再去改变高度,行也行。但是,这种感觉就像是:平时用地下水冲马桶的,后来自来水也能冲干净,但非要再用地下水冲一次。而且,在脚本的编写上,更折腾(display:none
的元素无法获取子元素的真实高度)。
还是那句话,为了让一切都显得那么简单,我们要稍微改变下习惯,学习使用height
控制元素的显隐。 - 以上公共方法不依赖任何JavaScript库。我这里想说的不是称赞其灵活性,而是想说,我们平时开发,都应该有自己的JS框架的。因此,上述代码有必要在自己框架基础上进行一番整改,可以大大简单代码;同时提高参数的可定制性(data-rel, 回调等);以及其他相关扩展——如ajax更多加载的动画显示等!
这里的,仅仅是最简单原始的,抛砖引玉而已。 - 定高其实是件伴随风险的事情,因为会有这样的情况:1. 页面内容宽度自适应,窄屏下元素应该更高;2. 更多元素内部还有类似展开收起的交互,高度可变。
因此,我们还需要额外处理。情况1,需要在动画结束的时候,设置height: auto; 情况2则是,内部再出现2次交互的时候,再次改动元素的高度值(自动触发动画)。
七、这是一个平淡的结语
我脑中突然冒出两个名字:“社会框架”和“团队框架”。“社会框架”就像我们使用的完整版的jQuery,因为其要兼容千万开发者受众各种环境,各种使用情况,因此,变得庞大是在所难免的。但是,如果放在单一的团队的,很多很多的东西都是多余的。因为,团队中可以有一个名叫“规范”的东西进行约束。——比方说,这种UI交互,我们的HTML结构上需要注意什么,需要什么样的CSS配合就可以使用极简的JS代码实现我们想要的效果等等。
说点更实际的,本文的内容,如果要让我写一个面向万千使用者的transition动画插件,我需要考虑的就非常多:
1. 有的用户喜欢默认设置display:none
, 以及其他CSS属性(例如其对容器设置了会冲突的overflow:auto);
2. 显隐元素里面就是文本,或者是列表子节点们。我需要获取各种情况下子元素们的高度。这很头疼;
3. 交互场景千千万。显隐元素内部还有其他域高度打交道的交互,我该如何处理;
4. 等等其他N多……
要全部兼顾上面的问题,可以想象,我的JS代码不是几十行就可以搞定了。肯定会有很多与核心逻辑不相干的代码,去处理这些个特殊情况。于是,洋洋洒洒N多代码,这是我很不喜欢的,大家也一定不会喜欢的。
但是,如果code只是面向一个规范的团队,或是自己内部小组,OK,我们就可以通过一些约定俗成,大大简化我们的代码,我们的开发,最后是大家都开心!
我越来越不喜欢过于肥胖的jQuery了!
本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=2717
(本篇完)
- 酷酷的jQuery鼠标悬停图片放大切换显示效果 (0.781)
- 内容loading加载后高度变化CSS3 transition体验优化 (0.219)
- css行高line-height的一些深入理解及应用 (0.156)
- CSS float浮动的深入研究、详解及拓展(一) (0.156)
- 纯CSS实现侧边栏/分栏高度自动相等 (0.156)
- CSSOM视图模式(CSSOM View Module)相关整理 (0.156)
- CSS中height:100%和height:inherit的异同 (0.156)
- HTML textarea cols,rows属性和宽度高度关系研究 (0.156)
- canvas HTML属性尺寸和CSS尺寸多个细节深入 (0.156)
- Chrome 88已经支持aspect-ratio属性了,学起来 (0.156)
- 小tip:CSS3下的圆形遮罩效果实现与应用 (RANDOM - 0.063)
旭哥,以案例一为例,在图片加上一个padding,则展开收齐的时候会显示一个padding的图片高度,如何解决这个问题
不能属性值的应用前后必须有时间差,例如:
第六节,transition的实现方法下面“不能属性值的应用前后必须有时间差,例如:”
是不同吧,鑫哥
请问,如何做到内容不从上面推下来?希望能像 Apple.com 那样的:
http://www.apple.com/cn/shop/buy-iphone/special-edition-iphone-7
底部的「常见问题解答」展开后的小问题,继续点击,则可以看到效果~
把上面例子的 buttom: 0; 去掉就行了
请教 eleMore && (eleMore.style.height = display? “auto”: “0px”); 这段代码中&&是什么用法
if的用法
博主为毛什么例子都用这美女的图片…….换海绵宝宝多好
楼主的梦中情人
css3动画确实流畅,就是要算高度啊啊啊啊。。。。。不知道楼主有没有分析jquery的slidedown的源代码的文章,了解到jq算高度的方法就好了
bootstrap 里面的实现 就是你所说的 鸡肋,他使用动画事件来监控,让我觉得很不爽。这个高度问题 的确很扯,你这12年的文章。我现在才遇到你当时的问题。不过你的职业和我的爱好都一样不得不说是缘分。 大哥你真够超前
不过楼主的算子元素高度的方法 的确也不是很优雅啊
楼主,我想到另一个方法:
先设置display:block,延迟10ms左右再改变“透明度”。
这样不知可否?不用计算高度,js估计也会少一点吧?(个人不是很懂js。。。)求评价!跪谢~
@Cc 这种实现动画效果就显得很鸡肋。
slide 在iPad上反应很慢,明显很卡,请问有好的解决方法吗
@杨勇 1. 绝对定位 2. 浅dom 3. 独立少关联 4. 去除半透明以及盒阴影等渲染,纯色底纹。
注:iPad不是杂牌国产pad,速度可以的。
query确实是越来越庞大了。如果要分析源码还是推荐zepto.js。 并且slide在ie下表现非常糟糕。
楼主好是好,可是太多字鸟……看得俺的眼……
想知道在IE6 图片不显示的bug 楼主是怎么解决的。。我也遇到这个。怎么改都不显示。。拷贝楼主的链接进IE6又是好的。 又全拷贝楼主代码 发现还是不显示。。
楼主 可以不可以也多分享下你的学习javascript 啊 你现在分享的CSS 也很全面和详细 哈
ie6 有BUG 图片显示不出来。其他浏览器完美哈!
@java_ljy 多谢提醒,问题已经修复。
当单位不一致的话,貌似也不会有动画,例如height:40px → height: 80%,博主共享下阉割掉的jQuery吧,学习下。
博主那首诗真的很不错,好诗!好诗!
博主研究的真深刻,我只遇到过jquery silide的滑入划出效果确实有停顿,确没有究其根源,博主的精神值得我学习呀,
敢问帮主 有研究过css3的图片滚动么 就是淘宝网的触屏版的图片滚动 期待此问题的博文
because 我们有时希望用半透明效果, display 是必须的啦 – 否则它透明了也点不到底下的东西。。。
相当好的~ IE 10 支持不带有前缀的 transition 效果超赞。。。另外最近 Firefox 也支持不带有前缀的 transition 版本了~
最近css3好多啊 不过我最近也研究css3,还挺有收获的,
版主什么时候讲讲原生的js些框架之类的话题
挺了
如果页面有多个需要更多收起,怎么办?
@牛逼的博主 例如:$(“.element”).forEach(function(ele) {
slideToggleTrans(ele);
});