Want to replicate youtube's autoplay toggle button in pure css

Viewed 159

Until recently youtube used a tag named "paper-toggle-button". My script used that but since youtube removed it I've had to settle with a normal boring checkbox. I don't just want an answer. I want to learn how it works. It bugs me that this advanced css doesn't click for me yet.

I've been trying to replicate it via tutorials that show in various ways how to make a sliding toggle button. But I'm not satisfied with the look. I want it to look as close to the youtube's toggle button as possible. At least one thing I've learned. The code below doesn't need any pictures which is good.

picture of the toggle button

This requires advanced knowledge of css which I don't have.

Here's an example and it looks ugly. Because it must for instance manually put the label in the correct place. See .labelterm. I gave up when I couldn't use this tutorial code to add a checkmark.

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1">
    <title>Awesome checkbox</title>
    <style type="text/css">
        .mylabel {
            position: relative;
            display: block;
            width: 60px;
            height: 30px;
            margin-bottom: 15px;
        }
        .mylabel input {
            display: none;
        }
        .slidinggroove {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            background: #ababab;
            /*background: rgba(0, 0, 0, 0.1);*/
            border-radius: 20px;
            transition: all 0.3s ease;
        }
        .slidinggroove:after {
            position: absolute;
            content: "";
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: #fff;
            /*background: rgba(255, 255, 255, 0.2);*/
            top: 1px;
            left: 1px;
            transition: all 0.3s ease;
        }
        input:checked + .slidinggroove {
            background: #5fcf80;
        }
        input:checked + .slidinggroove:after {
            transform: translateX(30px);
        }
        .labelterm {
            margin-left: 65px;
            font-size: 16px;
            color: #222;
            font-family: "Roboto", sans-serif;
            position: relative;
            top: 5px;
        }
    </style>
</head>

<body>
    <div class="mylabel">
        <input type="checkbox" id="coding">
        <div class="slidinggroove"></div>
        <label class="mylabel" for="coding" name="skills"><p class="labelterm">Test</p></label>
    </div>
</body>
</html>
2 Answers

Here's how I would tackle this to achieve the look of the picture shown:

.slidinggroove::before{
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-7px);
  width: 20px;
  height: 20px;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  content: "\f00c";
  display: block;
  color: #fff;
}

You must import a library for the icon as a font, I recommend using FontAwesome as shown in the working snippet here :

.mylabel {
  position: relative;
  display: block;
  width: 60px;
  height: 30px;
  margin-bottom: 15px;
}

.mylabel input {
  display: none;
}

.slidinggroove {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #ababab;
  /*background: rgba(0, 0, 0, 0.1);*/
  border-radius: 20px;
  transition: all 0.3s ease;
}

.slidinggroove:after {
  position: absolute;
  content: "";
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #fff;
  /*background: rgba(255, 255, 255, 0.2);*/
  top: 1px;
  left: 1px;
  transition: all 0.3s ease;
}

.slidinggroove:before {
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-7px);
  width: 20px;
  height: 20px;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  content: "\f00c";
  display: block;
  color: #fff;
}

input:checked+.slidinggroove {
  background: #5fcf80;
}

input:checked+.slidinggroove:after {
  transform: translateX(30px);
}

.labelterm {
  margin-left: 65px;
  font-size: 16px;
  color: #222;
  font-family: "Roboto", sans-serif;
  position: relative;
  top: 5px;
}
<html>

<head>
  <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1">
  <title>Awesome checkbox</title>
</head>

<body>
  <div class="mylabel">
    <input type="checkbox" id="coding">
    <div class="slidinggroove"></div>
    <label class="mylabel" for="coding" name="skills"><p class="labelterm">Test</p></label>
  </div>
</body>

</html>

The way it works is as follow, you create a pseudo-element that will have as content the unicode of the fontawesome icon. Then you have a complete control hover it (font-size, color, ...).

Appreciate your eagerness of leaning. Let’s break the problem down and tackle each of them then merge them together to have a complete solution. Apparently, we need several things:

  1. An oval shape background for the toggle to move. Lets call it pit
  2. A circle that can be move to left or right. Lets call it knob.
  3. The control need to have its own state, for checked and unchecked. We can make use of an native checkbox
  4. The color of the control will change along the state.
  5. Animation

We start with the basic first. To draw the toggle with html:

<div class="toggle">
    <input class="toggle__input" type="checkbox"> <span class="toggle__pit"> <span class="toggle__knob"></span>
    </span>
</div>

the toggle serve as the container of the whole toggle. Inside there is a a native checkbox element, toggle__pit and a toggle__knob. Without css they are just white square. Lets style it according to the sample image.

