Skip to main content
L
Loopaloo
Buy Us a Coffee
All ToolsImage ProcessingAudio ProcessingVideo ProcessingDocument & TextPDF ToolsCSV & Data AnalysisConverters & EncodersWeb ToolsMath & ScienceGames
Guides & BlogAboutContact
Buy Us a Coffee
L
Loopaloo

Free online tools for developers, designers, and content creators. Your files are processed in your browser and are never uploaded - no accounts required. A few network utilities (like What's My IP and Currency Converter) call public APIs to do their job and say so on their pages.

support@loopaloo.com

Tool Categories

  • Image Tools
  • Audio Tools
  • Video Tools
  • Document & Text
  • PDF Tools
  • CSV & Data
  • Converters
  • Web Tools
  • Math & Science
  • Games

Company

  • About Us
  • Contact
  • Blog
  • FAQ

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

Support

Buy Us a Coffee

© 2026 Loopaloo. All rights reserved. Built with privacy in mind.

Privacy|Terms|Disclaimer
  1. Home
  2. Web Tools
  3. CSS Button Generator
Add to favorites

CSS Button Generator

Design a CSS button and see every state measured against WCAG on the page colour you name: resting, hover, active, focus and disabled, plus the focus ring and the border.

Runs locally in your browserMore web toolsJump to full guide

Related reading

  • CSS Box Shadows: From Subtle Depth to Dramatic Effects12 min read
  • CSS Layout Mastery: Understanding Flexbox and Grid9 min read

Initializing in your browser…

You might also like

CSS Gradient Generator

Build a CSS gradient and choose the colour space it is interpolated in, with the colour it keeps through the middle measured and shown.

CSS Box Shadow Generator

Design complex box shadows with multi-layer support, inset shadows, visibility toggle, layer reordering, opacity control, and 12 professional presets

CSS Animation Generator

Create custom CSS keyframe animations visually. Add keyframes, adjust timing, and preview animations in real-time.

CSS Button Generator: a worked example

You need a primary call-to-action button for a white page, and you would like to know before it ships whether anyone can read it in every state rather than just the one on your screen.

Button settings

Label "Get started" · Background #2563EB · Text #FFF · 16px, weight 600
Radius 8px · Padding 12/24 · Hover #1D4ED8 · Active #1E40AF · Page #FFFFFF
What CSS Button Generator produces

What it measures, and what it writes

Resting                      5.17:1   passes
Hover                        6.70:1   passes
Active                       8.72:1   passes
Focused                      5.17:1   passes
Disabled                     1.49:1   exempt
Focus ring against the page 17.74:1   passes
Focus ring against the button 3.43:1  passes
Button edge against the page 5.17:1   passes

.button {
  font-size: 16px;
  font-weight: 600;
  color: #ffffff;
  background: #2563eb;
  border: none;
  border-radius: 8px;
  padding: 12px 24px;
  box-shadow: 0px 4px 6px 0px rgba(0, 0, 0, 0.2);
  cursor: pointer;
  transition: background-color 200ms ease, color 200ms ease,
    border-color 200ms ease, box-shadow 200ms ease, transform 200ms ease;
}

.button:hover:not(:disabled) {
  background: #1d4ed8;
  color: #ffffff;
  transform: scale(1.02);
  box-shadow: 0px 6px 6px 0px rgba(0, 0, 0, 0.2);
}

.button:active:not(:disabled) {
  background: #1e40af;
  color: #ffffff;
  transform: scale(1);
}

.button:focus-visible {
  outline: 3px solid #111827;
  outline-offset: 2px;
}

.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .button { transition: none; }
  .button:hover:not(:disabled) { transform: none; }
}

<button type="button" class="button">Get started</button>

The eight numbers come first because they are the part that decides whether the button is usable, and they are the part a generator normally does not produce.

The blue is #2563EB rather than the more familiar #3B82F6, and that is not a taste decision. #3B82F6 with white 16px semibold text is 3.68:1, below the 4.5:1 WCAG AA asks for at that size and weight. Weight 600 is not bold for the large-text rule: large means 24px, or 18.66px at weight 700, and only then does the threshold drop to 3:1. The presets this tool shipped before were measured by rendering their own CSS in a browser and reading the pixels, and ten of the twelve failed at rest on a white page, five failed on hover, and three of them failed at rest while passing on hover, which is the worst arrangement of all: the state everyone sees is the failing one and the state that passes needs a pointer.

The last three rows are not text at all. WCAG 2.2 section 1.4.11 asks for 3:1 on the boundary that identifies a control, and a focus ring has to clear 3:1 against the page and against the button it touches. Those are separate questions with different answers: a grey ring is 4.83:1 against a white page and 1.07:1 against this blue, so a checker that only looks at the page will pass a ring that disappears exactly where it lands. The #111827 ring here is 17.74:1 against the page and 3.43:1 against the button, so it survives both.

