1. 程式人生 > >css:預設的checkbox、input、radio太醜了?手把手教你改變使用純css3改寫的帶動畫的預設樣式

css:預設的checkbox、input、radio太醜了?手把手教你改變使用純css3改寫的帶動畫的預設樣式

專案的github地址為: https://github.com/sunshine940326/css3formeledemo
本文首發於我的個人部落格,http://cherryblog.site/ ;歡迎大家檢視我的其他部落格
最近在做公司後臺的優化專案,拿到設計稿一看,設計師覺得預設的input、checkbox、radio太醜了,要優化,在做了幾個demo之後找到了要怎麼優化這些樣式的方法,我優化的原則有以下幾點:

  • 因為是在已有的專案上做優化,所以儘量在不改變原有結構的基礎上進行修改
  • input、checkbox這些大都是表單裡面的元素,所以大部分跟後臺有互動,保留原有屬性,只增加新的class或者id
  • 只使用css3,並且其屬性也都是input,當然也可以直接使用img代替,或者用div+span模擬,但是這就不叫做“優化”,而是模仿了。
  • 使用sass,只需要改變引數就可以反覆多次使用

思路

大致的原理都是使用html原生的標籤元素標籤checkbox或者input,在後面加上label標籤,將一些原有的元素隱藏,然後再用css設定你想要樣式,行為方面都是根據原生屬性來判斷,不需要使用js。所有的html程式碼都是

div.container
    input type="checkbox" id="checkbox" 
    label for="checkbox"
    div
.bottom-line

都是利用css的原生屬性來判斷使用者的操作,先將原本的checkbox隱藏,然後再設定label的樣式,最後設定input[type=checkbox]:checked+label的樣式

checkbox

checkbox demo1

首先來看一個checkbox,實現這個動畫其實很簡單,只運用css就可以實現。實現的原理是繫結checkout和label,用label控制是否checked。點選label的時候改變checkbox的屬性
先將checkbox隱藏,然後label為一個只有border的框框,使用after和befor偽元素來實現對號的兩部分。
先將after和before設定寬度為width*0.4,height為0,設定不同的旋轉角度,讓befor和after合起來剛好是一個對號。
然後用css動畫設定使其height達到width*0.7和width*0.35並控制動畫使其連貫播放,

html

<div class="cb-container">
    <input type="checkbox" id="checkbox">
    <label for="checkbox" class="cb-label"></label>
</div>

scss


$checked-color: #fff;
$checked-bg:rgb(101,141,181);
$unchecked-color: #cfcece;
$unchecked-bg:rgb(249,249,249);
$checkbox-height: 100px;
$background-color:#fff;
$font-color:#dcdcdc;
$duration: .4s;
.cb-container{
  width: 1000px;
  text-align: center;
  margin-top: 50px;
}

html, body{
  padding:0;
  margin:0;
  background-color: $background-color;
  color:$font-color;
  font-family:'Open Sans';
}
#checkbox{
  display:none;
}

.cb-label{
  height: $checkbox-height;
  width: $checkbox-height;
  background: $unchecked-bg;
  border: $checkbox-height * .1 solid $unchecked-color;
  position: relative;
  display: inline-block;
  box-sizing: border-box;
  transition: border-color ease $duration/2;
  -moz-transition: border-color ease $duration/2;
  -o-transition: border-color ease $duration/2;
  -webkit-transition: border-color ease $duration/2;
  cursor: pointer;
  &::before,&::after{
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    position: absolute;
    height: 0;
    width: $checkbox-height * 0.2;
    background: $checked-color;
    display: inline-block;
    -moz-transform-origin: left top;
    -ms-transform-origin: left top;
    -o-transform-origin: left top;
    -webkit-transform-origin: left top;
    transform-origin: left top;
    content: '';
    -webkit-transition: opacity ease 0.5s;
    -moz-transition: opacity ease 0.5s;
    transition: opacity ease 0.5s;
  }
  &::before{
    top:$checkbox-height * 0.76;
    left: $checkbox-height * 0.31;
    -moz-transform: rotate(-135deg);
    -ms-transform: rotate(-135deg);
    -o-transform: rotate(-135deg);
    -webkit-transform: rotate(-135deg);
    transform: rotate(-135deg);
  }
  &::after {
    top: $checkbox-height * .45;
    left: $checkbox-height * 0;
    -moz-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    -o-transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
  }
}
input[type=checkbox]:checked + .cb-label,
.cb-label.checked{

  background: $checked-bg;
  border-color:$checked-bg;
  &::after{
    border-color:$checked-color;
    height: $checkbox-height * .35;
    -moz-animation: dothabottomcheck $duration/2 ease 0s forwards;
    -o-animation: dothabottomcheck $duration/2 ease 0s forwards;
    -webkit-animation: dothabottomcheck $duration/2 ease 0s forwards;
    animation: dothabottomcheck $duration/2 ease 0s forwards;
  }

  &::before{
    border-color:$checked-color;
    height: $checkbox-height * 1;
    -moz-animation: dothatopcheck $duration ease 0s forwards;
    -o-animation: dothatopcheck $duration ease 0s forwards;
    -webkit-animation: dothatopcheck $duration ease 0s forwards;
    animation: dothatopcheck $duration ease 0s forwards;
  }

}
@-moz-keyframes dothabottomcheck{
  0% { height: 0; }
  100% { height: $checkbox-height *0.35; }
}