.toggle__pit {
  /* set the size */
  width: 36px;
  height: 16px;
  /* set the color */
  background-color: #bababa;
  border: 1px solid #bababa;
  /* set the oval shape, value = height /2 */
  border-radius: 8px;
  /* border width is part of the element size */
  box-sizing: border-box;
  /* display span as a inline block element */
  /* span is a inline element which cant assign width and height*/
  display: inline-block;
}

.toggle__knob {
  /* set the size */
  width: 14px;
  height: 14px;
  /* make it circle */
  border-radius: 50%;
  background-color: white;
  display: inline-block;
}

.toggle .toggle__input {
  /* keep the checkbox hidden */
  display: none;
}
<div class="toggle">
  <input class="toggle__input" type="checkbox"> <span class="toggle__pit">
                <span class="toggle__knob"></span>
  </span>

</div>

Now the toggle looks like the sample image, but it is in unchecked state. We need to make it interactive so it responses to user action. Since the checkbox is hidden, user cannot interactive with it. We can use <label> to associate with the input. In this way even the input is hidden we can toggle it. We need to modify the html a bit, to have the input wrap by the label.

.toggle__pit {
  /* set the size */
  width: 36px;
  height: 16px;
  /* set the color */
  background-color: #bababa;
  border: 1px solid #bababa;
  /* set the oval shape, value = height /2 */
  border-radius: 8px;
  /* border width is part of the element size */
  box-sizing: border-box;
  /* display span as a inline block element */
  /* span is a inline element which cant assign width and height*/
  display: inline-block;
}

.toggle .toggle__pit::after {
  /* if the checkbox is checked, move knob to right */
  content: 'L';
  font-family: Helvetica, Arial, Sans-Serif;
  color: white;
  font-size: 12px;
  display: inline-block;
  transform: translateX(4px) translateY(-3px) scaleX(-1) rotate(-40deg);
  transform-origin: 50% 50%;
}

.toggle__knob {
  /* set the size */
  width: 14px;
  height: 14px;
  /* make it circle */
  border-radius: 50%;
  background-color: white;
  display: inline-block;
  /* for position it to left or right */
  position: absolute;
}

.toggle__label {
  /* act as a reference point for knob positioning */
  position: relative;
  line-height: 16px;
}

.toggle .toggle__input {
  /* keep the checkbox hidden */
  display: none;
}

.toggle .toggle__input:checked+.toggle__pit {
  /* if the checkbox is checked, change pit color */
  background-color: #167ac6;
  border: 1px solid #167ac6;
}

.toggle .toggle__input:checked+.toggle__pit .toggle__knob {
  /* if the checkbox is checked, move knob to right */
  left: 21px;
}
<div class="toggle">
  <label class="toggle__label"> <input class="toggle__input" type="checkbox"> <span class="toggle__pit">
                <span class="toggle__knob"></span>
        </span>
        </label>
</div>

Finally, to smoothen the state transition, add some transition to toogle__knob and toggle__pit.

.toggle__pit {
  /* set the size */
  width: 36px;
  height: 16px;
  /* set the color */
  background-color: #bababa;
  border: 1px solid #bababa;
  /* set the oval shape, value = height /2 */
  border-radius: 8px;
  /* border width is part of the element size */
  box-sizing: border-box;
  /* display span as a inline block element */
  /* span is a inline element which cant assign width and height*/
  display: inline-block;
  transition: background-color 0.5s linear, border 0.5s linear;
}

.toggle .toggle__pit::after {
  /* use L to mock a tick*/
  content: 'L';
  font-family: Helvetica, Arial, Sans-Serif;
  color: white;
  font-size: 12px;
  /* pseudo-element is inline by defauly, which you can't apply transform*/
  display: inline-block;
  /* flip L horizontally and rotate it */
  transform: translateX(4px) translateY(-3px) scaleX(-1) rotate(-40deg);
  transform-origin: 50% 50%;
}

.toggle__knob {
  /* set the size */
  width: 14px;
  height: 14px;
  /* make it circle */
  border-radius: 50%;
  background-color: white;
  display: inline-block;
  /* for position it to left or right */
  position: absolute;
  left: 1px;
  /* enable animation */
  transition: all 0.5s linear;
}

.toggle__label {
  /* act as a reference point for knob positioning */
  position: relative;
  line-height: 16px;
}

.toggle .toggle__input {
  /* keep the checkbox hidden */
  display: none;
}

.toggle .toggle__input:checked+.toggle__pit {
  /* if the checkbox is checked, change pit color */
  background-color: #167ac6;
  border: 1px solid #167ac6;
}

.toggle .toggle__input:checked+.toggle__pit .toggle__knob {
  /* if the checkbox is checked, move knob to right */
  left: 21px;
}
<div class="toggle">
  <label class="toggle__label"> <input class="toggle__input" type="checkbox"> <span class="toggle__pit">
                <span class="toggle__knob"></span>
        </span>
        </label>
</div>

Related