The rule set carries the three states hand-written button CSS usually omits. :focus-visible rather than :focus, so a mouse click does not draw a ring while a Tab key does. :hover:not(:disabled), so a disabled button does not light up under the pointer. And a prefers-reduced-motion block that drops the transition and the hover scale, which is the accessibility requirement that a transform on hover actually triggers. The transition names its properties instead of saying all. The markup carries type="button", because a button inside a form without it submits the form.

A button, and the numbers for every state of it

Design a button and see what it measures. Every state it generates is checked against WCAG 2.2 on the page colour you name: resting, hover, active, focused and disabled, plus the focus ring and the border, which are not text and are missed by every check that only looks at the label.

Key features

  • Every state measured against WCAG 2.2: resting, hover, active, focused and disabled
  • All five states rendered at once, because four of them cannot be hovered into view
  • The page colour as an input, so a transparent or translucent button gets a real answer instead of a guess
  • Gradients sampled across their length, with the worst point reported
  • Focus ring checked against the page and against the button, and the border against the page, per WCAG 1.4.11
  • The large text rule applied properly: 24px, or 18.66px at weight 700, and weight 600 is not bold
  • :focus-visible, :active and :disabled in the generated rule, with :hover:not(:disabled)
  • A prefers-reduced-motion block that drops the transition and the hover transform
  • Generated HTML with type="button", so it cannot submit a form by accident
  • A preview built from the same declarations as the output, so the two cannot disagree

How to use

  1. 1Set the page background the button will sit on. Every number below depends on it.
  2. 2Pick a preset or set the colours yourself. All twelve presets pass AA in every state.
  3. 3Read the contrast table: five states, plus the focus ring and the border.
  4. 4Copy the CSS and the HTML. The rule carries hover, active, focus-visible, disabled and a reduced-motion block.

The state you can see is not the state that fails

A button generator has one accuracy claim, that the CSS it hands you is usable, and contrast is where that claim usually breaks. Not on the resting state, which anyone can eyeball, but on the states nobody looks at while designing. The twelve presets this tool shipped before were measured by rendering their own generated CSS in a browser and reading the pixels: ten of the twelve failed WCAG AA at rest on a white page, and five failed on hover. Success was 2.28:1 where 4.5:1 is required. Ghost’s hover was 1.13:1, which is a blue label on a nearly white wash. Three of them, Primary, Danger and 3D, failed at rest and passed once hovered, so the state a reader sees almost all of the time was the failing one and the fix only appeared under a pointer that a touch user does not have.

Every preset here now passes AA in every state, and the numbers are on the page rather than in a claim. Each state is shown at once as its own button, because four of the five cannot be reached by hovering, and each carries its ratio. The measurement accounts for the things that make a label harder to read than a single pair of colours suggests: a gradient background is sampled across its length and the worst point is the one reported, a translucent background is composited onto the page colour first, and a disabled button is measured at its own opacity with both the label and its background composited down.

The page colour is an input rather than an assumption. A transparent or translucent button has no contrast of its own, so a tool that reports one is reporting a guess. Four of the presets are transparent, and asking for the page colour is the difference between "6.70:1, passes" and "2.83:1, fails", which is what the same ghost button measures on white and on a dark page.

Two things that are not text are measured for the same reason. WCAG 2.2 section 1.4.11 asks for 3:1 on the boundary that identifies a control, so the border, or the button edge where there is no border, is checked against the page. And a focus ring has to be visible against the page and against the button it sits next to: a grey ring is 4.83:1 against a white page and 1.07:1 against a blue button, so a check that only looks at the page passes a ring that vanishes exactly where it matters.

The rule set carries the three states a generated button usually leaves out. :focus-visible rather than :focus, so a mouse click does not draw a ring and a Tab key does. :active and :disabled, with the hover rule written as :hover:not(:disabled) so a disabled button does not light up under the pointer. The transition names the properties it animates rather than using transition: all, and a prefers-reduced-motion block drops it along with the hover transform, which is the one accessibility requirement a scale on hover actually triggers. The HTML is generated too, with type="button", because a button inside a form without it submits the form.

The preview and the output are built from the same declarations, so a preview showing a state the CSS does not produce is not possible here. That is checked from the other side as well: the project tests render the generated rule set in a browser, read the pixels of the label and the pixels behind it, and require the ratio the page reports to be the ratio those pixels give. Thirty-six such measurements run across the twelve presets. An opaque background has to agree exactly; a translucent one is allowed one level of 255, because a browser composites through premultiplied 8-bit values and no closed form reproduces its rounding.

