Search code examples
htmlcsscss-selectorscss-transforms

CSS :selectors animation stops working correctly after removing "required" tag from input field


I have the following code, which move the label out of the input field, as soon as the input is focused or valid.

.form-control-placeholder {
  font-family: "Zuric Light";
  color: black;
  position: absolute;
  top: 0;
  padding: 7px 0 0 13px;
  transition: all 200ms;
  opacity: .5;
}

.form-control:focus + .form-control-placeholder,
.form-control:valid + .form-control-placeholder {
  padding: 0;
  transform: translate3d(0, -100px, 0);
  opacity: 1;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>

<div class="form-group">
    <input type="text" id="address2" class="form-control" name="address2" required>
    <label class="form-control-placeholder" for="address2">Address line 2</label>
</div>

As you might see, the required attribute is applied to the input field. But as soon as I remove it, it stops working correctly because of the :valid selector. Without the required attribute, it will be valid all the time.

How do I solve this and can this be achieved with solely CSS?


Solution

  • :valid works only if the input have required attribute. Other way to achieve this is using :placeholder-shown Pseudo class.

    This pseudo class select all input and textarea that currently shows the placeholder text. In order to work, the input element must have the placeholder attribute.

    According to MDN, MS Edge won't support this.

    In this case, You want the label to go up only when input is focussed or it contains some value. So you need to use :not(:placeholder-shown) instead of :placeholder-shown. Otherwise it'll produce inverse effect.

    div{
    position: absolute;
    width:100%;
    top:50px;
    }
    .form-control-placeholder {
      font-family: "Zuric Light";
      color: black;
      position: absolute;
      top: 0;
      padding: 7px 0 0 13px;
      transition: all 200ms;
      opacity: .5;
    }
    
    .form-control:focus+.form-control-placeholder,
    .form-control:not(:placeholder-shown)+.form-control-placeholder {
      padding: 0;
      transform: translate3d(0, -100%, 0);
      opacity: 1;
    }
    <div class="form-group">
      <input type="text" id="address2" class="form-control" ngModel name="address2" placeholder="...">
      <label class="form-control-placeholder" for="address2">Address line 2</label>
    </div>