视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
css改变单选框颜色的方法实现(附代码)
2020-11-02 22:08:56 责编:小采
文档
本篇文章给大家带来的内容是关于css改变单选框颜色的方法实现(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

是否曾经被业务提出"能改改这个单选框的颜色吧!让它和主题颜色搭配一下吧!",然后苦于原生不支持换颜色,最后被迫自己手撸一个凑合使用。若抛开input[type=radio]重新开发一个,发现要模拟选中、未选中、不可用等状态很繁琐,而涉及单选框组就更烦人了,其实我们可以通过label、::before、:checked和tabindex,然后外加少量JavaScript脚本就能很好地模拟出一个样式更丰富的“原生”单选框。下面我们一起来尝试吧!

单选框了解一下

由于我们的目标是改变单选框颜色,其他外观特征和行为与原来的单选框一致,那么我们就必须先了解单选框原来的外观特征和行为主要有哪些。
1.外观特征
1.1.常态样式

margin: 3px 3px 0px 5px;
border: none 0;
padding: 0;
box-sizing: border-box;
display: inline-block;
line-height: normal;
position: static;

注意:外观上我们必须要保证布局特性和原生的一致,否则采用自定义单选框替换后很大机会会影响整体的布局,最后导致被迫调整其他元素的布局特性来达到整体的协调,从而扩大了修改范围。

1.2.获得焦点的样式

outline-offset: 0px;
outline: -webkit-focu-ring-color auto 5px;

注意:这里的获取焦点的样式仅通过键盘Tab键才生效,若通过鼠标点击虽然单选框已获得焦点,但上述样式并不会生效。

1.3.设置为disabled的样式

color: rgb(84, 84, 84);

2.行为特征
?单选框的行为特征,明显就是选中与否,及选中状态的改变事件,因此我们必须保持对外提供change事件。
?另外值得注意的是,当通过键盘的Tab键让单选框获得焦点后,再按下Space键则会选中该单选框。

?有了上述的了解,我们可以开始着手撸代码了!

少废话,撸代码

上图中左侧就是原生单选框,右侧为我们自定义的单选框。从上到下依次为未选中选中获得焦点disabled状态的样式。

CSS部分

label.radio {
 /* 保证布局特性保持一致 */
 margin: 3px 3px 0px 5px;
 display: inline-block;
 box-sizing: border-box;

 width: 12px;
 height: 12px;
}

.radio__appearance{
 display: block; /* 设置为block则不受vertical-align影响,从而不会意外影响到.radio的linebox高度 */
 position: relative;
 box-shadow: 0 0 0 1px tomato; /* box-shadow不像border那样会影响盒子的框高 */
 border-radius: 50%;
 height: 90%;
 width: 90%;
 text-align: center;
}
label.radio [type=radio] + .radio__appearance::before{
 content: "";
 display: block;
 border-radius: 50%;
 width: 85%;
 height: 85%;

 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);

 transition: background .3s;
}
label.radio [type=radio]:checked + .radio__appearance::before{
 background: tomato;
}
label.radio [type=radio][disabled] + .radio__appearance{
 opacity: .5;
}
label.radio:focus{
 outline-offset: 0px;
 outline: #999 auto 5px;
}
/* 通过鼠标单击获得焦点时,outline效果不生效 */
label.radio.clicked{
 outline: none 0;
}
/* 自定义单选框的行为主要是基于原生单选框的,因此先将原生单选框隐藏 */
label.radio input {
 display: none;
}

HTML部分

<!-- 未选中状态 -->
<label class="radio" tabindex="0">
 <input type="radio" name="a">
 <i class="radio__appearance"></i>
</label>

<br>

<!-- 选中状态 -->
<label class="radio" tabindex="0">
 <input type="radio" name="a" checked>
 <i class="radio__appearance"></i>
</label>

<br>

<!-- disabled状态 -->
<label class="radio">
 <input type="radio" name="a" disabled>
 <i class="radio__appearance"></i>
</label>

JavaScript部分

var radios = document.querySelectorAll(".radio")
radios.forEach(radio => {
 // 模拟鼠标点击后:focus样式无效
 radio.addEventListener("mousedown", e => {
 var tar = e.currentTarget
 tar.classList.add("clicked")
 var fp = setInterval(function(){
 if (document.activeElement != tar){
 tar.classList.remove("clicked")
 clearInterval(fp)
 }
 }, 400)
 })
 // 模拟通过键盘获得焦点后,按`Space`键执行选中操作
 radio.addEventListener("keydown", e => {
 if (e.keyCode === 32){
 e.target.click()
 }
 })
})