One limitation is stated rather than hidden: with a gradient background the :hover rule re-emits the same gradient, so the hover background colour has no effect. The page says so when the background type is a gradient, instead of leaving a control that silently does nothing.

Examples

  • The blue that fails

    #3B82F6 with white text is 3.68:1, below the 4.5:1 that 16px semibold text needs. #2563EB is 5.17:1 and looks near enough identical.

  • A ghost button on two pages

    The same transparent button with a #1D4ED8 label is 6.70:1 on white and 2.83:1 on a dark page. Nothing about the button changed.

  • A gradient under a label

    White on a pink to violet gradient is measured at 33 points along it, and the worst point is the number reported, because that is where the label is hardest to read.

  • A disabled button

    At 50 percent opacity both the label and its background composite onto the page, so the ratio drops. WCAG exempts disabled controls, and the number is shown anyway.

Tips & best practices

  • Set the page background before reading any number. A transparent button’s contrast is a fact about the page, not about the button.
  • Check the hover row and the active row, not just the resting one. A button that fails at rest and passes on hover is failing for everyone who is not pointing at it.
  • A focus ring needs 3:1 against the page and against the button. Dark rings pass against light pages and disappear on dark buttons.
  • 16px at weight 600 is not large text under WCAG. Large means 24px, or 18.66px at weight 700, and only then does the requirement drop to 3:1.
  • With a gradient background, use the scale, shadow or text colour for the hover. The background cannot change.

Practical scenarios

  • Checking a button you already have

    Put its colours in, name the page colour, and read every state. The states that fail are usually hover, active and disabled, because nothing measures them.

  • Design system exploration

    Try a palette and see immediately which shades survive the contrast requirement at the size and weight you are using.

  • Giving a button a keyboard story

    The generated rule has a focus-visible ring measured against both the page and the button, which is the part hand-written button CSS almost always misses.

  • Email template buttons

    The colours and the contrast still apply, though the states do not: most email clients drop :hover and :focus-visible entirely.

Frequently asked questions

Why does my button fail contrast when it looks fine?

Because looking fine is not the test. #3B82F6 with white 16px semibold text is 3.68:1 where WCAG AA asks for 4.5:1, and it is a perfectly readable-looking button. The requirement exists for people whose contrast sensitivity is lower than yours, and the number is the only way to know.

Is 16px bold text large enough to use the 3:1 threshold?

Only at weight 700 and at least 18.66px, or at 24px at any weight. Those are the WCAG definitions of large-scale text. A 16px label at weight 600, which is what most button styles use, is normal text and needs 4.5:1.

Why does the tool ask for the page background?

Because a transparent or translucent button has no contrast of its own. The same ghost button measures 6.70:1 on a white page and 2.83:1 on a dark one, and the only honest way to report either number is to be told which page it is.

Why does changing the hover background do nothing on a gradient button?

Because the :hover rule re-emits the same gradient, so the background cannot change between states. That is a limitation of the generated rule and the page says so as soon as you choose a gradient. Use the scale, the shadow or the text colour for the hover instead.

Will these buttons work in email clients?

The base rule mostly will, since it is standard properties. The states mostly will not: many clients strip :hover, and :focus-visible and :active are not supported anywhere useful in email. Treat the resting state as the whole design there, and check its contrast.

Why :focus-visible instead of :focus?

:focus fires for a mouse click as well as a Tab key, so a ring appears every time anyone clicks the button, which is why so many people remove focus styles entirely. :focus-visible only fires when the browser judges that a focus indicator is wanted, which in practice means keyboard navigation.

Related tools and how they differ

  • CSS Box Shadow Generator: Focuses solely on layered box-shadows; use it when you only need a shadow value, not a whole styled button.
  • CSS Border Radius Generator: Controls each corner radius in px or %; use it for standalone corner rounding when a full button is overkill.
  • CSS Gradient Generator: Builds rich linear, radial, or conic gradients; use it to craft a complex fill, then paste it as the button background.
  • Glassmorphism Generator: Makes a translucent frosted panel with backdrop blur; use it for glass-style buttons or cards needing see-through depth.
  • CSS Animation Generator: Creates @keyframes for continuous motion; use it for looping or entrance animations beyond the simple hover transitions here.
  • CSS Clip Path Generator: Clips an element to a custom polygon; use it for non-rectangular button shapes this rounded-rect tool cannot produce.

Further reading

  • CSS Box Shadows: From Subtle Depth to Dramatic Effects12 min read
  • CSS Layout Mastery: Understanding Flexbox and Grid9 min read

Private by design

This runs as client-side JavaScript. Keys, tokens, payloads, and other inputs never leave your device.