Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Effect of native

Buttons like this are common in mobile operating systems, but what if the H5 wanted to do this

The element

First, do we need to be clear that this is a button? A switch, “switch”? Let’s think about what elements in HTML5 are similar to this one.

button

In HTML5 native, there is the button tag, which by default provides the following click effects.

But this doesn’t seem to be quite what we expected. Although our expectation looks like a button, it’s actually a switch with two states. But HTML5 doesn’t offer components like the Switch in the UI library, so let’s see if there are other components that have similar duality.

Single box, check box

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
</head>
<body>
  <button>determine</button>
  <input type="radio" value="A">
  <input type="radio" value="B">
  <input type="checkbox">
</body>
</html>
Copy the code

As you can see, the checkboxes are relatively close, but you can’t achieve the “on/off” effect of switching left and right, because the default usage of checkboxes is actually whether or not each of the multiple options is checked.

Custom Components

So since native tags are a little short on such requirements, we have to consider implementing such a component ourselves, using nothing more than HTML+CSS

DOM structure

First, let’s declare the rough structure of the component using HTML

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <style>
    .toggle {
      width: 66px;
      height: 40px;
      box-sizing: border-box;
      padding: 3px;
      border-radius: 25px;
      background-color: #53535C;
    }
    .toggle::after {
      content: ' ';
      display: block;
      height: 34px;
      width: 34px;
      border-radius: 50%;
      background-color: #fff;
    }
  </style>
</head>
<body>
  <div class="toggle"></div>
</body>
</html>
Copy the code

What do you think? I think it’s starting to look good. The entire switch here uses a div tag, and the inner button is implemented using pseudo-elements. See CSS selectors for examples of pseudo-elements: How do pseudo-elements work? This article, there is a detailed interpretation.

Next, we need to “animate” the button to act as a switch.

Click on the event

Since the state of the switch generally needs to be recorded, it makes no sense to simply push the button to switch the interaction without recording the actual state of the switch. So we need a variable here to record the state of the switch, which needs to use JS to achieve, we add the following logic

<body>
  <div class="toggle" onclick="handleToggle()"></div>
  <script>
    let myToggleStatus = false;
    function handleToggle() { myToggleStatus = ! myToggleStatus }</script>
</body>
Copy the code

Style changes

Finally, we need to display different styles according to the state of the switch to achieve the desired switching performance.

<style>
.toggle_on::after {
  margin-left: 44%;
}
</style>
<body>
  <div id="toggle" class="toggle" onclick="handleToggle()"></div>
  <script>
    function changeToggleStyle() {
      const toggle = document.getElementById('toggle');
      if (myToggleStatus) {
        toggle.style.backgroundColor = '#3AFF66';
        toggle.classList.add('toggle_on');
      } else {
        toggle.style.backgroundColor = '#53535C';
        toggle.classList.remove('toggle_on'); }}</script>
</body>
Copy the code

Style optimization

In addition, you can use the TRANSITION property in CSS to add a transition effect to your style changes to make them look smoother.

.toggle {
  transition: background-color .3s ease;
}
.toggle::after {
  transition: margin-left .3s ease;
}
Copy the code

The complete code

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <style>
    .toggle {
      width: 66px;
      height: 40px;
      box-sizing: border-box;
      padding: 3px;
      border-radius: 25px;
      background-color: #53535C;
      transition: background-color .3s ease;
    }
    .toggle::after {
      content: ' ';
      display: block;
      height: 34px;
      width: 34px;
      border-radius: 50%;
      background-color: #fff;
      transition: margin-left .3s ease;
    }
    .toggle_on::after {
      margin-left: 44%;
    }
  </style>
</head>
<body>
  <div id="toggle" class="toggle" onclick="handleToggle()"></div>
  <script>
    let myToggleStatus = false;
    function handleToggle() { myToggleStatus = ! myToggleStatus changeToggleStyle() }function changeToggleStyle() {
      const toggle = document.getElementById('toggle');
      if (myToggleStatus) {
        toggle.style.backgroundColor = '#3AFF66';
        toggle.classList.add('toggle_on');
      } else {
        toggle.style.backgroundColor = '#53535C';
        toggle.classList.remove('toggle_on'); }}</script>
</body>
</html>
Copy the code