欢迎来到DIVCSS5查找CSS资料与学习DIV CSS布局技术!
    单选框了解一下
    由于我们的目标是改变单选框颜色,其他外观特征和行为与原来的单选框一致,那么我们就必须先了解单选框原来的外观特征和行为主要有哪些。
    1.外观特征
    1.1.常态样式
    margin:3px3px0px5px;
    border:none0;
    padding:0;
    box-sizing:border-box;
    display:inline-block;
    line-height:normal;
    position:static;
    注意:外观上我们必须要保证布局特性和原生的一致,否则采用自定义单选框替换后很大机会会影响整体的布局,最后导致被迫调整其他元素的布局特性来达到整体的协调,从而扩大了修改范围。
    1.2.获得焦点的样式
    outline-offset:0px;
    outline:-webkit-focu-ring-colorauto5px;
    注意:这里的获取焦点的样式仅通过键盘Tab键才生效,若通过鼠标点击虽然单选框已获得焦点,但上述样式并不会生效。
    1.3.设置为disabled的样式
    color:rgb(84,84,84);
    2.行为特征
    单选框的行为特征,明显就是选中与否,及选中状态的改变事件,因此我们必须保持对外提供change事件。
    另外值得注意的是,当通过键盘的Tab键让单选框获得焦点后,再按下Space键则会选中该单选框。
    有了上述的了解,我们可以开始着手撸代码了!
    少废话,撸代码
    435275490-5bb54e2fc18b1_articlex.png
    上图中左侧就是原生单选框,右侧为我们自定义的单选框。从上到下依次为未选中、选中、获得焦点和disabled状态的样式。
    CSS部分
    label.radio{
    /*保证布局特性保持一致*/
    margin:3px3px0px5px;
    display:inline-block;
    box-sizing:border-box;
    width:12px;
    height:12px;
    }
    .radio__appearance{
    display:block;/*设置为block则不受vertical-align影响,从而不会意外影响到.radio的linebox高度*/
    position:relative;
    box-shadow:0001pxtomato;/*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:#999auto5px;
    }
    /*通过鼠标单击获得焦点时,outline效果不生效*/
    label.radio.clicked{
    outline:none0;
    }
    /*自定义单选框的行为主要是基于原生单选框的,因此先将原生单选框隐藏*/
    label.radioinput{
    display:none;
    }
    HTML部分
    <!--未选中状态-->
    <labelclass="radio"tabindex="0">
    <inputtype="radio"name="a">
    <iclass="radio__appearance"></i>
    </label>
    <br>
    <!--选中状态-->
    <labelclass="radio"tabindex="0">
    <inputtype="radio"name="a"checked>
    <iclass="radio__appearance"></i>
    </label>
    <br>
    <!--disabled状态-->
    <labelclass="radio">
    <inputtype="radio"name="a"disabled>
    <iclass="radio__appearance"></i>
    </label>
    JavaScript部分
    varradios=document.querySelectorAll(".radio")
    radios.forEach(radio=>{
    //模拟鼠标点击后:focus样式无效
    radio.addEventListener("mousedown",e=>{
    vartar=e.currentTarget
    tar.classList.add("clicked")
    varfp=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,因此单选框将影响linebox高度。当自定义单选框内元素采用inline-block时,若vertical-align设置稍有不慎就会导致内部元素所在的linebox被撑高,从而导致自定义单选框所在的linebox高度变大。因此这里采用将内部元素的display均设置为block的做法,直接让vertical-align失效,提高可控性。
    通过opacity:0实现
    上面我们通过label关联display:none的input[type=radio]从而利用input[type=radio]简化自定义单选框的实现,但依然要手写JS实现按Space键选中的行为特征,有没有另一种方式可以更省事呢?我们只是想让用户看不到原生单选框,那么直接设置为opacity:0不就可以了吗?!
    CSS部分
    .radio{
    /*保证布局特性保持一致*/
    margin:3px3px0px5px;
    display:inline-block;
    box-sizing:border-box;
    width:13px;
    height:13px;
    }
    /*自定义单选框的行为主要是基于原生单选框的,因此先将原生单选框透明,且沾满整个父元素*/
    .radioinput{
    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:0001pxtomato;/*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:#999auto5px;
    }
    /*通过鼠标单击获得焦点时,outline效果不生效*/
    .radio.clicked.radio_appearance{
    outline:none0;
    }
    HTML部分
    <!--未选中状态-->
    <spanclass="radio">
    <spanclass="radio__container-box">
    <inputtype="radio"name="a">
    <iclass="radio__appearance"></i>
    </span>
    </span>
    <br>
    <!--选中状态-->
    <spanclass="radio">
    <spanclass="radio__container-box">
    <inputtype="radio"name="a"checked>
    <iclass="radio__appearance"></i>
    </span>
    </span>
    <br>
    <!--disabled状态-->
    <spanclass="radio">
    <spanclass="radio__container-box">
    <inputtype="radio"name="a"disabled>
    <iclass="radio__appearance"></i>
    </span>
    </span>
    JavaScript部分
    varradios=document.querySelectorAll(".radio")
    radios.forEach(radio=>{
    //模拟鼠标点击后:focus样式无效
    radio.addEventListener("mousedown",e=>{
    vartar=e.currentTarget
    tar.classList.add("clicked")
    varfp=setInterval(function(){
    if(!tar.contains(document.activeElement){
    tar.classList.remove("clicked")
    clearInterval(fp)
    }
    },400)
    })
    })








本文转载自中文网

 

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/css3-style/c57332.shtml