Amazing Css:自定义下划线样式的Input
Amazing Css:自定义下划线样式的Input
这篇文章将通过CSS的方式实现一个常见的Input样式,包括一些VUE的Tips
效果
相比于传统的方框Input同款样式,下划线的input输入框占用版面更小,视觉效果比较灵活,通常可以使表单面板更加整洁。写这样一个输入框的组件只需要一些CSS和少量的JS就可以完成。
第一步思考:border
对于带下划线的东西,可能最容易想到的就是border这个属性了。border属性的确可以在一定程度上完成这个需求,只需要把传统Input的边框去掉,然后将底部的border加上颜色和宽度就可以完成。
尝试给input添加如下样式,去掉原本的边框,然后给border-bottom加一个颜色和宽度。
<div class="sejta-input-container">
<input placeholder="input"/>
</div>
.sejta-input-container{
--inputWidth: 285px;
--inputHeight: 30px;
width: var(--inputWidth);
height: var(--inputHeight);
position: relative;
& input{
height: 100%;
width: var(--inputWidth);
border: 0;
outline: 0;
display: flex;
border-bottom: cornflowerblue 2px solid;
}
}
现在这个输入框的样式大概是这样:
第二步思考:PlaceHolder
给input元素加上原生的placeholder属性,先来看看:
好像还阔以~
好吧,尽管对大多数情况,这个PlaceHolder的样式已经够了,在这个强调用户交互感(卖弄技术流)的年代里,可能还需要一点点的修饰。
我们先用代码把原来的PlaceHolder隐藏掉,将PlaceHolder的颜色设置成透明就可以了:
.sejta-input-container{
...
& input{
...
&:placeholder-shown::placeholder{
color: transparent;
}
}
}
然后给HTML中加一个Label元素
<div class="sejta-input-container">
<input placeholder="this is a placeholder"/>
<label>this is a placeholder</label>
</div>
最后给Label元素添加一个绝对定位和样式:
.sejta-input-container{
...
& label{
pointer-events: none;
position: absolute;
font-size: 12px;
color: #C1C1C1;
top: calc(50% - 6px);
left: 0;
}
}
好的,现在的样子大概是这样的:
我尼玛。。一顿操作0-5的既视感,就是说,我们删掉了原来的placeholder,然后用一个label标签占住了原来placeholder的位置。熟悉CSS变换操作(视觉欺骗)的同学可能已经知道我们要干什么了,placeholder是不能乱动的,但是label基本上属于一个可以为所欲为的标签。
为所欲为啊为所欲为:
.sejta-input-container{
& label{
...
transition: .1s linear;
transform-origin: 0% 0%;
}
& input {
...
&:not(:placeholder-shown)~label,&:focus~label{
--transy:calc((-0.5)*var(--inputHeight));
transform: scale(0.8) translate(0,var(--transy));
color: cornflowerblue;
}
}
}
解读一下,这里用了placeholder-shown的选择器,意思是当placehodler-shown为false的时候,选择input的下一个兄弟元素label(~选择器),让它进行一系列的旋转跳跃。
注意整理的–transy变量,是为了计算transform的位移量而设置的。
我们设置变形中心 transfrom-orgin为0 0的点,这样可以避免变形后的label向右侧移动。
到现在为止,整个dom结构是这样的,这里用了vue的格式来书写:
<template>
<div class="sejta-input-container">
<input placeholder="this is a placeholder"/>
<label>this is a placeholder</label>
</div>
</template>
<style lang="scss">
.sejta-input-container{
--inputWidth: 285px;
--inputHeight: 30px;
width: var(--inputWidth);
height: var(--inputHeight);
position: relative;
& input{
height: 100%;
width: var(--inputWidth);
border: 0;
outline: 0;
display: flex;
border-bottom: cornflowerblue 2px solid;
&:placeholder-shown::placeholder{
color: transparent;
}
&:not(:placeholder-shown)~label,&:focus~label{
--transy:calc((-0.5)*var(--inputHeight));
transform: scale(0.8) translate(0,var(--transy));
color: cornflowerblue;
}
}
& label{
transition: .1s linear;
transform-origin: 0% 0%;
pointer-events: none;
position: absolute;
font-size: 12px;
color: #C1C1C1;
top: calc(50% - 6px);
left: 0;
}
}
</style>
<script>
export default {
name:"sejta-input"
}
</script>
第三步思考:更多的交互内容
其实一开始写这个控件,是不想使用border的。border是一个很强大的属性,与此同时也有很大的限制性,比如说动画。
一位伟人说得好,想要为所欲为,首先你需要一个div。
最初为了轻量和简单,准备使用伪元素来仿造border,结果一顿操作发现input没有before或者after伪元素–就算部分chrome浏览器可以渲染出来,显示也不太正常。所以这里直接用div操作了。当然有兴趣的童鞋也可以使用svg的line来做下面的效果。
我们把原来border-bottom的代码去掉,并且添加一个div,用来伪造border:
<div class="sejta-input-container">
<input placeholder="this is a placeholder"/>
<label>this is a placeholder</label>
<div class="border-line"></div>
</div>
.sejta-input-container{
...
& input{
...
/*border-bottom: cornflowerblue 2px solid;*/
box-sizing: border-box;
}
& .border-line{
height: 2px;
width:var(--inputWidth);
background: cornflowerblue;
position: absolute;
bottom: 0;
left: 0;
}
}
OK,现在我们得到了一个跟之前一毛一样的input。注意这个新添加的input属性:
box-sizing:border-box;
它的意思是让input计算高度的时候以边框的位置开始计算。如果没有这一行代码:
Very Well~
下面我们来添加交互效果。首先让代表着**的这个div宽度为0,然后当输入框**时,宽度从0变成var(–inputWidth)
.sejta-input-container{
...
& .border-line{
...
width: 0px;
transition: all .2s linear;
}
& input{
...
&:not(:placeholder-shown)~.border-line,&:focus~.border-line{
/*transform: scaleX(100);*/
width:var(--inputWidth);
color: cornflowerblue;
}
}
}
来看看效果:Div是真的好用,当初用SVG的位移,定位差点没搞死我。
好的,到现在为止,贴一下全部代码:
<template>
<div class="sejta-input-container">
<input placeholder="this is a placeholder"/>
<label>this is a placeholder</label>
<div class="border-line"></div>
</div>
</template>
<style lang="scss">
.sejta-input-container{
--inputWidth: 285px;
--inputHeight: 30px;
width: var(--inputWidth);
height: var(--inputHeight);
position: relative;
& .border-line{
width: 0px;
height: 2px;
transition: all .2s linear;
background: cornflowerblue;
position: absolute;
bottom: 0;
left: 0;
}
& input{
box-sizing: border-box;
height: 100%;
width: var(--inputWidth);
border: 0;
outline: 0;
display: flex;
border-bottom: #C1C1C1 2px solid;
&:placeholder-shown::placeholder{
color: transparent;
}
&:not(:placeholder-shown)~label,&:focus~label{
--transy:calc((-0.5)*var(--inputHeight));
transform: scale(0.8) translate(0,var(--transy));
color: cornflowerblue;
}
&:not(:placeholder-shown)~.border-line,&:focus~.border-line{
/*transform: scaleX(100);*/
width:var(--inputWidth);
color: cornflowerblue;
}
}
& label{
transition: .1s linear;
transform-origin: 0% 0%;
pointer-events: none;
position: absolute;
font-size: 12px;
color: #C1C1C1;
top: calc(50% - 6px);
left: 0;
}
}
</style>
<script>
export default {
name:"sejta-input"
}
</script>
一个凑合的input就写好了。
How To Vue Components
敬请期待