サインインフォームのベストプラクティスを試す

1. このページの目的

サインインフォームのベストプラクティスを試す。

Use cross-platform browser features to build a sign-in form をその通り実装してみる。

2. デモ

Sign in

Eight or more characters, with at least one lowercase and one uppercase letter.

HTML

<form action="#" method="post">

  <h1>Sign in</h1>

  <section>
    <label for="email">Email</label>
    <input id="email" name="email" type="email" autocomplete="username" required autofocus>
  </section>

  <section>
    <label for="password">Password</label>
    <button id="toggle-password" type="button" aria-label="Show password as plain text. Warning: this will display your password on the screhow password</button>
    <input id="password" name="password" type="password" autocomplete="current-password" minlength="8"  aria-describedby="password-constrainquired>
    <div id="password-constraints">Eight or more characters, with at least one lowercase and one uppercase letter.</div>
  </section>

  <button id="sign-in">Sign in</button>

</form>

CSS

:root {
  --desktop-font-size: 16px;
  --mobile-font-size: 22px;
}

body {
  font-family: sans-serif;
  font-weight: 500;
  margin: 10px 20px;
}

button {
  background-color: #eee;
  border: 1px solid #ccc;
  border-radius: 2px;
  color: #444;
  cursor: pointer;
  display: block;
  font-size: 22px; /* fallback */
  font-size: var(--mobile-font-size);
  font-weight: 500;
  margin: 3px 0 0 0;
  padding: 10px;
}

button:hover {
  background-color: #ccc;
  color: black;
}
button#toggle-password {
  background: none;
  border: none;
  cursor: pointer;
  font-weight: 300;
  padding: 0;
  position: absolute;
  top: -4px;
  right: -2px;
}

form {
  margin: 0 auto;
  max-width: 500px;
}

h1 {
  border-bottom: 1px solid #ccc;
  font-size: 28px;
  font-weight: 600;
  margin: 0 0 20px 0;
  padding: 0 0 5px 0;
}

input {
  border: 1px solid #ccc;
  font-size: 22px; /* fallback */
  font-size: var(--mobile-font-size);
  padding: 15px;
  width: 90%; /* fallback */
  width: calc(100% - 30px); /* full width minus padding */
}

input[type=email]:not(:focus):invalid,
input[type=password]:not(:focus):invalid {
  color: red;
  outline-color: red;
}

label {
  display: block;
  font-size: 20px;
  font-size: var(--mobile-font-size);
  font-weight: 500;
  margin: 0 0 3px 0;
}

form section {
  margin: 0 0 20px 0;
  position: relative; /* for password toggle positioning */
}

@media (min-width: 450px) {
  body {
    margin: 50px;
  }
  button {
    font-size: 14px; /* fallback */
    font-size: var(--desktop-font-size);
  }
  h1 {
    font-size: 28px;
    font-size: calc(2 * var(--desktop-font-size));
    font-weight: 500;
    margin: 0 0 80px 0;
  }
  input {
    font-size: 14px; /* fallback */
    font-size: var(--desktop-font-size);
  }
  label {
    font-size: 14px; /* fallback */
    font-size: var(--desktop-font-size);
  }
}
div#password-constraints {
  margin: 5px 0 0 0;
  font-size: 16px;
}

JavaScript

const passwordInput = document.getElementById('password');
const togglePasswordButton = document.getElementById('toggle-password');

togglePasswordButton.addEventListener('click', togglePassword);

function togglePassword() {
  if (passwordInput.type === 'password') {
    passwordInput.type = 'text';
    togglePasswordButton.textContent = 'Hide password';
    togglePasswordButton.setAttribute('aria-label',
      'Hide password.');
  } else {
    passwordInput.type = 'password';
    togglePasswordButton.textContent = 'Show password';
    togglePasswordButton.setAttribute('aria-label',
      'Show password as plain text. ' +
      'Warning: this will display your password on the screen.');
  }
}

passwordInput.addEventListener('input', resetCustomValidity);
function resetCustomValidity() {
  passwordInput.setCustomValidity('');
}

// A production site would use more stringent password testing.
function validatePassword() {
  let message= '';
  if (!/.{8,}/.test(passwordInput.value)) {
    message = 'At least eight characters. ';
  }
  if (!/.*[A-Z].*/.test(passwordInput.value)) {
    message += 'At least one uppercase letter. ';
  }
  if (!/.*[a-z].*/.test(passwordInput.value)) {
    message += 'At least one lowercase letter.';
  }
  passwordInput.setCustomValidity(message);
}

const form = document.querySelector('form');
const signinButton = document.querySelector('button#sign-in');

form.addEventListener('submit', handleFormSubmission);

function handleFormSubmission(event) {
  event.preventDefault();
  validatePassword();
  form.reportValidity();
  if (form.checkValidity() === false) {
  } else {
    // On a production site do form submission.
    alert('Logging in!')
    signinButton.disabled = 'true';
  }
}

3. 参考