<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>详细的自定义错误提示</title>
  <style>
    body {
      font: 1em sans-serif;
      width: 200px;
      padding: 0;
      margin : 0 auto;
    }

    p * {
      display: block;
    }

    input[type=email]{
      -webkit-appearance: none;
      appearance: none;

      width: 100%;
      border: 1px solid #333;
      margin: 0;

      font-family: inherit;
      font-size: 90%;

      box-sizing: border-box;
    }

    /* 自定义的错误格式 */
    input:invalid{
      border-color: #900;
      background-color: #FDD;
    }

    input:focus:invalid {
      outline: none;
    }

    /* 错误信息样式 */
    .error {
      width  : 100%;
      padding: 0;

      font-size: 80%;
      color: white;
      background-color: #900;
      border-radius: 0 0 5px 5px;

      box-sizing: border-box;
    }

    .error.active {
      padding: 0.3em;
    }
  </style>
</head>

<body>
  <form novalidate>
    <p>
      <label for="mail">
        <span>请输入一个电子邮件地址：</span>
        <input type="email" id="mail" name="mail" required minlength="8">
        <span class="error" aria-live="polite"></span>
      </label>
    </p>
    <button>提交</button>
  </form>

  <script>
    // 获取 DOM 节点有很多途径，这里我们获取整个表单，包括邮件输入框和显示出错信息的 <span>。
    const form  = document.getElementsByTagName('form')[0];

    const email = document.getElementById('mail');
    const emailError = document.querySelector('#mail + span.error');

    email.addEventListener('input', function (event) {
      // 每当用户输入信息时，检查表单输入框域是否合法。

      if (email.validity.valid) {
        // 当前显示出错信息的情况下，如果邮件输入框内容合法，则移除错误信息。
        emailError.innerHTML = '';      // 重置消息内容
        emailError.className = 'error'; // 重置消息可见状态
      } else {
        // 如果有错误，则显示对应的出错信息
        showError();
      }
    });

    form.addEventListener('submit', function (event) {
      // 如果表单包含合法数据，则允许提交。

      if(!email.validity.valid) {
        // 否则显示对应的出错信息
        showError();
        // 然后禁止表单通过取消事件提交
        event.preventDefault();
      }
    });

    function showError() {
      if(email.validity.valueMissing) {
        // 如果邮件框为空，则显示下方出错信息。
        emailError.textContent = '请输入一个电子邮件地址。';
      } else if(email.validity.typeMismatch) {
        // 如果邮件框不包含合法的邮件地址，则显示下方出错信息。
        emailError.textContent = '请输入一个有效的电子邮件地址。';
      } else if(email.validity.tooShort) {
        // 如果输入内容过短，则显示下方出错信息。
        emailError.textContent = `电子邮件地址长度至少为 ${ email.minLength } 个字符，当前你输入了 ${ email.value.length } 个字符。`;
      }

      // 设置合适的样式
      emailError.className = 'error active';
    }
  </script>
</body>

</html>
