Pure CSS Focus Follower
Overview
This CSS module creates a visual effect where a single circular element (.follow) moves to follow the currently focused or checked form element (text inputs, checkboxes, or submit button) in a form. When the submit button is clicked, the circle moves in an arc-like path to enhance the visual transition. The effect is implemented purely in CSS, without JavaScript, and is designed to match the behavior of a provided JavaScript-based example where a circle stops 16px to the left of the focused element, vertically centered.
Purpose
- Provide an interactive, visually engaging user experience by highlighting the active form element with a moving circle.
- Ensure the circle follows clicks on text inputs, checkboxes (both :focus and :checked states), and the submit button.
HTML
<h2>Focus Follower in {PURE CSS}</h2>
<div class="form-wrapper">
<form onsubmit="return false;">
<label for="name">Name</label>
<input type="text" id="name">
<label for="email">Email</label>
<input type="email" id="email">
<label for="password">Password</label>
<input type="password" id="password">
<input type="checkbox" id="check1">
<label for="check1">I accept the terms</label>
<button>Submit</button>
<span class="follow"></span>
</form>
</div>
CSS
* {
box-sizing: border-box;
}
:root {
--spacing: 16px;
--radius: 8px;
}
html,
body {
font-family: "Source Code Pro", Inconsolata, Menlo, monospace;
font-size: 20px;
display: flex;
flex-direction:column;
align-items: center;
justify-content: center;
height: 100%;
margin: 0;
color: #fff;
background-color: cadetblue;
}
.form-wrapper {
position: relative;
height: 500px;
width: 500px;
padding: 80px;
border: 1px dashed #becdcd;
margin: 0 auto;
}
form {
margin: auto;
width: 100%;
max-width: 400px;
position: relative;
}
label {
color: #fff;
}
input[type="text"],
input[type="email"],
input[type="password"] {
display: block;
width: 100%;
margin: 0.5rem 0 1rem 0;
padding: 0.5rem;
font-size: 1rem;
border: 0;
border-radius: 0.125rem 0.25rem;
background-color: hsl(222, 20%, 95%);
position: relative;
}
input[type="checkbox"] {
margin: 0 0.5rem 0 0;
width: 1rem;
height: 1rem;
}
button {
display: block;
padding: 0.5rem 1rem;
border: 0;
border-radius: 0.125rem 0.25rem;
background-color: darkslategrey;
color: #fff;
margin: 2rem 0 0 auto;
position: relative;
}
input:focus,
button:focus {
outline: 0;
}
/* Follower element styling */
.follow {
position: absolute;
width: calc(var(--radius) * 2);
height: calc(var(--radius) * 2);
background-color: darkslategrey;
border-radius: 50%;
pointer-events: none;
z-index: 1;
opacity: 0;
transition: transform 0.3s ease, opacity 0.2s ease;
transform: translateX(0) translateY(0);
left: 0;
top: 0;
}
/* Position follower for each focused or checked element */
#name:focus ~ .follow {
transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
translateY(2.35rem);
opacity: 1;
}
#email:focus ~ .follow {
transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
translateY(7.25rem);
opacity: 1;
}
#password:focus ~ .follow {
transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
translateY(12rem);
opacity: 1;
}
#check1:focus ~ .follow,
#check1:checked ~ .follow {
transform: translateX(calc(-1 * var(--spacing) - var(--radius)))
translateY(14.5rem);
opacity: 1;
}
button:focus ~ .follow {
transform: translateX(calc(-1 * var(--spacing) - var(--radius) + 12.8rem))
translateY(18.15rem);
opacity: 1;
}

Top comments (0)