说明
. 表单元素在不同浏览器上的默认样式不尽相同,为了统一,通常需要覆盖默认样式,再重新自定义新的样式
. 部分样式需要使用浏览器前缀
. 方便起见,设置各表单元素为border-box
. 部分元素可以设置appearance为none,从头开始设计UI
. form布局可以使用表格;也可以使用其它布局方式
. 以下各例,如无特殊说明,均进行初始化设计
. 请多参考底部的 can i use,避免样式使用异常
相关伪元素
类别
说明
::placeholder
占位符样式
::selection
元素选中部分样式
相关伪类
以下伪类都可以配合:not()使用
类别
说明
:focus
获取焦点时
:checked
元素选择中
:valid
有效时
:invalid
无效时
:in-range
在指定范围
:out-of-range
超出指定范围
:placeholder-shown
占位符显式[必须有占位符]
新CSS样式
类别
说明
accent-color
指定部分控件的颜色,如<input>的radio、checkbox、range和<progress>;抛弃原来丑到爆的样式
可以统一指定
:root {
accent-color: #f40;
}
[ ] input初始化设置
. 字体大小、类型、边框、轮廓
. 默认的占位符样式和文本选择样式
. 通常根据type修改特定的表单元素
input[type=text] {
width: 100%;
border: none;
outline: none;
font: inherit;
box-sizing: border-box;
background-color: transparent;
}
input[type=text]::placeholder {
color: #089;
}
input[type=text]::selection {
color: #F40;
}
[ ] 自定义radio-利用:checked
方案1. 额外增加元素,替换/隐藏<input>
. 伪元素 ::after
. 相邻兄弟选择器 +
[ HTML ]
<label class="label-custom">
<input type="radio" name="cgender" checked>
<span class="radio"></span>
<span>Male</span>
</label>
[ CSS ]
.label-custom {
cursor: pointer;
}
.label-custom input {
display: none;
//appearance: none;
}
.label-custom span {
vertical-align: middle;
}
.label-custom .radio {
display: inline-block;
position: relative;
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid #666;
}
.label-custom input:checked+.radio {
border-color: #f40;
}
.label-custom input:checked+.radio::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #f40;
}
方案2. 直接使用<label>替换<input>:可以是文字、图片、字体图标;详情请参考 个人网站
[ ]
自定义checkbox-利用伪<label>的伪元素实现;点击时跳转其位置从左边到右边
. <label>是inline,要转换为block才可以设置宽高
. 没有使用传统的父相子绝方式,而是让伪元素相对位置发生变化[作为子元素,它本来就在父元素的开始位置]
. 也可以使用accent-color修改默认的背景颜色,简单快捷,但是只适用于部分表单元素
[ HTML ]
<input type="checkbox" id="cb-custom" hidden>
<label for="cb-custom" class="cb-custom"></label>
[ CSS ]
.cb-custom {
display: block;
margin: 2rem auto;
width: 80px;
height: 40px;
border: 2px solid var(--main-color-gray);
padding: 2px;
border-radius: 20px;
cursor: pointer;
}
.cb-custom::before {
content: '';
position: relative;
display: block;
left: 0px;
width: 50%;
height: 100%;
background-color: var(--main-color-gray);
border-radius: 50%;
transition: 0.4s;
}
#cb-custom:checked+.cb-custom::before {
left: 50%;
background-color: var(--main-color-blue);
}
[ ] 自定义range-利用appearance
. 默认高度是16px
. 直接修改滑块背景的样式
. 滑块的样式需要使用浏览器前缀
.range-bar {
appearance: none;
background-image: linear-gradient(74deg, #16a085, #1abc9c);
border-radius: 16px;
border: 2px solid #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .2);
}
.range-bar::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
background-color: #f1c40f;
border-radius: 50%;
transition: 0.5s;
}
.range-bar:active::-webkit-slider-thumb {
box-shadow: 0 0 10px 4px #f39c12;
}
[ ] 自定义fieldset
. 可以单独设置每一条边;还可以使用定位任意放置legend
.fieldset fieldset {
position: relative;
border: 1px solid var(--main-color-dark);
border-top: 10px solid var(--main-color-blue);
margin-bottom: 2rem;
}
.fieldset legend {
font-size: 1.2rem;
margin: 0 auto;
padding: 0 1rem;
text-transform: capitalize;
}
.fieldset fieldset:nth-child(2) legend {
position: absolute;
right: 40px;
top: -20px;
background-color: #fff;
}
.fieldset fieldset:nth-child(3) legend {
position: absolute;
left: 40px;
bottom: -20px;
background-color: #fff;
}
[ ] :focus - 获取焦点
. 初始设计:边框border、占位符placeholder颜色,填充padding-left、背景background透明
. :hover:边框换色
. :focus:边框换色、字体颜色;后期可用使用动画设计呼吸灯效果
. :valid内容有效时,通常配合:focus一起使用
.custom-ipt::placeholder {
color: #999;
}
.custom-ipt::selection {
color: #089;
}
.custom-ipt:hover {
border-color: #999;
}
.custom-ipt:focus,
.custom-ipt:valid {
border-color: #089;
color: #f40;
}
事件类型
. 事件处理的业务逻辑在<script>中;建议使用外部.js文件
. 没有失去焦点的伪类选择器;只能通过事件onblur检测
类别
说明
input
数据输入时;使用时要采用 防抖 措施
change
数据改变且失去焦点
keypress
按键按下并保持
keydown
按键按下
keyup
按键释放
blur
失去焦点
事件处理一般步骤
1. 获取input元素 querySelector;更多信息,请参考 DOM
2. 添加事件侦听器 addEventListener;更多信息,请参考 Event
[ ] 播放器进度条
[H5] audio | button | input[range]
[C3] appearance
[JS] click | input | loadmetadata | timeupdate | querySelector
play
[CSS]
#player button {
width: 120px;
}
#player input {
width: 100%;
}
.custom-range {
appearance: none;
height: 10px;
background-color: #01b4ff;
border: 2px solid #fff;
border-radius: 10px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, .2);
}
.custom-range::-webkit-slider-thumb {
appearance: none;
width: 15px;
height: 15px;
background-color: #fff;
border: 1px solid #01b4ff;
border-radius: 50%;
cursor: pointer;
}
.custom-range::-webkit-slider-thumb:hover {
background-color: #ff0;
}
[Javascript]
let bool = false;
let player = document.querySelector('#player');
let audioIpt = player.querySelector('audio');
let btnIpt = player.querySelector('button');
let sliderIpt = player.querySelector('input');
audioIpt.src = '/music/Alizee-La Isla Bonita.mp3';
audioIpt.addEventListener('loadedmetadata', () => {
sliderIpt.max = audioIpt.duration;
})
audioIpt.addEventListener('timeupdate', () => {
sliderIpt.value = Math.floor(audioIpt.currentTime);
})
audioIpt.addEventListener('ended', () => {
sliderIpt.value = 0;
// audioIpt.pause();
btnIpt.innerHTML = 'play';
bool = false;
})
btnIpt.addEventListener('click', () => {
if (bool) {
audioIpt.pause();
btnIpt.innerHTML = 'play';
bool = false;
} else {
audioIpt.play();
btnIpt.innerHTML = 'pause';
bool = true;
}
})
sliderIpt.addEventListener('input', () => {
audioIpt.currentTime = sliderIpt.value;
audioIpt.play();
btnIpt.innerHTML = 'pause';
bool = true;
})
[ ] 输入长度提示-检测input值
. 获取input元素:querySelector
. 获取input元素的maxlength属性/最大长度:el.getAttribute()
. 获取当前输入的值的长度:el.value.length
[HTML]
<input type="text" name="len" id="len-ipt" required maxlength="8" placeholder="text here">
[JavaScript] 将input事件分别修改为change事件、keyup事件、blur事件,体会他们之间的不同
let lenIpt = document.querySelector('#len-ipt');
let lenVal = document.querySelector('#len-val');
lenIpt.addEventListener('input', function () {
lenVal.innerHTML = '还可以输入' + (this.getAttribute('maxlength') - this.value.length)
})
[ ] 显示密码-修改input类型
. 部分系统自带有显式密码功能
. 部分系统要求密码框必须位于表单form中,且应该指定自动完成autocomplete
let spBtn = document.querySelector('#sp-btn');
let spIpt = document.querySelector('#sp-ipt');
spBtn.addEventListener('click', () => {
if (spIpt.type == 'text') {
spIpt.type = 'password'
spBtn.value = '显示密码'
} else {
spIpt.type = 'text'
spBtn.value = '隐藏密码'
}
})
[ ] 全选-修改input属性
. 利用元素的checked属性判断当前选择状态;如果全选为真/选中,则所有选项都置为真/选中;否则取消全选/置为假
. 统计选中的个数,如果等于选项个数,则全选;如果为0,则全不选
. 更多案例,请参考 DOM
let cbs = document.querySelectorAll('input[name="web"]');
let all = document.querySelector('#all');
let allNo = document.querySelector('#all-no');
all.addEventListener('change', function (e) {
console.log(this.checked);
if (this.checked) {
for (let i = 0; i ≤ cbs.length; i++) {
cbs[i].checked = true
}
}
})
allNo.addEventListener('change', function (e) {
console.log(this.checked);
if (this.checked) {
for (let i = 0; i ≤ cbs.length; i++) {
cbs[i].checked = false
}
}
})
cbs.forEach(item => {
item.addEventListener('change', function () {
let num = 0
for (let j = 0; j ≤ cbs.length; j++) {
if (cbs[j].checked) {
num++;
}
}
console.log((num));
if (num == 3)
all.checked = true;
else if (num == 0)
allNo.checked = true;
else {
all.checked = false;
allNo.checked = false;
}
})
})