Links and buttons are the parts of a page people actually click, so they deserve careful styling. A good link is easy to spot in a paragraph. A good button looks pressable, reacts when you hover, shows clearly when it has keyboard focus, and looks unavailable when it's disabled. Getting these details right makes a site feel polished, and getting them wrong makes it confusing and inaccessible.
Links have several states that you can style separately: unvisited, visited, hovered, focused and being clicked. Buttons share most of these states and add a disabled one. In this lesson you'll style each state with pseudo-classes, control underlines with the text-decoration family of properties, and build a reusable button style with primary, secondary and outline variations.
You'll also learn an important rule of thumb: use a link (<a>) when something takes you to another page, and a <button> when it does something on the current page. CSS can make either look like the other, but the HTML element should match what it does.
Link states in the right order
a:link { color: #1d4ed8; } /* not visited yet */
a:visited { color: #6d28d9; } /* visited before */
a:hover { color: #1e40af; } /* mouse over */
a:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; } /* keyboard focus */
a:active { color: #dc2626; } /* being clicked */Write them in this order, often remembered as LoVe HAte (link, visited, hover, active). Each state has the same specificity, so a later rule wins; if :hover came before :visited, hovering over a visited link would do nothing. For privacy, browsers only let :visited change colours, not sizes or backgrounds.
Underlines with text-decoration
| Property | Example | What it does |
|---|---|---|
text-decoration | none | Removes the underline |
text-decoration-color | #93c5fd | Underline colour |
text-decoration-thickness | 2px | Underline thickness |
text-underline-offset | 4px | Gap between text and underline |
Links inside paragraphs should keep an underline, because colour alone isn't enough for people with colour blindness. You can still make it subtle and attractive with a lighter colour and an offset, then make it bolder on hover. In navigation bars and buttons, where the context makes it obvious, removing the underline is fine.
Building a button style
.btn {
display: inline-block;
padding: 10px 18px;
border: 2px solid transparent;
border-radius: 8px;
background: #16a34a;
color: white;
font: inherit;
font-weight: 600;
text-decoration: none;
cursor: pointer;
}display: inline-blocklets a link styled as a button take padding properly.- A transparent border keeps solid and outline buttons the same size.
font: inheritstops buttons from using the browser's small system font.cursor: pointershows the hand cursor. Add:hover,:focus-visible,:activeand:disabledstates on top.
Focus styles for keyboard users
Many people navigate with the keyboard, pressing Tab to move between links and buttons. The focus ring shows where they are. Never remove it with outline: none unless you replace it. :focus-visible shows a ring for keyboard users but not for mouse clicks, which gives you the best of both:
.btn:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }CSS Links and Buttons Syntax
Link and button states
a { color: #1d4ed8; text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }
.btn { padding: 10px 18px; border-radius: 8px; cursor: pointer; }
.btn:hover { background: #15803d; }
.btn:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }CSS Links and Buttons Summary
- Style link states in the order
:link,:visited,:hover,:focus-visible,:active. - Keep underlines in body text; style them with
text-decoration-color,thicknessandtext-underline-offset. - A button style needs padding, a border, a radius,
font: inheritandcursor: pointer. - Never remove focus outlines without a replacement;
:focus-visibletargets keyboard users. - Use
<a>for navigation and<button>for actions, then style either as needed.
CSS Links and Buttons Examples
Each example runs in the page. Edit the code and press Run to see what changes.
Attractive text links
Hover the links, then press Tab to see the focus ring.
<p>Read our <a href="#">delivery guide</a> or browse the <a href="#">full menu</a> before you order.</p>p { font: 18px/1.6 Georgia, serif; }
a {
color: #1d4ed8;
text-decoration-color: #93c5fd;
text-decoration-thickness: 2px;
text-underline-offset: 4px;
transition: text-decoration-color 0.2s;
}
a:hover { text-decoration-color: currentColor; }
a:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 3px; border-radius: 2px; }Line-by-line explanation
- Lines 4 to 7A light blue underline set a little below the text.
- Line 8The underline colour fades smoothly on hover.
- Line 11On hover the underline turns the same colour as the text.
- Line 12Keyboard users get a clear outline.
A button set with variations
<button class="btn">Save</button>
<button class="btn secondary">Preview</button>
<button class="btn outline">Cancel</button>
<button class="btn" disabled>Sending</button>
<a class="btn" href="#">View plans</a>.btn {
display: inline-block;
padding: 10px 18px;
margin: 4px;
border: 2px solid transparent;
border-radius: 8px;
background: #16a34a;
color: white;
font: 600 15px sans-serif;
text-decoration: none;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
}
.btn:hover { background: #15803d; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
.secondary { background: #1f2937; }
.secondary:hover { background: #111827; }
.outline { background: transparent; color: #16a34a; border-color: #16a34a; }
.outline:hover { background: #f0fdf4; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }Line-by-line explanation
- Lines 1 to 13One base class holds everything the buttons share.
- Lines 15 to 17Hover, press and keyboard focus states.
- Lines 19 to 22Variations only change colours.
- Line 24Disabled buttons look faded and show a not-allowed cursor.
An icon button with a large tap area
<button class="icon-btn" aria-label="Close">✕</button>
<button class="pill">Add to basket <span>+</span></button>.icon-btn {
min-width: 44px;
min-height: 44px;
border: 0;
border-radius: 50%;
background: #f3f4f6;
font-size: 18px;
cursor: pointer;
}
.icon-btn:hover { background: #e5e7eb; }
.pill {
display: inline-flex; align-items: center; gap: 8px;
padding: 10px 20px; border: 0; border-radius: 999px;
background: #f97316; color: white; font: 600 15px sans-serif; cursor: pointer;
}
.pill span { font-size: 18px; }Line-by-line explanation
- Lines 2 to 3A 44 by 44 pixel button is easy to tap.
- Line 13Flexbox lines up the text and the plus sign.
- Line 14A radius of 999px makes a pill shape at any size.
Common CSS Links and Buttons Mistakes
Removing the focus outline
button:focus { outline: none; }button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }Without a focus style, keyboard users can't see where they are on the page.
Hover before visited
a:hover { color: red; }
a:visited { color: purple; } /* hover never shows on visited links */a:visited { color: purple; }
a:hover { color: red; }A div that pretends to be a button
/* <div class="btn" onclick="save()">Save</div> */
.btn { cursor: pointer; }/* <button class="btn" type="button" onclick="save()">Save</button> */
.btn { cursor: pointer; }A <div> can't be reached with Tab or pressed with Enter. Style a real <button> instead.
CSS Links and Buttons in Real Projects
Buttons in design systems
Every design system, from GitHub's Primer to Google's Material, starts with a button component that has a few variants (primary, secondary, outline, danger), a few sizes, and hover, focus, active and disabled states. The colour contrast between button text and background is checked against accessibility guidelines (at least 4.5 to 1 for normal text), and tap targets meet minimum sizes for mobile.
CSS Links and Buttons Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Remove the underline from navigation links.
nav a {
: none;
}
text-decoration: none removes underlines.Which pseudo-class styles a link while the mouse is over it?
Which selector shows a focus ring for keyboard users but not mouse clicks?
Which property moves the underline further from the text?
The button should have the hand cursor, inherit the page font, and show a 3px solid outline on keyboard focus instead of none. Fix the CSS.
<div class="page"><button class="btn">Order</button></div>.page { font-family: Georgia, serif; }
.btn { cursor: default; padding: 10px 16px; }
.btn:focus-visible { outline: none; }- Pointer cursor
- Inherits the page font
- Focus ring is defined
CSS Links and Buttons Quiz
5 questions to check what you learned.
Why keep underlines on links inside paragraphs?
- They load faster
- Browsers require them
- Colour alone isn't enough for everyone to spot links
- They help SEO
What is the recommended order for link states?
- hover, link, active, visited
- active, hover, visited, link
- Any order works
- link, visited, hover, active
Why give buttons a transparent border?
- For accessibility
- So solid and outline buttons stay the same size
- It's required
- To add a shadow
When should you use
<a>rather than<button>?- When it takes the user to another page or URL
- When it's blue
- When it submits a form
- When it opens a menu
Which property can
:visitedchange?- color
- font-size
- background-image
- display
CSS Links and Buttons Challenge
A call-to-action button
- Give
.ctapadding: 12px 24px,border-radius: 999px,background: rgb(124, 58, 237)andcolor: rgb(255, 255, 255) - Remove its underline and give it
cursor: pointer - On
:hover, change the background torgb(109, 40, 217) - Add a
:focus-visiblestyle withoutline: 3px solid rgb(245, 158, 11)
<a class="cta" href="#">Start learning</a>.cta { display: inline-block; font: 600 16px sans-serif; }
- Pill-shaped purple button
- White text, no underline
- Pointer cursor
- Hover and focus states