这个实现有3个注意点:

1、通过label传递鼠标点击事件到关联的input[type=radio],因此可以安心隐藏单选框又可以利用单选框自身特性。但由于label控件自身的,如默认不是可获得焦点元素,因此无法传递键盘按键事件到单选框,即使添加tabindex特性也需手写JS来实现;

2、当tabindex大于等于0时表示该元素可以获得焦点,为0时表示根据元素所在位置安排获得焦点的顺序,而大于0则表示越小越先获得焦点;

3、由于单选框的display为inline-block,因此单选框将影响line box高度。当自定义单选框内元素采用inline-block时,若vertical-align设置稍有不慎就会导致内部元素所在的line box被撑高,从而导致自定义单选框所在的line box高度变大。因此这里采用将内部元素的display均设置为block的做法,直接让vertical-align失效,提高可控性。

通过opacity:0实现

?上面我们通过label关联display:none的input[type=radio]从而利用input[type=radio]简化自定义单选框的实现,但依然要手写JS实现按Space键选中的行为特征,有没有另一种方式可以更省事呢?我们只是想让用户看不到原生单选框,那么直接设置为opacity:0不就可以了吗?!

CSS部分

.radio {
 /* 保证布局特性保持一致 */
 margin: 3px 3px 0px 5px;
 display: inline-block;
 box-sizing: border-box;

 width: 13px;
 height: 13px;
}
/* 自定义单选框的行为主要是基于原生单选框的,因此先将原生单选框透明,且沾满整个父元素 */
.radio input {
 opacity: 0;
 position: absolute;
 z-index: 1; /* 必须覆盖在.radio__appearance上才能响应鼠标事件 */
 width: 100%;
 height: 100%;
}
.radio__container-box{
 position: relative;
 width: 100%;
 height: 100%;
}
.radio__appearance{
 display: block; /* 设置为block则不受vertical-align影响,从而不会意外影响到.radio的linebox高度 */
 position: relative;
 box-shadow: 0 0 0 1px tomato; /* box-shadow不像border那样会影响盒子的框高 */
 border-radius: 50%;
 height: 90%;
 width: 90%;
 text-align: center;
}
.radio [type=radio] + .radio__appearance::before{
 content: "";
 display: block;
 border-radius: 50%;
 width: 85%;
 height: 85%;

 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);

 transition: background .3s;
}
.radio [type=radio]:checked + .radio__appearance::before{
 background: tomato;
}
.radio [type=radio][disabled] + .radio__appearance{
 opacity: .5;
}
.radio:focus-within .radio__appearance{
 outline-offset: 0px;
 outline: #999 auto 5px;
}
/* 通过鼠标单击获得焦点时,outline效果不生效 */
.radio.clicked .radio_appearance{
 outline: none 0;
}

HTML部分

<!-- 未选中状态 -->
<span class="radio">
 <span class="radio__container-box">
 <input type="radio" name="a">
 <i class="radio__appearance"></i>
 </span>
</span>

<br>

<!-- 选中状态 -->
<span class="radio">
 <span class="radio__container-box">
 <input type="radio" name="a" checked>
 <i class="radio__appearance"></i>
 </span>
</span>

<br>

<!-- disabled状态 -->
<span class="radio">
 <span class="radio__container-box">
 <input type="radio" name="a" disabled>
 <i class="radio__appearance"></i>
 </span>
</span>

JavaScript部分

var radios = document.querySelectorAll(".radio")
radios.forEach(radio => {
 // 模拟鼠标点击后:focus样式无效
 radio.addEventListener("mousedown", e => {
 var tar = e.currentTarget
 tar.classList.add("clicked")
 var fp = setInterval(function(){
 if (!tar.contains(document.activeElement){
 tar.classList.remove("clicked")
 clearInterval(fp)
 }
 }, 400)
 })
})

总结

对于复选框我们可以稍加修改就可以了,然后通过VUE、React等框架稍微封装一下提供更简约的API,使用起来就更方便了。

下载本文
显示全文
专题