Css only animated login form

Viewed 51

I have this animated login form in which when you focus on input or fill up the input the label animates to the top. It works well for the most part when the type of input is text, but when the type of input is email it crashes. The HTML and CSS are following:

form .register-txt_field{
    position: relative;
    border-bottom: 2px solid var(--color-light);
    margin: 30px 0;
  }
  .register-txt_field input{
    width: 100%;
    padding: 0 5px;
    height: 40px;
    font-size: 16px;
    border: none;
    background: none;
    outline: none;
    color: var(--color-light);
  }
  .register-txt_field label{
    position: absolute;
    top: 50%;
    left: 5px;
    color: var(--color-light);
    transform: translateY(-50%);
    font-size: 16px;
    pointer-events: none;
    transition: .5s;
  }
  .register-txt_field span::before{
    content: '';
    position: absolute;
    top: 40px;
    left: 0;
    width: 0%;
    height: 2px;
    background: var(--violet);
    transition: .5s;
  }
  .register-txt_field input:focus ~ label,
  .register-txt_field input:valid ~ label{
    top: -5px;
    color: var(--violet);
  }
  .register-txt_field input:focus ~ span::before,
  .register-txt_field input:valid ~ span::before{
    width: 100%;
  }
  
  input[type="submit"]{
    width: 100%;
    height: 50px;
    background: var(--violet);
    border-radius: 10px;
    font-size: 18px;
    color: var(--color-light);
    font-weight: 700;
    cursor: pointer;
    outline: none;
    border: none;
  }
  input[type="submit"]:hover{
    border-color: var(--violet);
    transition: .5s;
    background-color: inherit;
    outline: none;
  }
  .register-login_link{
    margin: 30px 0;
    text-align: center;
    font-size: 16px;
    color: var(--color-light);
  }
  .register-login_link a{
    color: var(--violet);
    text-decoration: none;
  }
  .register-login_link a:hover{
    text-decoration: underline;
  }
  
<form method="post">
        <div className="register-txt_field">
          <input type="text" required />
          <span></span>
          <label>Name</label>
        </div>
        <div className="register-txt_field">
          <input type="text" required />
          <span></span>
          <label>Email</label>
        </div>
        <div class="register-txt_field">
          <input type="password" required />
          <span></span>
          <label>Password</label>
        </div>
        <Link to={"/login"}>
          <input type="submit" value="Sign Up" />
        </Link>
        <div class="register-login_link">
          Already have an account?{" "}
          <Link to={"/login"}>
            <a href="/signup">Login</a>
          </Link>
        </div>
      </form>

The animation is happening with this part right here:

.register-txt_field input:focus ~ label,
.register-txt_field input:valid ~ label{
 top: -5px;
 color: var(--violet);
 }

whenever the input is focused and the content is valid which is text in this case it works but when the type is email it doesn't until the user puts the correct format of email with @gmail and all. If the user puts something random when the type is email it breaks and the label comes down and merges with the input. I know I explained it in a weird way but if someone can help it will be great.

1 Answers

My solution to this problem is to combine the :placeholder-shown and :not() pseudo classes as shown in the snippet below.

The problem is that :valid relies upon the user input being valid rather than simply being present. For the name and password fields that doesn't matter, whereas the email field is more of an issue here.

This would seem like an easy fix with a pseudo class like :blank or :user-invalid however these have surprisingly terrible browser support.

Most browsers support :placeholder-shown and :not() though, so we can define a placeholder with whitespace on each input and style inputs that aren't showing their placeholder (have user input):

.register-txt_field input:not(:placeholder-shown)~label {}

form .register-txt_field {
  position: relative;
  border-bottom: 2px solid var(--color-light);
  margin: 30px 0;
}

.register-txt_field input {
  width: 100%;
  padding: 0 5px;
  height: 40px;
  font-size: 16px;
  border: none;
  background: none;
  outline: none;
  color: var(--color-light);
}

.register-txt_field label {
  position: absolute;
  top: 50%;
  left: 5px;
  color: var(--color-light);
  transform: translateY(-50%);
  font-size: 16px;
  pointer-events: none;
  transition: .5s;
}

.register-txt_field span::before {
  content: '';
  position: absolute;
  top: 40px;
  left: 0;
  width: 0%;
  height: 2px;
  background: var(--violet);
  transition: .5s;
}

.register-txt_field input:focus~label,
.register-txt_field input:not(:placeholder-shown)~label {
  top: -5px;
  color: var(--violet);
}

.register-txt_field input:focus~span::before,
.register-txt_field input:not(:placeholder-shown)~span::before {
  width: 100%;
}
<form method="post">
  <div class="register-txt_field">
    <input type="text" placeholder=" " required />
    <span></span>
    <label>Name</label>
  </div>
  <div class="register-txt_field">
    <input type="email" placeholder=" " required />
    <span></span>
    <label>Email</label>
  </div>
  <div class="register-txt_field">
    <input type="password" placeholder=" " required />
    <span></span>
    <label>Password</label>
  </div>
</form>

Related