Hi, I’m Steven.

In this issue we will do a drag-and-drop puzzle captcha, which is a very common type of captcha in recent years, as opposed to the traditional guessing of words:

So let’s get started.

This video version of the tutorial at www.bilibili.com/video/BV1NM… , welcome the attention of three companies!

The infrastructure

Open the CodePen editor and add a

in the HTML section with the id captcha.

Go to the CSS section, add the Body selector, and use Flexbox to center the content up, down, left, and right. Add the #captcha selector, set the display to block, the width to 400px, and the height to 260px. Since you will use this width and height later, split them into CSS variables.

Add a few rounded corners and set the background image. The background image is the picture of the puzzle. On Unsplash’s website, find this one that fits:

Then copy its link and apply it to background-image. To fill the container, background-size is set to cover, background-position is set to center, and position is set to relative, add a little shadow, and you’re done.

Two pieces of the puzzle

The next step is to make two puzzles, one on the outside and one on the inside.

The piece inside was a hint of a gap in the puzzle, and since it happened to be two, I went straight to Pseudo Elements.

Add the #captcha::before and #captcha:: After selectors and set position to absolute. To display pseudo-elements, you must set the Content property to a blank string. Display is set to block, and the next several Settings are set according to the parent element, including width, height, background image, background-size and background-position.

Since the background image is the same, there is no difference. Temporarily remove the setting of the background image, set the background color to red, and you can see the size and position of the fake element.

The next step is to set the size of the puzzle block. Go back to #captcha and set the two CSS variables –puzzle-width and –puzzle-height to 80px.

Then, through the inset() of the clip-path property, set the mask to zoom up, right, down, left and inward. Here, set the -WebKit version first.

The first set is to zoom in from the top, set it to calc(), var(–height) minus var(–puzzle-height) and divide by 2 to get 90px.

Var (–puzzle-width) var(–puzzle-width);

The third set point is zoomed in from the bottom. This is the same as the first set point. Copy and paste it.

Var (–width) minus var(–puzzle-width) multiplied by 2 to get 230px.

Now you see where the red square is, it’s 80px by 80px. Duplicate the Settings of -webkit and apply the clip-path.

Then move one of the squares out to the left, add the #captcha:: After selector and set transform: translatex(-300px). Change the red square back to the background image to remove the jigsaw square. Change it to calc(var(–width) * -1) to align it more accurately.

And then what about the square inside? Add the #captcha:: Before selector, set the background color to 60% opacity black, and set background-blend-mode to multiply to blend the translucent black with the background image.

Pull the article

This part is finished, then make the lower pull bar, add a

to the HTML #captcha with the ID of Handle, and add a SPAN to make the button inside. The reason you don’t make buttons with pseudo-elements is that you can’t listen for pseudo-element events directly in JavaScript.

Add the # Handle selector to the CSS section, set the width to calc(), var(–width), add var(–puzzle-width) multiplied by 2, set the height to 30px and the rounded corners to 15px.

Set the background color to light gray, position to absolute, move to bottom, bottom to -50px, move left to calc(), var(–puzzle-width) * 2 * -1, add a little shadow inward, Make a little bit of stereo and add a light gray frame line. Because of the box line, the height is different, so change the rounded corners to 18px.

Then handle the drag button, add the # Handle SPAN selector, set display to block, and set the width to the same as the jigsaw. The height and rounded corners are inherited from the parent element, and the background color is set to white, followed by inwards and outwards shadows to create a three-dimensional effect.

Set position to Absolute and change the cursor style to Move.

To handle its horizontal displacement, add a CSS variable called — Moved, and assign it 0px; Or set it to 200px first to make it easier to see the effect:

Move it by transform: translatex(). And you have to have a minimum and a maximum, otherwise you’re going to exceed this bar. Clamp () function with the first minimum value set to 0px, the second value set to — Moved, and the third maximum value set to width plus jigsaw width.

Going back to — Moved, try extreme numbers, like 1000px will move to the far right, and -1000px will move to the far left. Temporarily change it to 400px so that we can handle the displacement of the puzzle.

Go to the #captcha:: After selector, change to CLAMP (), set the minimum value to width times -1, move the value to width times -1, and add –moved. And the maximum is going to be the width of the puzzle, so let’s try changing — Moved, and see what it looks like, and that’s about it.

Ok, so now we know that by adjusting — Moved, we can move the drag button and the puzzle in sync. So the next step is simply to add JavaScript logic and change the value of — Moved.

The part of JavaScript logic

Go to the JavaScript section and define a few constants to get the selectors you’ll use: Captcha, Handle, and Button.

Then add three event listeners:

  • mousedownWhen you click down;
  • mousemoveWhen moving;
  • mouseupThe time to let go.

We need to define a flag here, too, called shouldMove, to see if it’s clicked.

Then on mouseDown, set it to true.

Go inside the Mousemove, if shouldMove is true, define the constant offsetLeft to get the shift between the pull bar and the left side of the screen. Define the constant buttonWidth to get the width of the button. With the cursor position, you can calculate the correct — Moved result by changing the value of — Moved under #captcha, which is the CSS variable.

Set it to e. clientx, the cursor’s X position, minus offsetLeft, minus buttonWidth divided by 2, the cursor’s X position, minus the distance between the move bar and the left, minus the buttonWidth divided by 2. Divide by 2 because the center point is set to the middle of the button.

And then in mouseup, shouldMove should be false.

The move effect is achieved, but there is a problem, is that in the process of dragging, if the cursor is not above the button, it will not move, because it has left the button itself, the event listener can not listen. So change the mousemove and Mouseup listener from Button to Window.

Finally, deal with the logic of the success puzzle.

Say shouldMove equals false when shouldMove is true. Then define the constant finalOffset to get the drag distance, subtract e.clientx from the left displacement of the drag bar, and output console.log().

This captchas usually allow a small margin of error, so we’ll take 430 to 450 as the acceptable range. If not, we’ll set — Moved to 0px, and put the button back where it was; If successful, add a class name passed to #captcha, and we’ll go to CSS to handle the style change.

Going back to the CSS section, when #captcha is passed, set the transparency of ::before, ::after, and #handle inside to 0.

Then I want to add a rebound effect when the puzzle fails. Go to # Handle Span and add transition:

The transition from # Captcha: Active to # Handle Span is None. The transition from # Captcha: Active is none.

The same Settings apply to the #captcha:: After selector.

Let’s look at the completion of this case

And that’s it for this episode.


The source code for this case is at codepen. IO /stevenlei/p…

Your support is my motivation, please pay attention to CodingStartup at least class, we come together!

  • B station: space.bilibili.com/451368848
  • YouTube: youtube.com/codingstart…
  • The Denver nuggets: juejin. Cn/user / 249773…