自定義input[type="radio"]的樣式

對於表單,input[type="radio"] 的樣式老是不那麼友好,在不一樣的瀏覽器中表現不一。chrome

2017年11月28日更新瀏覽器

對單選按鈕自定義樣式,咱們之前一直用的腳原本實現,不過如今可使用新的僞類 :checkbox 來實現。app

若是直接對單選按鈕設置樣式,那麼這個僞類並不實用,由於沒有多少樣式可以對單選按鈕起做用。不過,卻是能夠基於單選按鈕的勾選狀態藉助組合選擇符來給其餘元素設置樣式。優化

不少時候,不管是爲了表單元素統一,仍是爲了用戶體驗良好,咱們都會選擇 label 元素和 input[type="radio"] 一塊兒使用。當<label>元素與單選按鈕關聯以後,也能夠起到觸發開關的做用ui

思路:this

1. 能夠爲<label>元素添加生成性內容(僞元素),並基於單選按鈕的狀態來爲其設置樣式;spa

2. 而後把真正的單選按鈕隱藏起來;firefox

3. 最後把生成內容美化一下。code

解決方法:orm

1. 一段簡單的結構代碼:

<div class="female">
    <input type="radio" id="female" name="sex" />
    <label for="female"></label>
</div>
<div class="male">                
    <input type="radio" id="male" name="sex" />
    <label for="male"></label>
</div>

2. 生成一個僞元素,做爲美化版的單選按鈕,先給僞元素添加一些樣式:

input[type="radio"] + label::before {
    content: "\a0"; /*不換行空格*/
    display: inline-block;
    vertical-align: middle;
    font-size: 18px;
    width: 1em;
    height: 1em;
    margin-right: .4em;
    border-radius: 50%;
    border: 1px solid #01cd78;
    text-indent: .15em;
    line-height: 1; 
}

如今的樣子:

原來的單選按鈕仍然可見,可是咱們先給單選按鈕的勾選狀態添加樣式:

3. 給單選按鈕的勾選狀態添加不一樣的樣式: 

input[type="radio"]:checked + label::before {
    background-color: #01cd78;
    background-clip: content-box;
    padding: .2em;
}

如今的樣子: 

4. 如今把原來的單選按鈕隱藏:

input[type="radio"] {
    position: absolute;
    clip: rect(0, 0, 0, 0);
}

 如今的樣子:

隱藏原來的單選按鈕時,若是使用 display: none; 的話,那樣會把它從鍵盤 tab 鍵切換焦點的隊列中徹底刪除。

因而可採用剪切的方式,讓剪切後的尺寸爲零,這樣就隱藏了原來的單選按鈕。

 

 


 

下面爲舊內容:

爲了最大程度的顯示出它們的差異,而且爲了好看,首先定義了一些樣式:

<form action="">
    <div class="sex">
        <div class="female">
            <label for="female"></label>
            <input type="radio" name="sex" id="female">
        </div>
        <div class="male">
            <label for="male"></label>
            <input type="radio" name="sex" id="male">
        </div>
    </div>
</form>
body { margin: 0; }
input { padding: 0; margin: 0; border: 0; }
.female, .male {
    position: relative;
    height: 40px;
    line-height: 40px;
    margin-left: 40px;
}
.sex label {
    display: block;
    height: 40px;
    width: 40px;
    line-height: 40px;
    font-size: 20px;
    cursor: pointer;
}
.sex input {
    z-index: 3;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 40px;
    margin: auto;
    display: block;
    width: 30px;
    height: 30px;
    cursor: pointer;
}

而後在各個瀏覽器中觀察,會發現有很大的差異:

ie:

edge:

opera:

chrome:

firefox:

對於 firefox 瀏覽器,即使是設置了寬和高,依然是沒有效果,input[type="radio"] 的那個圓圈仍是初始狀態那麼大。其它瀏覽器的表現也不一致,爲了達到一致的效果,咱們須要作兼容處理。

思路:

1. 將 input[type="radio"] 隱藏, opacity: 0; 置於上層,當咱們點擊它時,就能正確的響應本來的事件。

2. 自定義一個圓圈,置於下層,模擬本來類似的樣式;

3. 用 js 實現選中 input[type="radio"] 時,在其下層的自定義的元素改變原來的背景顏色。

代碼:

<form action="">
    <div class="sex">
        <div class="female">
            <label for="female"></label>
            <input type="radio" name="sex" id="female">
            <span class="female-custom"></span> <!-- 同下面的 span 同樣做爲自定義的元素 -->
        </div>
        <div class="male">
            <label for="male"></label>
            <input type="radio" name="sex" id="male">
            <span class="male-custom"></span>    
        </div>
    </div>
</form>
body { margin: 0; }
input { padding: 0; margin: 0; border: 0; }
.female, .male {
    position: relative; /* 設置爲相對定位,以便讓子元素能絕對定位 */
    height: 40px;
    line-height: 40px;
    margin-left: 40px;
}
.sex label {
    display: block;
    height: 40px;
    width: 40px;
    line-height: 40px;
    font-size: 20px;
    cursor: pointer;
}
.sex input {
    z-index: 3;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 40px;
    margin: auto; /* 這裏及以上的定位,可讓該元素豎直居中。(top: 0; bottom: 0;) */
    opacity: 0;
    display: block;
    width: 30px;
    height: 30px;
    cursor: pointer;
}
.sex span {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 40px;
    margin: auto;
    display: block;
    width: 25px;
    height: 25px;
    border: 1px solid #000;
    border-radius: 50%;
    cursor: pointer;
}        
.sex span.active {
    background-color: #000;            
}
$("#male").click( function () {
    $(this).siblings("span").addClass("active");
    $(this).parents("div").siblings("div").children("span").removeClass("active");
});
$("#female").click( function () {
    $(this).siblings("span").addClass("active");
    $(this).parents("div").siblings("div").children("span").removeClass("active");
});

