preface
Have you ever been asked by the business “can you change the color of this checkbox?” Match it with the theme color!” “, then suffering from native does not support the color change, and finally forced to hand one to make do. If input[type=radio] is discarded, it is very tedious to simulate selected, unselected, unavailable and other states, and it is even more annoying to involve the checkbox group. In fact, we can use label, ::before, : Checked and tabIndex. Then add a few JavaScript scripts and you can do a good job of emulating a richer “native” checkbox. Let’s try it together.
Check out the box
Since our goal is to change the color of the marquee and the other features and behaviors of the marquee to match the original marquee, we must first understand the main features and behaviors of the marquee. 1. Appearance features 1.1. Normal style
margin: 3px 3px 0px 5px;
border: none 0;
padding: 0;
box-sizing: border-box;
display: inline-block;
line-height: normal;
position: static;
Copy the code
Note: in terms of appearance, we must ensure that the layout features are consistent with the original. Otherwise, the replacement of the custom single box will most likely affect the overall layout, and finally force us to adjust the layout features of other elements to achieve the overall coordination, thus expanding the scope of modification.
1.2. Style to get focus
outline-offset: 0px;
outline: -webkit-focu-ring-color auto 5px;
Copy the code
Note: the “get focus” style here only works with the keyboard Tab key, but it does not work if you click on the menu box to get focus.
1.3. Set the style to Disabled
color: rgb(84, 84, 84);
Copy the code
2. Behavior Characteristics The behavior characteristics of the checkbox are obviously whether it is selected or not, and the change event of the selected state. Therefore, we must keep providing the change event externally. It is also worth noting that the box will be selected by pressing the Space key after it has been brought into focus with the keyboard’s Tab key.
With that in mind, we can start coding!
Cut the crap, dick code
In the figure above, the native menu box is on the left and our custom menu box is on the right. From top to bottom, the styles are unchecked, checked, focused, and disabled.
The CSS part
/* margin: 3px 3px 0px 5px; display: inline-block; box-sizing: border-box; width: 12px; height: 12px; } .radio__appearance{ display: block; */ position: relative; */ position: relative; box-shadow: 0 0 0 1px tomato; /* box-shadow does not affect the height of the box like 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;*/ label.radio.clicked{outline: none 0; Radio input {display: none; / / Radio input {display: none; }Copy the code
HTML part
<! -- Unchecked --> <label class="radio" tabindex="0">
<input type="radio" name="a">
<i class="radio__appearance"></i> </label> <br> <! -- Select status --> <label class="radio" tabindex="0">
<input type="radio" name="a" checked>
<i class="radio__appearance"></i> </label> <br> <! -- Disabled status --> <label class="radio">
<input type="radio" name="a" disabled>
<i class="radio__appearance"></i>
</label>
Copy the code
JavaScript part
var radios = document.querySelectorAll(".radio") radios. ForEach (radio => {//"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)}) // After the keyboard is in focus, press 'Space' to perform the selected operation radio.addeventListener ("keydown", e => {
if (e.keyCode === 32){
e.target.click()
}
})
})
Copy the code
There are three caveats to this implementation:
- through
label
Passes mouse click events to associatedinput[type=radio]
, so you can safely hide the checkbox and use the features of the checkbox itself. But as a result oflabel
The control’s own limitations, such as not being able to get focus elements by default, make it impossible to pass keyboard keystroke events to a checkbox, even if addedtabindex
Features also need handwritten JS to achieve; - When tabIndex is greater than or equal to 0, it means that the element can get the focus; when tabIndex is 0, it means that the order of getting the focus is arranged according to the location of the element; and when tabIndex is greater than 0, it means that the smaller the element, the earlier it gets the focus.
- Due to the single check box
display
forinline-block
, so the single box will affect the line box height. When customizing an element in the box is usedinline-block
If,vertical-align
A careless setting will cause the line box where the inner element is located to be stretched, which will cause the height of the line box where the custom single box is located to be increased. So here we use the inner elementdisplay
All set toblock
The practice of direct letvertical-align
Failure, improve controllability.
throughopacity:0
Implementation (2018/10/5 added)
Above, we associate input[type=radio] of display: None with label so as to simplify the implementation of the custom single box by using input[type=radio], but we still need to write JS to achieve the behavior characteristics selected by pressing Space key. Is there another way to save more trouble? We just want users to not see the native single-click box, so why not set it to opacity:0 directly? ! The CSS part
.radio {/* make sure the layout is the same */ margin: 3px 3px 0px 5px; display: inline-block; box-sizing: border-box; width: 13px; height: 13px; } /* The behavior of custom singleton is mainly based on the native singleton; therefore, the native singleton is first transparent and the entire parent element is filled with */. Radio input {opacity: 0; position: absolute; z-index: 1; /* Must overwrite. Radio__appearance to respond to mouse events */ width: 100%; height: 100%; } .radio__container-box{ position: relative; width: 100%; height: 100%; } .radio__appearance{ display: block; */ position: relative; */ position: relative; box-shadow: 0 0 0 1px tomato; /* box-shadow does not affect the height of the box like 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;*/.radio.clicked. Radio_appearance {outline: none 0; }Copy the code
HTML part
<! -- Unselected status --> <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 state --> <span class="radio">
<span class="radio__container-box">
<input type="radio" name="a" disabled>
<i class="radio__appearance"></i>
</span>
</span>
Copy the code
JavaScript part
var radios = document.querySelectorAll(".radio") radios. ForEach (radio => {//"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)
})
})
Copy the code
conclusion
Check boxes can be modified slightly, and then encapsulated in VUE, React and other frameworks to provide a simpler API for easier use. Respect the original, reproduced please indicate from: www.cnblogs.com/fsjohnhuang… ^_^ fat John