In HTML, most links are <a> elements with an href attribute. Browsers give these elements default styling (usually blue and underlined), plus special styling for states like “visited”.

Your job with CSS is basically to:

  • Choose a readable color.
  • Decide how (or whether) to underline.
  • Make hover/focus/active states obvious (and accessible).
  • Keep things consistent across your site.

Links can be in different states. The classic order is: LVHA:

  1. :link (a normal unvisited link)
  2. :visited (a link you’ve visited before)
  3. :hover (mouse over)
  4. :active (while clicking / pressing)

If you write your CSS in the wrong order, later rules can unintentionally override earlier ones. The safest approach is: write them in LVHA order.

a:link {
  color: #0b63f6;
}
a:visited {
  color: #6b2fd6;
}
a:hover {
  color: #0747b2;
}
a:active {
  color: #d10f47;
}
  
/* Alternative: group hover+focus so keyboard users get the same “hey!” */
a:link {
  color: #0b63f6;
}
a:visited {
  color: #6b2fd6;
}
a:hover,
a:focus-visible {
  color: #0747b2;
}
a:active {
  color: #d10f47;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  padding: 16px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0 0 12px;
  line-height: 1.5;
}

.note {
  font-size: 14px;
  opacity: 0.8;
}
  

Try visiting a link, then come back: Example.com

Another link: Example.org

Tip: Hover, click, and press Tab.

The most common link styling is setting color. That’s literally the link text color.

You can style links globally with a, or more safely with a class like .link. In real projects, using a class avoids surprising side effects (like changing nav icons, cards, or footers unintentionally).

.link {
  color: #0b63f6;
}
  
.link {
  color: #0b63f6;
}

.link:visited {
  color: #6b2fd6;
}
  
/* “inherit” can be useful when you want links to match surrounding text */
.link {
  color: inherit;
  text-decoration-color: #0b63f6;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  display: grid;
  gap: 12px;
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.panel {
  padding: 16px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0 0 10px;
  line-height: 1.5;
}

.muted {
  color: #333;
}
  

Normal link: Read the docs

Inherit example: This link matches the paragraph

You can style :visited, but browsers intentionally limit what properties are allowed there (privacy reasons). Keep your visited styles simple: usually just color.

Underlines are the classic “this is clickable” signal. You can control them with:

  • text-decoration-line (usually underline)
  • text-decoration-thickness
  • text-underline-offset
  • text-decoration-color
  • text-decoration-style (solid, dotted, wavy, etc.)

Better Underlines With text-decoration

.link {
  color: #0b63f6;
  text-decoration: underline;
}
  
.link {
  color: #0b63f6;
  text-decoration: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}
  
.link {
  color: #0b63f6;
  text-decoration: underline;
  text-decoration-color: rgba(11, 99, 246, 0.45);
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}
  
.link {
  color: #0b63f6;
  text-decoration: underline;
  text-decoration-style: wavy;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  padding: 18px;
  border: 2px solid #111;
  background: #fff;
}

h4 {
  margin: 0 0 10px;
  font-size: 18px;
}

p {
  margin: 0;
  line-height: 1.6;
}
  

Underline styles

Here’s a link you can style: Hover me, click me, admire my underline

Learn more in the CSS Text Decoration Interactive Tutorial.

Removing the underline is easy: text-decoration: none;

The tricky part is: when you remove the underline, you should replace it with another clear “clickable” cue. Color alone can be risky (especially for color-blind users, or low-contrast situations).

Remove Underline and Add a Better Cue

.link {
  color: #0b63f6;
  text-decoration: none;
}
  
/* A common pattern: no underline by default, underline on hover/focus */
.link {
  color: #0b63f6;
  text-decoration: none;
}

.link:hover,
.link:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}
  
/* Another cue: a small background highlight instead of underline */
.link {
  color: #0b63f6;
  text-decoration: none;
  padding: 2px 4px;
  border-radius: 6px;
}

