为了账号安全,请及时绑定邮箱和手机立即绑定

【CSS 好文系列】实战大操作-表单控件

忍不住开头打个广告😎:
2021 火爆全网的 CSS 架构实战课上线,好评如潮!!!
【课程链接:https://coding.imooc.com/class/501.html

前言

表单是网页中最常见的视觉元素,而表单校验是表单中最常见的操作。通常情况下,会结合Angular/React/Vue等MVVM框架完成相关的表单校验功能。

本次通过纯CSS完成一个可切换的登录注册模块,通过选择器实现一些看似只能由JS才能实现的效果,具体使用到如下选择器。

  • +:相邻同胞选择器
  • ~:通用同胞选择器
  • :not():非指定条件的元素
  • :hover:鼠标悬浮的元素
  • :focus:输入聚焦的表单元素
  • :valid:输入合法的表单元素
  • :invalid:输入非法的表单元素
  • :checked:选项选中的表单元素
  • :placeholder-shown:占位显示的表单元素
  • :nth-child(n):元素中指定顺序索引的元素

登录注册

登录注册模块是每一个网站都可能具备的模块。本次实战需求是通过纯CSS编写一个登录注册模块,当然排除登录注册的按钮点击事件。首先需明确有哪些功能。

  • 切换登录注册两个模块,可用~:checkednth-child(n)实现
  • 悬浮模块导航时显示选中状态,可用:hover实现
  • 判断输入框是否进入输入状态并校验内容,可用:focus:valid:invalid实现
  • 判断输入框是否存在内容,可用+:not()placeholder-shown实现

总体来说,可将登录注册模块分为两部分,分别是模块切换表单校验

模块切换

还记得第9章选择器如何构造这种纯CSS切换效果吗?若忘记了可回看这章,实现原理主要是结合<input><label><input>使用id<label>使用for关联起来,而hidden使<input>隐藏起来,不占用页面任何位置,此时<label>放置在页面任何位置都行。

input:checked + div {}
input:checked ~ div {}

还记得第9章选择器的切换按钮的刹车动画吗?也搬过来使用吧,对使用刹车动画的节点声明transition:all 300ms cubic-bezier(.4,.4,.25,1.35)即可。

登录注册-1

<div class="auth">
    <input id="login-btn" type="radio" name="auth" checked hidden>
    <input id="logon-btn" type="radio" name="auth" hidden>
    <div class="auth-title">
        <label for="login-btn">登录</label>
        <label for="logon-btn">注册</label>
        <em></em>
    </div>
    <div class="auth-form">
        <form>登录</form>
        <form>注册</form>
    </div>
</div>

.bruce {
    background-color: #999;
}
.auth {
    overflow: hidden;
    border-radius: 2px;
    width: 320px;
    background-color: #fff;
    .auth-title {
        display: flex;
        position: relative;
        border-bottom: 1px solid #eee;
        height: 40px;
        label {
            display: flex;
            justify-content: center;
            align-items: center;
            flex: 1;
            height: 100%;
            cursor: pointer;
            transition: all 300ms;
            &:hover {
                color: #66f;
            }
        }
        em {
            position: absolute;
            left: 0;
            bottom: 0;
            border-radius: 1px;
            width: 50%;
            height: 2px;
            background-color: #f66;
            transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
        }
    }
    .auth-form {
        display: flex;
        width: 200%;
        height: 250px;
        transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
        form {
            flex: 1;
            padding: 20px;
        }
    }
}
#login-btn:checked {
    & ~ .auth-title {
        label:nth-child(1) {
            font-weight: bold;
            color: #f66;
        }
        em {
            transform: translate(0, 0);
        }
    }
    & ~ .auth-form {
        transform: translate(0, 0);
    }
}
#logon-btn:checked {
    & ~ .auth-title {
        label:nth-child(2) {
            font-weight: bold;
            color: #f66;
        }
        em {
            transform: translate(160px, 0);
        }
    }
    & ~ .auth-form {
        transform: translate(-50%, 0);
    }
}

表单校验

还记得第9章选择器的表单校验吗?通过以下几点结合能完成纯CSS表单校验,具体细节可回看这章。

完成一个完整的表单校验,需以下HTML属性和选择器搭配。

  • placeholder:占位,在未输入内容时显示提示文本
  • pattern:正则,在输入内容时触发正则验证
  • :valid:作用于输入合法的表单节点
  • :invalid:作用于输入非法的表单节点

以手机输入框为例,需满足以下HTML结构和CSS样式。

<input type="text" placeholder="请输入手机" pattern="^1[3456789]\d{9}$" required>

input:valid {}
input:invalid {}