這樣處理後,在瀏覽器中展現效果所有同樣了:

 

擴展:

1. 對於代碼中出現的定位,對父元素使用 position: relative; 給子元素使用 position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; 能實現讓子元素相對於父元素居中(知足水平居中和豎直居中)顯示。若是隻是須要豎直居中,則不須要添加 right: 0; 和 left: 0; 的樣式。

2. 有時當咱們不容易肯定子元素的高度時,能夠這樣設置:對父元素 position: relative; 對子元素 position: absolute; top: 10px; bottom: 10px; margin: auto; 這樣一來,子元素的高度就是父元素的高度減去20px後的值了,一樣,top 和 bottom 支持百分數,可擴展性更強。

 

優化更新:

需求:

1. 有時候咱們須要內聯的單選樣式;

2. 選中的按鈕內的小圓圈不須要佔滿整個外圈的大小。

思路:

1. 讓每個包裹選擇的 div 左浮動;

2. 給父元素添加圓形的外邊框,子元素設置一個稍小於父元素大小的背景。

代碼:

<form action="">
    <div class="fruit">
        <div class="apple">
            <label for="apple">蘋果</label>
            <input type="radio" name="fruit" id="apple">
            <div class="user-defined">
                <span class="circle"></span>
            </div>
        </div>
        <div class="banana">
            <label for="banana">香蕉</label>
            <input type="radio" name="fruit" id="banana">
            <div class="user-defined">
                <span class="circle"></span>
            </div>
        </div>
        <div class="orange">
            <label for="orange">橘子</label>
            <input type="radio" name="fruit" id="orange">
            <div class="user-defined">
                <span class="circle"></span>
            </div>
        </div>
    </div>
</form>
* { box-sizing: border-box; }

body { padding: 50px; }

input { padding: 0; margin: 0; border: 0; }

.fruit:before { content: ""; display: table; }

.fruit:after { content: ""; display: table; clear: both; }

.fruit > div { position: relative; float: left; margin-right: 50px; width: 80px; height: 40px; line-height: 40px; }

.fruit > div:last-child { margin-right: 0; }

.fruit label { display: block; width: 50px; height: 40px; line-height: 40px; cursor: pointer; }

.fruit input { z-index: 3; display: block; opacity: 0; position: absolute; top: 0; bottom: 0; left: 50px; margin: auto; width: 30px; height: 30px; cursor: pointer; }

.fruit .user-defined { z-index: 2; position: absolute; top: 0; bottom: 0; left: 50px; margin: auto; width: 30px; height: 30px; border: 1px solid #000; border-radius: 50%; cursor: pointer; }

.fruit .user-defined span.circle  { display: block; width: 24px; height: 24px; margin-top: 2px; margin-left: 2px; background-color: transparent; border-radius: 50%; }

.fruit .user-defined span.active  { background-color: #000; }
$("input").click(function() {
    $(this).siblings("div").children("span").addClass("active");
    $(this).parents("div").siblings("div").find("span").removeClass("active");
});

效果顯示以下:

 

優化更新: (2016年11月07日)

需求:

1. 有時候咱們的選擇只有兩種,好比性別;

2. 這種選擇但願能像手機系統設置裏的切換同樣。

思路:

1. 讓每個包裹選擇的 div 左浮動;

2. 讓當前子元素添加區別的背景。

預期結果:

代碼:

<div class="sex">
    <span class="warning fl">性別肯定後將不可更改!</span>
    <div class="select fr">
        <div class="male fl">
            <label for="male">                        
                <input type="radio" name="sex" id="male" checked></label>
            <span class="btn active"></span>
        </div>
        <div class="female fl">
            <label for="female">
                <input type="radio" name="sex" id="female"></label>
            <span class="btn"></span>
        </div>                    
    </div>         
</div>
/*性別*/
.sex span.warning {
    font-size: 1.4rem;
    color: #ccc;
}
.sex .male,
.sex .female {
    position: relative;
    width: 4rem;
    height: 3.9rem;
    z-index: 1;
    line-height: 3.9rem;
    text-align: center;
}
.sex .male label,
.sex .female label {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 4rem;
    height: 3.9rem;
    z-index: 3;
    opacity: 0;
    margin: auto;
    display: inline-block;
    line-height: 3.9rem;
    cursor: pointer;
}
.sex input {
    display: inline-block;
    vertical-align: middle;/*讓默認的單選樣式的圓圈和「男」「女」的文本沒有高差,看起來在同一水平線*/
    height: 2.8rem;
    line-height: 2.8rem;
    margin: 0; /*清除瀏覽器默認的外邊距*/
}
.sex .male span.btn,
.sex .female span.btn {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 4rem;
    height: 2.8rem;
    z-index: 2;
    margin: auto;
    display: inline-block;
    line-height: 2.6rem;
    text-align: center;
    border: .1rem solid #fe5454;
    color: #fe5454;
}
.sex .male span {
    border-top-left-radius: .2rem;
    border-bottom-left-radius: .2rem;
}
.sex .female span {
    border-top-right-radius: .2rem;
    border-bottom-right-radius: .2rem;
}
.sex .male span.active,
.sex .female span.active {
    background-color: #fe5454;
    color: #fff;
}    

若是用 jQuery 來寫切換的功能的話,很簡單的幾行代碼:

$(".select label").click(function() {
    $(this).siblings("span").addClass("active");
    $(this).parent().siblings("div").find("span").removeClass("active");
}); 

最後,作出來的效果單選原樣式沒有 opacity: 0; 隱藏時:

單選原樣式 opacity: 0; 隱藏時:

相關文章
相關標籤/搜索