Building good CSS buttons
A well-built button is more than a colored box. It needs comfortable padding and a readable font size, clear contrast between text and background, and distinct states: :hover for pointer users, :focus-visible for keyboard users and :active for the moment it is pressed. This generator writes all of them, plus a prefers-reduced-motion guard that switches off movement for people who have asked their system to reduce animation.
Use display: inline-flex with align-items: center so text and icons line up regardless of font metrics, and set line-height explicitly so the button height is predictable. Transition only the properties you change — background-color, color, box-shadow and transform — rather than transition: all, which can animate layout properties by accident and costs more to run.
Use a real <button> element for actions and an <a> link for navigation; the same class works on both. A <div> styled as a button is not focusable and is not announced as a button by screen readers.
How to use the CSS Button Generator
- Start from a preset — Primary, Outline, Pill, Ghost, 3D or Gradient — or edit the default button.
- Set the text, padding, font size, weight and family, then choose text and background colors, a border, radius and shadow.
- Configure the hover color, lift and shadow, the pressed effect and the keyboard focus ring.
- Hover, click and Tab to the preview button on a light, gray or dark background to test every state.
- Rename the class if needed, then copy or download the CSS and copy the HTML snippet.
Example
A minimal accessible primary button:
.btn {
display: inline-flex;
align-items: center;
padding: 12px 24px;
font: 600 16px/1.2 system-ui, sans-serif;
color: #fff;
background-color: #4f46e5;
border: 0;
border-radius: 8px;
cursor: pointer;
transition: background-color 200ms ease;
}
.btn:hover {
background-color: #4338ca;
}
.btn:focus-visible {
outline: 3px solid #a5b4fc;
outline-offset: 2px;
}Accessibility checklist
- Text should reach a contrast ratio of at least 4.5:1 against the button background (3:1 for large, bold text). Check the hover state too.
- Never remove the focus outline without a replacement.
:focus-visibleshows the ring to keyboard users without showing it on every mouse click. - Make touch targets at least 44×44 CSS pixels where possible — padding counts toward the target size.
- Do not rely on color alone to show state; a lift, shadow or underline helps people with color-vision deficiencies.
- Wrap movement such as hover lifts in a
prefers-reduced-motionguard, as the generated CSS does.
Related tools
Fine-tune the elevation with the Box Shadow Generator, design richer backgrounds in the CSS Gradient Generator, or add a loading pulse with the CSS Animation Generator.
Frequently Asked Questions
What is the difference between :focus and :focus-visible?
:focus matches whenever the element has focus, including after a mouse click. :focus-visible only matches when the browser decides a visible indicator is needed — typically keyboard navigation — so you can show a strong ring without distracting mouse users. It is supported in all modern browsers.
How do I make a CSS button with a gradient hover effect?
Gradients cannot be transitioned directly. Make the background twice as wide with background-size: 200% auto and transition background-position on hover, which is what the Gradient preset generates.
Should I use a button or a link?
Use <button type="button"> (or type="submit" in forms) for actions that happen on the page and <a href> for navigation to another URL. Both can share the same CSS class.
Why use transform for the hover lift instead of margin or top?
transform does not affect layout, so neighbouring elements do not move and the browser can animate it on the compositor. Changing margin or top triggers layout on every frame.
Why is there a prefers-reduced-motion block?
Some users experience discomfort from movement and enable "reduce motion" in their operating system. The media query removes the lift and press transforms for them while keeping color changes.