但是存在一个问题,若直接声明input:validinput:invalid,在页面初始化后或输入框内容为空时都会触发:invalid,导致表单校验还未开始就显示校验不通过的样式。为了只在输入内容时才触发:valid:invalid,可在其前面添加:focus,表示在表单处于聚焦状态时才触发某些行为。

input:focus:valid {}
input:focus:invalid {}

在输入内容时,有内容无内容可通过:placeholder-shown判断。:placeholder-shown表示占位显示的表单元素,而占位不显示的表单元素可用:not()取反,再结合+带动紧随该节点的节点。

  • 有内容就无占位::not(:placeholder-shown)
  • 无内容就有占位::placeholder-shown

本次实战主要是为了将上述选择器结合起来使用而提供一种场景,所以不写太多复杂的输入框了。将登录模块的HTML结构复制一份到注册模块,哈哈!最终代码如下。

登录注册

<div class="auth">
    <input id="login-btn" type="radio" name="auth" checked hidden>
    <input id="logon-btn" type="radio" name="auth" hidden>
    <div class="auth-title">
        <label for="login-btn">登录</label>
        <label for="logon-btn">注册</label>
        <em></em>
    </div>
    <div class="auth-form">
        <form>
            <div>
                <input type="text" placeholder="请输入手机" pattern="^1[3456789]\d{9}$" required>
                <label>手机</label>
            </div>
            <div>
                <input type="password" placeholder="请输入密码(6到20位字符)" pattern="^[\dA-Za-z_]{6,20}$" required>
                <label>密码</label>
            </div>
            <button type="button">登录</button>
        </form>
        <form>
            <div>
                <input type="text" placeholder="请输入手机" pattern="^1[3456789]\d{9}$" required>
                <label>手机</label>
            </div>
            <div>
                <input type="password" placeholder="请输入密码(6到20位字符)" pattern="^[\dA-Za-z_]{6,20}$" required>
                <label>密码</label>
            </div>
            <button type="button">登录</button>
        </form>
    </div>
</div>

.bruce {
    background-color: #999;
}
.auth {
    overflow: hidden;
    border-radius: 2px;
    width: 320px;
    background-color: #fff;
    .auth-title {
        display: flex;
        position: relative;
        border-bottom: 1px solid #eee;
        height: 40px;
        label {
            display: flex;
            justify-content: center;
            align-items: center;
            flex: 1;
            height: 100%;
            cursor: pointer;
            transition: all 300ms;
            &:hover {
                color: #66f;
            }
        }
        em {
            position: absolute;
            left: 0;
            bottom: 0;
            border-radius: 1px;
            width: 50%;
            height: 2px;
            background-color: #f66;
            transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
        }
    }
    .auth-form {
        display: flex;
        width: 200%;
        height: 250px;
        transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
        form {
            flex: 1;
            padding: 20px;
        }
        div {
            display: flex;
            flex-direction: column-reverse;
            & + div {
                margin-top: 10px;
            }
        }
        input {
            padding: 10px;
            border: 1px solid #e9e9e9;
            border-radius: 2px;
            width: 100%;
            height: 40px;
            outline: none;
            transition: all 300ms;
            &:focus:valid {
                border-color: #09f;
            }
            &:focus:invalid {
                border-color: #f66;
            }
            &:not(:placeholder-shown) + label {
                height: 30px;
                opacity: 1;
                font-size: 14px;
            }
        }
        label {
            overflow: hidden;
            padding: 0 10px;
            height: 0;
            opacity: 0;
            line-height: 30px;
            font-weight: bold;
            font-size: 0;
            transition: all 300ms;
        }
        button {
            margin-top: 10px;
            border: none;
            border-radius: 2px;
            width: 100%;
            height: 40px;
            outline: none;
            background-color: #09f;
            cursor: pointer;
            color: #fff;
            transition: all 300ms;
        }
    }
}
#login-btn:checked {
    & ~ .auth-title {
        label:nth-child(1) {
            font-weight: bold;
            color: #f66;
        }
        em {
            transform: translate(0, 0);
        }
    }
    & ~ .auth-form {
        transform: translate(0, 0);
    }
}
#logon-btn:checked {
    & ~ .auth-title {
        label:nth-child(2) {
            font-weight: bold;
            color: #f66;
        }
        em {
            transform: translate(160px, 0);
        }
    }
    & ~ .auth-form {
        transform: translate(-50%, 0);
    }
}


  • 在线演示:[Here] codepen.io/JowayYoung/pen/OJXLBwZ
  • 在线源码:[Here] github.com/JowayYoung/idea-css/blob/master/icss/src/components/component/%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C.vue

作者:JowayYoung

打个小广告

2021 火爆全网的 CSS 架构实战课上线,好评如潮!!!
【课程链接:https://coding.imooc.com/class/501.html

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
55
获赞与收藏
38

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消