原生CSS、HTML 和 JavaScript 實現酷炫表單

一直使用 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 變量,就可以根據設置跟隨鼠標移動的樣式了。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章