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;
        }
    }

现在这个输入框的样式大概是这样:
Amazing Css:自定义下划线样式的Input

第二步思考:PlaceHolder

给input元素加上原生的placeholder属性,先来看看:
Amazing Css:自定义下划线样式的Input
好像还阔以~
好吧,尽管对大多数情况,这个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;
        }
}

好的,现在的样子大概是这样的:
Amazing Css:自定义下划线样式的Input
Amazing Css:自定义下划线样式的Input
我尼玛。。一顿操作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向右侧移动。
Amazing Css:自定义下划线样式的Input
到现在为止,整个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。
Amazing Css:自定义下划线样式的Input

最初为了轻量和简单,准备使用伪元素来仿造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计算高度的时候以边框的位置开始计算。如果没有这一行代码:
Amazing Css:自定义下划线样式的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;
            }
	}
}

来看看效果:
Amazing Css:自定义下划线样式的Input
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

敬请期待