<div class="container">
  <p>
    Input should be a number. A letter will make it invalid. Also a value that is out of range will also match just like <code>:out-of-range</code> would. The styles applied using <code>:out-of-range</code> override the styles applied using <code>:invalid</code>. Try adding <code>:out-of-range</code> styles in the CSS to see this in action.
  </p>
  <input type="number" min="1" max="10" value="8">
  <p>
    Input type email. Email is optional, so it won't be considered :invalid except when you start typing a value that doesn't match a valid email address pattern.
  </p>
  <input type="email">
  <p>
    Input type email. Email is required, so it will be invalid while it is empty and when you type a value that doesn't match a valid email address pattern.
  </p>
  <input type="email" required>
  <p>
    Input type URL. If the value you enter does not match the pattern of a URL, it will apply the invalid styles.
  </p>
  <input type="url">
</div>
body {
  color: #555;
  font-size: 1.2em;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

hr {
  margin: 50px 0;
}

.container {
  margin: 40px auto;
  max-width: 700px;
}

input {
  display: block;
  width: 50%;
  height: 2em;
  background-color: lightgreen;
}

input[type="number"] {
  width: auto;
}

input:invalid {
  background-color: tomato;
}
/*input[type="number"]:out-of-range {
background-color: yellow;
}
input[type="number"]:invalid {
background-color: orange;
}*/

input:invalid:focus {
  outline: 0;
  border: none;
  box-shadow: 0 0 3px 6px rgba(255, 0, 0, 0.3);
}