Development

CSS buttons without images, with states that make sense

Style a real button with modern CSS while preserving focus, contrast, disabled behavior, and a comfortable target size.

CSS can give a button shape, depth, and feedback without an image asset. The important foundation is still the HTML element: use a button for an action and an anchor for navigation.

This new tutorial revisits the old “CSS3 buttons” collection with one adaptable style rather than a bundle of decorative examples.

A restrained starting style

.action {
  border: 1px solid #24522e;
  border-radius: .5rem;
  padding: .75rem 1.1rem;
  background: #286333;
  color: #fff;
  font: 600 1rem/1.3 system-ui, sans-serif;
  cursor: pointer;
}
.action:hover { background: #1e4d28; }
.action:focus-visible {
  outline: 3px solid #4c8fdd;
  outline-offset: 3px;
}
.action:disabled { opacity: .65; cursor: not-allowed; }

Use <button type="button" class="action">Save draft</button> for a scripted action, or an appropriate submit type inside a form. Test the colors against the real page background. A contrast value cannot be inferred from a screenshot alone.

Design every state

Default, hover, focus, active, loading, and disabled states should be distinguishable without making the label jump around. Keep enough width for a loading label or icon if the layout must remain stable.

A disabled button cannot explain itself through a tooltip that requires focus. Put the reason nearby when it matters. For asynchronous work, announce the outcome and restore the control on failure.

Keep decoration subordinate

Subtle shadows and gradients can clarify a hierarchy, but a large glossy bevel rarely helps someone decide what to do. Use one primary action in a local group and quieter treatment for secondary actions.

The HTML button reference is the place to check native behavior. CSS should improve the presentation while leaving that behavior intact.