前言
常用的搜索图标是一个放大镜,不需要任何文字描述,人们就知道点击它进行搜索。很久之前看到一个奇妙的搜索图标,点击之后放大镜的圈会展开成为一个搜索框,而放大镜的柄会变成一个叉,点击之后就可以整个再折叠回去。当初看到的时候感到很有趣,前不久又想起来,决定复刻一下
示例
实现
思路是用伪元素充当放大镜的柄,但可惜的是,
<input type="text">
并不支持伪元素(因为它没有内容物),因此只能再用一个<div></div>
包起来<div id="searchbox"> <input type="text" placeholder="Type to search" autocomplete="off"> </div>
先来给
<input>
加上展开的效果:触发:focus
后,直接用padding
把圈撑大,再让width
增加
在transition
中设置延时(第三个参数),如果在原处和伪类处设置不同的transition
,那么会由于覆盖导致正向和反向时有不同的效果记得设置
outline: none
,不然点击后有外框#searchbox>input{ width: 1.2rem; height: 1.2rem; position: absolute; top: 0; right: 0; box-sizing: border-box; outline: none; padding: .6rem; border: .2rem solid skyblue; border-radius: 2rem; background: transparent; transition: width .3s, padding .1s .4s; } #searchbox>input:focus{ width: 20rem; padding: 1rem; background: whitesmoke; transition: width .3s .2s, padding .1s; }
然后考虑放大镜的柄,分别用
<div>
的两个伪元素实现(定位需要仔细找一下)
由于伪元素在父元素上,<input>
的:focus
不能触发它,所以我们使用:focus-within
伪类,它可以被focus事件的冒泡触发记得设置
z-index
,不然会被<input>
遮住#searchbox::before, #searchbox::after{ content: ''; width: .9rem; height: .1rem; position: absolute; right: -.4rem; top: 1.1rem; background-color: skyblue; transform: rotate(45deg); z-index: 1; transition: top .1s .4s, right .1s .4s, transform .1s .2s; } #searchbox:focus-within::before, #searchbox:focus-within::after{ top: .75rem; right: .75rem; transition: right .1s, top .1s, transform .2s .2s cubic-bezier(.18,.89,1,1.42); } #searchbox:focus-within::after{ transform: rotate(135deg); }
为了更好的用户体验,我们将两个伪类的可点击范围扩大一点。可以用
border
拓宽,不过需要特别设置一下background-clip: padding-box
,不然border
上也会有背景颜色#searchbox::before, #searchbox::after{ border-top: .4rem solid transparent; border-bottom: .4rem solid transparent; background-clip: padding-box; }
现在来分析一下效果:
- 当点击放大镜时,分别触发
<input>
的:focus
和伪元素的:focus-within
,导致放大镜展开为搜索框,并且柄变成一个叉 - 再点击叉或者页面其他位置,都会导致
<input>
失去:focus
状态(因为点击伪元素是算在父元素上的),于是整体回到放大镜状态
- 当点击放大镜时,分别触发
最后,当然你还是要用
js
给<input>
绑上事件。按下回车开始搜索(回车的keyCode
是13
)document.querySelector('#searchbox>input').addEventListener('keydown', function(e){ if(e.keyCode == 13){ } });
Orz