摘要:前言是否曾经被业务提出能改改这个单选框的颜色吧让它和主题颜色搭配一下吧,然后苦于原生不支持换颜色,最后被迫自己手撸一个凑合使用。设置为的样式行为特征单选框的行为特征,明显就是选中与否,及选中状态的改变事件,因此我们必须保持对外提供事件。
前言
是否曾经被业务提出"能改改这个单选框的颜色吧!让它和主题颜色搭配一下吧!",然后苦于原生不支持换颜色,最后被迫自己手撸一个凑合使用。若抛开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部分
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个注意点:
通过label传递鼠标点击事件到关联的input[type=radio],因此可以安心隐藏单选框又可以利用单选框自身特性。但由于label控件自身的限制,如默认不是可获得焦点元素,因此无法传递键盘按键事件到单选框,即使添加tabindex特性也需手写JS来实现;
当tabindex大于等于0时表示该元素可以获得焦点,为0时表示根据元素所在位置安排获得焦点的顺序,而大于0则表示越小越先获得焦点;
由于单选框的display为inline-block,因此单选框将影响line box高度。当自定义单选框内元素采用inline-block时,若vertical-align设置稍有不慎就会导致内部元素所在的line box被撑高,从而导致自定义单选框所在的line box高度变大。因此这里采用将内部元素的display均设置为block的做法,直接让vertical-align失效,提高可控性。
通过opacity:0实现(2018/10/5追加) 上面我们通过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部分
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,使用起来就更方便了。
尊重原创,转载请注明来自:https://www.cnblogs.com/fsjoh... ^_^肥仔John
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/113963.html
摘要:真心没法弄出圆角自从有了后,我们就可以通过制作圆角矩形圆形等图形,甚至连也受到影响从而实现元素阴影也能做到圆角的效果。那么是否也能做出圆角的效果呢答案是否定的。 前言 在CSS魔法堂:改变单选框颜色就这么吹毛求疵!中我们要模拟原生单选框通过Tab键获得焦点的效果,这里涉及到一个常常被忽略的属性——outline,由于之前对其印象确实有些模糊,于是本文打算对其进行稍微深入的研究^_^ ...
摘要:利用用和来做表单即时校验需求让表单检验变得简单优雅,不需要写冗长的代码来校验设置样式丰富了表单元素,提供了类似等表单元素属性。不知细叶谁裁出,二月春风似剪刀。首先,你需要先了解一下渐变的使用技巧。 之前不久,由于自己平时涉猎还算广泛,总结了一篇博客:这些JavaScript编程黑科技,装逼指南,高逼格代码,让你惊叹不已,没想到受到了大家的欢迎,有人希望能博主还能整理个 CSS 的一些黑...
摘要:利用用和来做表单即时校验需求让表单检验变得简单优雅,不需要写冗长的代码来校验设置样式丰富了表单元素,提供了类似等表单元素属性。不知细叶谁裁出,二月春风似剪刀。首先,你需要先了解一下渐变的使用技巧。 之前不久,由于自己平时涉猎还算广泛,总结了一篇博客:这些JavaScript编程黑科技,装逼指南,高逼格代码,让你惊叹不已,没想到受到了大家的欢迎,有人希望能博主还能整理个 CSS 的一些黑...
摘要:利用用和来做表单即时校验需求让表单检验变得简单优雅,不需要写冗长的代码来校验设置样式丰富了表单元素,提供了类似等表单元素属性。不知细叶谁裁出,二月春风似剪刀。首先,你需要先了解一下渐变的使用技巧。 之前不久,由于自己平时涉猎还算广泛,总结了一篇博客:这些JavaScript编程黑科技,装逼指南,高逼格代码,让你惊叹不已,没想到受到了大家的欢迎,有人希望能博主还能整理个 CSS 的一些黑...
阅读 1045·2021-11-18 10:02
阅读 1303·2021-09-23 11:22
阅读 2602·2021-08-21 14:08
阅读 1632·2019-08-30 15:55
阅读 1718·2019-08-30 13:45
阅读 3135·2019-08-29 16:52
阅读 3090·2019-08-29 12:18
阅读 1633·2019-08-26 13:36