咱们今天用css来实现一个常见的tab切换效果css
查看原文能够有更好的排版效果哦html
先看效果前端
https://codepen.io/xboxyan/pe...react
哪些简单的效果能够考虑用css来实现呢,目前css可以作的交互有jquery
hover
:cheked
那是否是上述全部的交互均可以用css来实现呢?显然不是的,css实现依赖于html结构,由于css选择器有限,有子选择器,没有父选择器,有后选择器,没有前选择器,因此局限性很大。因此当咱们思考可否用css来实现时还应考虑到html的结构,能不能构造出知足css已存在的选择器的html布局。css3
通常在碰到tab类型的组件时,通常会有以下的html浏览器
<div class="tabs"> <div class="tab-nav"> <div class="tab-item">tab01</div> <div class="tab-item">tab02</div> <div class="tab-item">tab03</div> </div> <div class="tab-content"> <div>111</div> <div>222</div> <div>333</div> </div> </div>
大体就是这种布局吧,暂且称做分离模式吧,足够灵活,就是导航部分和内容结构分开,须要什么动画效果均可以分别实现。组件化
还有一种布局,大概是这样的布局
<div class="tabs"> <div class="tab-pane"> <div class="tab-item">tab01</div> <div class="tab-content">111</div> </div> <div class="tab-pane"> <div class="tab-item">tab01</div> <div class="tab-content">111</div> </div> <div class="tab-pane"> <div class="tab-item">tab01</div> <div class="tab-content">111</div> </div> </div>
这里每个tab里面的导航和内容是一块儿的,咱们称为合并模式吧,这种在组件化里面很常见,好比在react
里面,一个tab组件
,通常会写成这样动画
ReactDOM.render( <Tabs defaultActiveKey="1" onChange={callback}> <TabPane tab="Tab 1" key="1">Content of Tab Pane 1</TabPane> <TabPane tab="Tab 2" key="2">Content of Tab Pane 2</TabPane> <TabPane tab="Tab 3" key="3">Content of Tab Pane 3</TabPane> </Tabs>, mountNode);
是否是很像?
相信用js只要是一名合格的前端都能轻易的实现吧,这里咱们主要是研究如何用css来实现
这里有两种思路
herf
+ :target
nth-child(n)
选择器锚点实现主要是在a
标签加上href
属性,而后目标元素上添加相同的id
,当点击a
标签时,目标元素的:target
就生效了
<style> #item01:target{ background:red } </style> <a href="#item01">跳转</a> <div id="item01">内容</div>
这种方式能够将导航和内容连接到一块,可是在浏览器中有一个很不友好的地方,就是当点击带有锚点的a
连接的时候,浏览器会自动定位到目标位置,很影响体验,须要去掉这种效果估计还得借助js来实现,故不太推荐用这种方式
nth-child(n)
选择器,这种方式就比较传统了,不过导航切换部分仍是用到label
+input[type=radio]
,实现基本和js是同一个思路,甚至还不如js方便,由于你有多少个tab选项就得写多少个nth-child
样式
.tab-nav input:nth-of-type(1):checked ~ .tab-content :nth-of-type(1), .tab-nav input:nth-of-type(2):checked ~ .tab-content :nth-of-type(2), .tab-nav input:nth-of-type(3):checked ~ .tab-content :nth-of-type(3), ... { z-index:1 }
你大概会看到这样的样式,若是选项卡比较固定,基本是静态的,比较少,能够一一写出来,若是比较多,或者是js生成的,那么建议这一部分样式也经过js生成出来。
下面着重来实现第二种布局
若是是这样一种布局,那么导航和内容就能够经过相邻选择器+
联系上了,重点是如何实现选项卡的样式,固然,咱们也须要改一下html
<div class="tabs"> <div class="tab-pane"> <input type="radio" name="tab" id="tab01"/> <label class="tab-item" for="tab01">tab01</label> <div class="tab-content">111</div> </div> <div class="tab-pane"> <input type="radio" name="tab" id="tab02"/> <label class="tab-item" for="tab02">tab02</label> <div class="tab-content">222</div> </div> <div class="tab-pane"> <input type="radio" name="tab" id="tab03"/> <label class="tab-item" for="tab03">tab03</label> <div class="tab-content">333</div> </div> </div>
而后咱们经过样式美化一下
.tabs{ position:relative; width:400px; height:300px; } .tab-pane{ display:inline-block; } .tabs input[type='radio']{ position:absolute; clip:rect(0,0,0,0) } .tab-item{ display:block; height:34px; line-height:34px; cursor:pointer; padding:0 10px } .tab-content{ position:absolute; border:1px solid #eee; padding:20px; left:0; top:36px; bottom:0; right:0; background:#fff; }
而后加入交互,主要就是相邻选择器+
和:checked
选择器,
.tabs input[type='radio']:checked+.tab-item{/**导航选中状态**/ background:orangered; color:#fff } .tabs input[type='radio']:checked+.tab-item+.tab-content{/**当前内容切换**/ z-index:1 }
咱们这里只用了z-index:1
就实现了隐藏显示,固然还能够实现更多的效果,好比淡入淡出等
下面是演示效果
https://codepen.io/xboxyan/pe...
固然,这种方式也有必定的不足,因为这里内容区域用到了绝对定位,因此整个tab容器就不能根据里层的内容来自适应,也须要给外层一个固定的高度,否则整个tab容器就只有顶部导航区域才占据空间,这明显就不合常理。
/**给导航添加横条的缩放效果**/ .tab-item:after{ position:absolute; content:''; height:3px; width:100%; background:orangered; left:0; bottom:2px; transition:.3s; transform:scaleX(0) } .tabs input[type='radio']:checked+.tab-item:after{ transform:scaleX(1) } /**给内容区域添加一个淡入淡出的效果**/ .tab-content{ position:absolute; background:#eee; padding:20px; left:0; top:36px; bottom:0; right:0; transition:.3s; opacity:0; transform:translateY(50px) } .tabs input[type='radio']:checked+.tab-item+.tab-content{ z-index:1; opacity:1; transform:translateY(0) }
https://codepen.io/xboxyan/pe...
经过css咱们也能实现导航效果,并且更容易复用,只须要复制html结构就行(固然这里确定也是须要改一下name
和id
的)。这就有点相似组件的意思了,给你一个html结构,你不须要关系切换逻辑,只须要根据接口取到数据,而后塞到每一个tab标签页里面去,事实上如今react
实现的组件也通常都是这种思路,只需关注业务逻辑,但这些都是大工程,哪里有css直接来的快。
这就让我想到了刚进公司那会,每碰到一个tab,那就要取一个id
,而后用jquery
实现一遍tab切换逻辑,后来放聪明了,把tab封装成一个插件,碰到一个tab就调用一次插件...看着代码变少了,其实也没什么本质区别。
用css来实现的好处就是能够尽可能大的把组件功能和业务逻辑分离开来,真正作一个UI组件
该作的事,但愿css愈来愈好