一直使用 Vue/React ,習慣了用元件,偶爾想用原生三劍客寫點 Demo 發現樣式醜的不忍直視。最近看 掘金小冊《玩轉CSS的藝術之美》看到 CSS 相關的内容,發現原生 CSS 也可以把表單處理的很好看。
效果:
完整代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.form-box {
width: 500px;
}
.form-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
label {
display: block;
font-size: 16px;
flex: 90px 0 0;
}
label::after {
content: ":";
margin-right: 6px;
display: inline-block;
vertical-align: middle;
}
input.text-input {
display: block;
padding: 0 10px;
border: 1px solid #ccc;
width: 100%;
height: 40px;
outline: none;
caret-color: #09f;
/*光标顔色*/
transition: all 300ms;
border-left-width: 5px;
}
input.text-input:valid {
border-color: #3c9;
}
input.text-input:invalid {
border-color: #f66;
}
input[type=checkbox] {
position: relative;
appearance: none;/*去除系統預設appearance的樣式引發的問題*/
cursor: pointer;
transition: all 100ms;
border-radius: 31px;
width: 70px;
height: 40px;
background-color: #e9e9eb;
outline: none;
margin: 0;
display: inline-block;
}
input[type=checkbox]::before {
position: absolute;
content: "";
transition: all 300ms cubic-bezier(.45, 1, .4, 1);
border-radius: 31px;
width: 70px;
height: 40px;
background-color: #e9e9eb;
}
input[type=checkbox]::after {
position: absolute;
left: 4px;
top: 4px;
border-radius: 27px;
width: 32px;
height: 32px;
background-color: #fff;
box-shadow: 1px 1px 5px rgba(#000, .3);
content: "";
transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
}
input[type=checkbox]:checked {
background-color: #3c9;
}
input[type=checkbox]:checked::before {
transform: scale(0);
}
input[type=checkbox]:checked::after {
transform: translateX(30px);
}
button {
width: 48%;
height: 40px;
padding: 0;
margin: 0;
border: none;
outline: none;
cursor: pointer;
border-radius: 5px;
overflow: hidden;
position: relative;
background: #63c3ff;
color: #fff;
}
button::before {
--size: 0;
position: absolute;
left: var(--x);
top: var(--y);
width: var(--size);
height: var(--size);
background-image: radial-gradient(circle closest-side, #09f, transparent);
content: "";
transform: translate3d(-50%, -50%, 0);
transition: width 200ms ease, height 200ms ease;
}
button[type=reset] {
background: #6fcc6f;
}
button[type=reset]::before {
background-image: radial-gradient(circle closest-side, #4abf4a, transparent);
}
button:hover::before {
--size: 400px;
}
button:first-child {
margin-right: 4%;
}
span {
position: relative;
pointer-events: none;
}
</style>
</head>
<body>
<form class="form-box" id="form" onsubmit=onSubmit(event)>
<div class="form-item">
<label>昵稱</label>
<input type="text"
name="name"
class="text-input"
placeholder="請輸入昵稱(3-20個字元,僅限英文字母,數字和下劃線)"
pattern="^[\w]{3,20}$"
oninput="setCustomValidity('')"
oninvalid="setCustomValidity('請輸入合法的昵稱>_<')"
required>
</div>
<div class="form-item">
<label>郵箱</label>
<input type="email"
class="text-input"
placeholder="請輸入郵箱位址"
required>
</div>
<div class="form-item">
<label>密碼</label>
<input type="password"
name="password"
class="text-input"
placeholder="請輸入密碼"
oninput="onPwdInput(event)"
required>
</div>
<div class="form-item">
<label>确認密碼</label>
<input type="password"
name="password"
id="confirmPwd"
class="text-input"
placeholder="請輸入密碼"
required>
</div>
<div class="form-item">
<label>VIP</label>
<input name="isAdult" type="checkbox" />
</div>
<div class="form-item">
<button type="reset" onmousemove="move(event)">
<span>重 置</span>
</button>
<button type="submit" value="提 交" onmousemove="move(event)">
<span>提 交</span>
</button>
</div>
</form>
<script>
function move(e) {
const x = e.pageX - e.target.offsetLeft;
const y = e.pageY - e.target.offsetTop;
e.target.style.setProperty("--x", `${x}px`);
e.target.style.setProperty("--y", `${y}px`);
}
function onSubmit(e) {
e.preventDefault(); // 阻止表單送出
const form = e.target;
console.log(params);
}
function onPwdInput(e) {
confirmPwd.pattern = e.target.value;
}
</script>
</body>
</html>
順便說一下代碼裡涉及的知識點
1、屬性選擇器
一般用的較多 CSS 選擇器的是ID、類、和标簽選擇器。屬性選擇器也有各種靈活的使用方式。文法是中括号。
[attr] 表示帶有以 attr 命名的屬性的元素。
[attr=value] 表示帶有以 attr 命名的屬性,且屬性值為 value 的元素。
還有其他限制開頭、結尾、包含等規則,可以自己查找。
2、表單狀态選擇器
:valid 和 :invalid 分别對應合法的
表單元素和不合法的表單元素。
3、appearance: none
appearance 主要有兩種用途,要将平台特定的樣式應用于預設情況下不包含該樣式的元素,删除預設情況下具有特定于平台的樣式的元素。
上面代碼中的 appearance: none 就是删除 checkbox 原有的樣式。
<div style="appearance: button;">button</div> 可以讓你一個 div 顯示原生按鈕樣式。(不過相容性不大好,我試了下Chrome并沒有生效, -webkit-appearance 在Safari中生效了)
4、pointer-events: none
指定 pointer-events: none; 的元素永遠不會成為滑鼠事件的 target。禁用其滑鼠事件和滑鼠相關樣式。
但是,當其後代元素的
pointer-events
屬性指定其他值時,滑鼠事件可以指向後代元素,在這種情況下,滑鼠事件将在捕獲或冒泡階段觸發父元素的事件偵聽器。
5、表單驗證
required:任何帶有 required 屬性的字段都必須有值,否則無法送出表單。
input type: HTML5 為 <input> 元素增加了幾個新的 type 值。這些類型屬性不僅表明了字段期待的資料類型,而且也提供了一些預設驗證,其中兩個新的輸入類型是已經得到廣泛支援的 "email" 和 "url"。
pattern:文本字段 pattern 屬性,用于指定一個正規表達式,使用者輸入的文本必須與之比對。在重複輸入密碼的時候,把第一次的密碼作為重複密碼的 pattern 以保證兩次輸入密碼一緻性驗證。
setCustomValidity: 自定義表單不合法時的提示資訊。
表單 reset(): 把表單字段重置為各自的預設值。
6、CSS 變量
在 JavaScript 接受滑鼠事件參數并将滑鼠位置指派給 CSS 變量,就可以根據設定跟随滑鼠移動的樣式了。