.link:hover,
.link:focus-visible {
  background: rgba(11, 99, 246, 0.12);
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  display: grid;
  gap: 12px;
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.box {
  padding: 16px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0;
  line-height: 1.6;
}
  

A link without underline: Account settings (make sure it still looks clickable)

Links are text, so you can style them like text: font-family, font-size, font-weight, letter-spacing, and more.

Two practical tips:

  • Use inherit if you want links to match surrounding text.
  • If you set a custom font for links, do it intentionally (random link fonts can look like a glitch).
.link {
  font-weight: 700;
}
  
.link {
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
  
.link {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-weight: 600;
}
  
/* “inherit” keeps typography consistent, while still allowing color/decoration changes */
.link {
  font: inherit;
  color: #0b63f6;
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  padding: 16px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0 0 12px;
  line-height: 1.6;
}

.small {
  font-size: 14px;
  opacity: 0.85;
}
  

Download the guide

Typography changes can make links feel “button-like” even without a button.

Once you’ve nailed the basics, you’ll see a few popular “link styles” everywhere:

  • Animated underline
  • Background highlight on hover
  • Button-style links
  • External link indicator

This pattern removes the default underline and replaces it with a custom underline using a background gradient. It animates smoothly on hover/focus.

.link {
  color: #0b63f6;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 0% 3px;
  background-position: 100% 100%;
  padding-bottom: 2px;
  transition: background-size 180ms ease;
}

.link:hover,
.link:focus-visible {
background-size: 100% 3px;
background-position: 0 100%;
} 
/* A variant: start in the center for a “grow outwards” effect */
.link {
  color: #0b63f6;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 0% 3px;
  background-position: 50% 100%;
  padding-bottom: 2px;
  transition: background-size 180ms ease, background-position 180ms ease;
}

.link:hover,
.link:focus-visible {
  background-size: 100% 3px;
  background-position: 0 100%;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.block {
  padding: 18px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0;
  line-height: 1.6;
  font-size: 18px;
}
  

  

Sometimes you want a link to look like a button (for navigation or calls-to-action). You can do that with padding, background, borders, and hover/focus states.

.button-link {
  display: inline-block;
  padding: 10px 14px;
  border: 2px solid #111;
  background: #fff;
  color: #111;
  text-decoration: none;
  font-weight: 700;
  border-radius: 10px;
  transition: transform 120ms ease, box-shadow 120ms ease;
}

.button-link:hover,
.button-link:focus-visible {
transform: translateY(-6px);
box-shadow: 0 6px 0 #111;
} 
/* Filled button variant */
.button-link {
  display: inline-block;
  padding: 10px 14px;
  border: 2px solid #111;
  background: #111;
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  border-radius: 10px;
  transition: transform 120ms ease, filter 120ms ease;
}

.button-link:hover,
.button-link:focus-visible {
  transform: translateY(-2px);
  filter: brightness(1.4);
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  display: grid;
  gap: 12px;
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  padding: 18px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0 0 12px;
  line-height: 1.6;
}

.row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}
  

Links can be styled like buttons, but they still navigate.

Hover is where link styling often becomes “fun”. But don’t forget: not everyone uses a mouse. Whatever you do for :hover, you usually want to do for :focus-visible too.

Hover and Focus Should Match

.link {
  color: #0b63f6;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  transition: color 160ms ease, text-decoration-color 160ms ease;
}

.link:hover,
.link:focus-visible {
color: #0747b2;
text-decoration-color: rgba(7, 71, 178, 0.35);
}

.link:active {
color: #d10f47;
} 
/* A “focus ring” pattern that’s hard to miss */
.link {
  color: #0b63f6;
  text-decoration: none;
  padding: 2px 4px;
  border-radius: 6px;
}

.link:hover {
  background: rgba(11, 99, 246, 0.12);
}

.link:focus-visible {
  outline: 3px solid #111;
  outline-offset: 3px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.panel {
  padding: 18px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0;
  line-height: 1.7;
  font-size: 18px;
}
  

Hover me and try keyboard focus.

Learn more in the CSS :hover Pseudo-Class Interactive Tutorial.

Here are a couple of extra great patterns.

You can add a little “↗” indicator using ::after. This is just decoration.

.external {
  color: #0b63f6;
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}

.external::after {
content: " ↗";
font-size: 0.9em;
} 
/* Only show the indicator on hover/focus */
.external {
  color: #0b63f6;
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}

.external::after {
  content: " ↗";
  opacity: 0;
  transition: opacity 140ms ease;
}

.external:hover::after,
.external:focus-visible::after {
  opacity: 1;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  border: 3px solid #111;
  background: #f6f6f6;
  font-family: system-ui, Arial, sans-serif;
}

.box {
  padding: 18px;
  border: 2px solid #111;
  background: #fff;
}

p {
  margin: 0;
  line-height: 1.6;
  font-size: 18px;
}
  

  
  • Another selector is more specific. Example: .nav a will beat a. Fix by styling in the right place (or using a class on the link).
  • You styled a, but your element isn’t a link. If it’s a <button> or a <span>, it won’t match a.
  • You’re seeing :visited. If you only styled :link, your visited link may still show a different color.
  • Hover is overridden by another rule. Example: you have a:hover but later you wrote a { color: ... }.
  • You’re hovering the wrong element. If you styled .link:hover but forgot the class in HTML, nothing happens.
  • Something is covering the link. A positioned element on top can steal the hover/click.

If you remove underlines, consider adding at least one of these:

  • A hover/focus underline (underline appears on interaction)
  • A background highlight on hover/focus
  • A visible focus ring via :focus-visible
  • Enough contrast (don’t make links “barely different”)

If you remember just a few rules, you’ll style links like a pro:

  • Write link states in LVHA order.
  • Use color for link text color (and keep :visited simple).
  • Underlines are good. If you remove them, replace them with another clear cue.
  • Always treat :hover and :focus-visible like best friends.

Links are everywhere, so good link styling is a must-have skill for any web designer. With a solid grasp of link states, colors, underlines, and hover effects, you can make your links look great and work well for everyone.

Learn more about underline styles in the CSS Underline Interactive Tutorial.