UCSSR
CSS Reference

CSS Button Styles

Complete guide to styling CSS buttons — backgrounds, borders, hover effects, transitions, focus states, and accessibility.

Overview

Buttons are the primary interactive elements in web interfaces. CSS button styling involves background-color, color, border, border-radius, padding, font, box-shadow, and pseudo-classes like :hover, :focus-visible, and :active. Well-styled buttons communicate clickability, provide feedback on interaction, and maintain accessibility for keyboard and screen reader users. This guide covers styling patterns from basic to advanced.

Syntax

button { background: ...; color: ...; border: ...; padding: ...; ... }

Values & Keywords

background-color
Primary visual — use solid colors, gradients, or transparent for ghost buttons.
border
Outline style. border: 2px solid currentColor for outline buttons, border: none for filled.
padding
Internal spacing. Typical: padding: 0.5em 1.5em. Use em to scale with font size.
:hover
Hover state — change background, add shadow, or scale slightly (transform: scale(1.02)).
:focus-visible
Keyboard focus indicator. Always style this for accessibility. Use outline or box-shadow.
:active
Pressed state — slight scale-down (transform: scale(0.98)) or inset shadow.
transition
transition: all 0.2s ease. Smooths state changes between default, hover, and active.

Practical Examples

Primary
Primary filled button
A solid background button with hover darkening, active press, and focus ring. The foundation of any button system.
.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0.625rem 1.25rem;
  font: inherit;
  font-weight: 500;
  color: white;
  background: #3b82f6;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s, transform 0.15s;
}

.btn-primary:hover {
  background: #2563eb;
}

.btn-primary:active {
  transform: scale(0.98);
}

.btn-primary:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;
}
Ghost
Ghost / outline button
A transparent button with a border that fills on hover. Useful for secondary actions alongside a filled primary button.
.btn-ghost {
  padding: 0.625rem 1.25rem;
  font: inherit;
  font-weight: 500;
  color: #3b82f6;
  background: transparent;
  border: 1.5px solid #3b82f6;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-ghost:hover {
  background: #3b82f6;
  color: white;
}
Icon button
A square button containing only an icon. Equal width and height with centered content. Always add aria-label for accessibility.
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  font: inherit;
  color: #6b7280;
  background: transparent;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-icon:hover {
  color: #1f2937;
  background: #f3f4f6;
  border-color: #d1d5db;
}
Submit
Submit
Button with loading state
Disable the button and show a spinner during async operations. Use pointer-events: none instead of opacity alone to prevent interaction.
.btn-loading {
  position: relative;
  color: transparent;
  pointer-events: none;
}

.btn-loading::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

Try it visually

Use our interactive button CSS generator to experiment with values and see the result in real-time. Copy production-ready CSS, cross-browser CSS, or Tailwind classes with one click.

Open CSS Button Styles Tool

Common Patterns

Button variant system
Define a base button class with shared styles, then create variant classes that override just the visual properties. This keeps your CSS DRY and consistent.
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0.5em 1.25em;
  font: inherit;
  font-weight: 500;
  border: 1.5px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-primary {
  background: #3b82f6;
  color: white;
}

.btn-secondary {
  background: #f1f5f9;
  color: #1e293b;
}

.btn-destructive {
  background: #ef4444;
  color: white;
}

.btn-outline {
  background: transparent;
  border-color: #e2e8f0;
  color: #1e293b;
}
Button group / toolbar
Group related buttons together with shared borders. Remove border-radius on inner edges for a seamless appearance.
.btn-group {
  display: inline-flex;
}

.btn-group .btn {
  border-radius: 0;
}

.btn-group .btn:first-child {
  border-radius: 8px 0 0 8px;
}

.btn-group .btn:last-child {
  border-radius: 0 8px 8px 0;
}

.btn-group .btn + .btn {
  border-left: 1px solid rgba(0, 0, 0, 0.1);
}
Animated hover with pseudo-element
Use a pseudo-element to create a slide-in background effect on hover — more interesting than a simple color change.
.btn-slide {
  position: relative;
  overflow: hidden;
  z-index: 0;
}

.btn-slide::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.1);
  transform: translateX(-100%);
  transition: transform 0.3s;
  z-index: -1;
}

.btn-slide:hover::before {
  transform: translateX(0);
}

Tips & Best Practices

  1. 1

    Always provide :focus-visible styles — never remove the default outline without adding a replacement. Keyboard users rely on visible focus indicators to navigate.

  2. 2

    Use em units for padding so buttons scale proportionally with font size. padding: 0.5em 1.5em adapts to both small and large button variants.

  3. 3

    Maintain a minimum touch target of 44x44px (WCAG 2.5.5). Even if the visual button is smaller, use padding or min-width/min-height to ensure the interactive area meets this threshold.

  4. 4

    Keep transition durations under 200ms for button states. Longer animations feel sluggish and make the UI feel unresponsive.

  5. 5

    Use cursor: pointer and user-select: none on custom buttons. Add -webkit-tap-highlight-color: transparent on mobile to remove the default tap highlight.

Browser Support

All properties universally supported. :focus-visible requires Chrome 86+, Firefox 85+, Safari 15.4+.

Related CSS Guides

CSS Button Styles — FAQ

Common questions about button CSS and how to use it effectively.

How do I remove default button styles?

Use appearance: none; background: none; border: none; padding: 0; font: inherit; cursor: pointer; to reset browser defaults, then apply your custom styles on top.

How do I make a button accessible?

Ensure 4.5:1 color contrast for text, provide :focus-visible styles for keyboard users, use semantic <button> elements (not divs), maintain minimum 44x44px touch targets, and add aria-label for icon-only buttons.

How do I create a gradient button with hover?

Use background-image: linear-gradient(...) with background-size: 200%. On hover, shift background-position to reveal the second half. Alternatively, use a pseudo-element overlay that fades in on hover.

Should I use <button> or <a> for clickable elements?

Use <button> for actions (submit, toggle, open modal). Use <a> for navigation (links to other pages or anchors). The distinction matters for accessibility — screen readers announce them differently, and keyboard handling differs (Enter for links, Enter/Space for buttons).

How do I disable a button properly?

Use the disabled attribute on <button>. Style it with .btn:disabled { opacity: 0.5; cursor: not-allowed; }. Do NOT use pointer-events: none alone — it prevents click but also prevents keyboard interaction and screen reader access.