@-webkit-keyframes dothabottomcheck{
  0% { height: 0; }
  100% { height: $checkbox-height *0.35; }
}

@keyframes dothabottomcheck{
  0% { height: 0; }
  100% { height: $checkbox-height *0.35;  }
}

@keyframes dothatopcheck{
  0% { height: 0; }
  50% { height: 0; }
  100% { height: $checkbox-height * 0.7; }
}
@-webkit-keyframes dothatopcheck{
  0% { height: 0; }
  50% { height: 0; }
  100% { height: $checkbox-height * 0.7; }
}
@-moz-keyframes dothatopcheck{
  0% { height: 0; }
  50% { height: 0; }
  100% { height: $checkbox-height * 0.7; }
}

經過改變後的checkbox

checkboxdemo2

checkboxdemo2

checkboxdemo3

checkboxdemo3

checkboxdemo4

checkboxdemo4

input

input的優化源於在掘金上看到的一篇文章,效果著實小清新,於是就使用拿來主義,寫了一個簡易版的demo,效果如下,運用的是flex佈局還有偽元素placeholder來實現的。
input效果

  • 輸入框清除預設樣式
  • 當輸入框獲得焦點時,輸入框原本的文字向上移,並且下方藍色的線寬度由0變為100
  • 如果沒有輸入內容,還變為未輸入的狀態
    先貼上程式碼

html程式碼

html結構很簡單,使用的是HTML原生的form元素input和label;在效果中的“請輸入內容”這幾個字不是使用的placeholder,而是使用的label,但是也設定有placeholder,只不過是把placeholder的透明度設定為0,因為我們需要根據placeholder是否顯示來設定下方line的寬度和label的位置。

div.input-container
    input type="input" id="input" placeholder="請輸入內容"
    label for="input"
    div.bottom-line

完整html程式碼如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="scss/main.css">
</head>
<body>
<div class="input-container">
    <input type="input" id="input" placeholder="請輸入內容">
    <label for="input">請輸入內容</label>
    <div class="bottom-line"></div>
</div>
</body>
</html>

css程式碼

全部的動畫效果都只使用了css,但是使用的一些新特性瀏覽器相容性還沒有那麼好,相容到ie10.佈局使用的是flex,動畫效果用的是用的transform。運用偽類placeholder判斷是否輸入了文字,如果輸入了文字下方的line寬度變為100%;label中的文字上移並且變小
程式碼如下:

$width: 500px;
$label-font-color: #3f4f5b;
$label-focus-font-color: rgb(82, 97, 108);
$border-bottom-color: #d5d5d5;
$focus-border-color: rgb(101, 141, 181);
$transform-top: 10px;
$transform-time: 0.3s;
$scale: 0.9;

.input-container {
  width: $width;
  position: relative;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: reverse;
  -ms-flex-flow: column-reverse;
  flex-flow: column-reverse;
  -webkit-box-align: start;
  -ms-flex-align: start;
  align-items: flex-start;
  margin: 100px auto
}

.input-container input {
  -webkit-box-ordinal-group: 11;
  order: 10;
  -ms-flex-order: 10;
  outline: none;
  border: none;
  width: 100%;
  padding: 10px 0;
  font-size: 20px;
  border-bottom: 1px solid $border-bottom-color;
  text-indent: 10px;
}

.input-container input::-moz-placeholder {
  opacity: 0;
}

.input-container input::-webkit-input-placeholder {
  opacity: 0;
}

.input-container input:-ms-input-placeholder {
  opacity: 0;
}

.input-container input, .input-container label {
  transition: all $transform-time;
}

.input-container label {
  -webkit-box-ordinal-group: 101;
  -ms-flex-order: 100;
  order: 100;
  color: $label-font-color;
  -webkit-transform-origin: left bottom;
  transform-origin: left bottom;
  -webkit-transform: translate(10px, 40px);
  transform: translate(0px, 40px);
}

.input-container .bottom-line {
  order: 2;
  width: 0;
  height: 2px;
  background: $focus-border-color;
  transition: all $transform-time;
}

.input-container input:focus {
  border-bottom-color: #fff;
}

.input-container input:focus ~ div, .input-container input:not(:placeholder-shown) ~ div {
  width: 100%
}

.input-container input:focus + label, .input-container input:not(:placeholder-shown) + label {
  color: $label-focus-font-color;
  -webkit-transform: translate(10px) scale($scale);
  transform: translate(10px) scale($scale)
}