AD JB Toolbox 01 EN

CSS Tutorial / CSS Link States and Visible Keyboard Focus

Style link states with pseudo-classes such as :link, :visited, :hover, and :focus-visible while keeping links recognizable. Keyboard users need a visible focus indicator, and hover styling alone cannot communicate every interactive state.

Make links recognizable

a {

  text-decoration: underline;

  text-underline-offset: 0.15em;

}

The link is created with an a element containing href. Just coloring the text blue doesn't make it an actual link. Underlining also informs readers who have difficulty distinguishing between colors as to which parts can be moved. text-underline-offset adjusts the spacing between letters and underlines. Here em is based on the font size of the link.

Use a name that describes the connection, such as “Visitor Information,” rather than an unknown destination, such as “Click.” Before making a regular link look like a button, you need to distinguish whether it's navigation or action. Links are suitable for elements that move to another document, and buttons are usually suitable for elements that execute actions on the current screen.

Compare link states and source order

selector Applicable situations Changes seen in the example
a:link Links with unvisited destinations Blue #1756a9
a:visited Destinations that the browser treats as visited Purple #6b438c
a:hover Pointer is over link Red #b53239
a:active While activating a link, e.g. while pressing the mouse Dark red #8a2630
a:link { color: #1756a9; }

a:visited { color: #6b438c; }

a:hover { color: #b53239; }

a:active { color: #8a2630; }

A link can match several states at once: a visited link under the pointer matches both :visited and :hover. With equal specificity and otherwise equal cascade conditions, the later declaration wins for the same property. The order link → visited → hover → active makes the hover and pressed colors observable whether the destination has been visited or not. See CSS Combinators and Pseudo-Classes.

This order doesn't beat all the rules. If you have more specific selectors or other cascade conditions, the results will be different. If the color does not change, check which color declaration is applied in developer tools. :active is not in a state to continue displaying the selected menu. If you need to display the current page menu, consider a separate class or semantic display such as aria-current.

Keep keyboard focus visible

a:focus-visible {

  outline: 3px solid #e58c1f;

  outline-offset: 3px;

}

Focus refers to the object that will receive keyboard input. If the current location is not visible when navigating to a link with Tab, it is difficult for the user to know where to press Enter. :focus-visible applies in situations where the browser determines that displaying focus is necessary. It usually appears in keyboard movements, but not all click/input situations are simply divided into two types. When applying focus principles such as links to input elements, distinguish between the focus of the input window CSS Form States: Focus, Validation, disabled, and readonly.

outline draws the focus outline and outline-offset separates it from the element. Do not remove the default indicator with outline: none unless you provide an adequate replacement. This example retains both the link underline and a visible focus outline. See MDN: :focus visible.

Create the two-file example

Create links.html and visit.html in the same folder. Save the first code as links.html and the next code as visit.html as UTF-8. The first link takes you to the actual separate file, and the second link takes you to the operating hours heading within the current page.

<!doctype html>

<html lang="en">

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Link states exercise</title>

  <style>

    body { margin: 24px; font: 1rem/1.7 sans-serif; color: #333; }

    main { max-width: 65ch; }

    a { text-decoration: underline; text-underline-offset: 0.15em; }

    a:link { color: #1756a9; }

    a:visited { color: #6b438c; }

    a:hover { color: #b53239; }

    a:active { color: #8a2630; }

    a:focus-visible { outline: 3px solid #e58c1f; outline-offset: 3px; }

    nav li + li { margin-block-start: 0.7em; }

  </style>

</head>

<body>

  <main>

    <h1>Small Garden visitor information</h1>

    <nav aria-label="Instruction link"><ul>

      <li><a href="visit.html">Visitor information on a separate page</a></li>

      <li><a href="#hours">Opening hours on this page</a></li>

    </ul></nav>

    <h2 id="hours">Opening hours</h2>

    <p>Plant care takes place in the morning. These times are fictional sample content, not information about a real facility.</p>

    <p>Hover over the links or press Tab to check their colors and outlines.</p>

  </main>

</body>

</html>
<!doctype html>

<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Visitor Information</title></head>

<body><h1>Visitor information page</h1><p>This separate document is opened by the first link.</p><p><a href="links.html">Return to the link exercise</a></p></body></html>

Test links with a mouse and keyboard

  1. Open links.html and hover over the first link. Check to see if it turns red. If you hold down the mouse button, you will see a dark red color. Since the page moves the moment you release it, the active color does not remain after the click.
  2. Open the first link and return to the browser back. Move the pointer off the link and check the visit color. Results may vary under new profiles, private windows, or clear history, and addresses that have already been visited may be visited from the beginning.
  3. Place the pointer outside the link and tab to the first link. Make sure the orange outline appears, then Tab again to the next link. Shift+Tab moves in the opposite order.
  4. With focus on the first link, press Enter. Make sure visit.html opens. When you return, activate the second link with Enter and it should take you to the Operating Hours heading.

The display of visited has privacy restrictions. Some color attributes, such as color, can be used, but the size, image, etc. cannot be freely changed to determine whether a visit has occurred. The browser may not directly tell you the colors visited in getComputedStyle(), etc., so do not judge the visit history based solely on the calculated style value. Detailed restrictions are described in :visited on the MDN and in the privacy statement .

Diagnose missing state changes

  • If the link does not move, check the file name of href and the location of visit.html. First, check whether you put both files in the same folder.
  • If you only see the hover color instead of the visit color, move the pointer off the link. If hover is forcibly turned on in developer tools, turn it off.
  • If the keyboard doesn't move, check if it's a real link with an href. Your browser/operating system's keyboard navigation settings may also have an effect.
  • When the focus line is cut, check the parent element's overflow and surrounding space. On mobile touch, hover may behave differently than on desktop, so essential information is not only shown on hover.

Once you've finished practicing changing the order of the rules, return them to their original order. CSS that has been temporarily modified in developer tools will return to the value saved in the file when you refresh, but browsing history is not reset just by refreshing.

More in This Category
CSS Tutorial / CSS Width, Height, min/max Limits, and box-sizing

CSS Tutorial / CSS Width, Height, min/max Limits, and box-sizing

Compare content-box and border-box sizing, percentage heights, fluid width limits, and the consequences of fixed heights for growing text.

CSS Tutorial / CSS z-index and Stacking Contexts

CSS Tutorial / CSS z-index and Stacking Contexts

Inspect parent and child stacking contexts, compare real overlap examples, and distinguish stacking order from clipping problems.

CSS Tutorial / Check Responsive CSS with Width, Zoom, and Keyboard Tests

CSS Tutorial / Check Responsive CSS with Width, Zoom, and Keyboard Tests

Follow a repeatable browser checklist, test breakpoint boundaries and longer text, and record layout problems before changing CSS rules.

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

Choose basic selectors for a small page, combine conditions correctly, and inspect whether each rule matches the intended elements.

CSS Tutorial / CSS Inheritance, Specificity, and the Cascade

CSS Tutorial / CSS Inheritance, Specificity, and the Cascade

Work through inheritance and conflicting rules, compare specificity and source order, and understand the limits of !important in a simplified example.

CSS Tutorial / Fluid CSS Layouts with min, max, and clamp

CSS Tutorial / Fluid CSS Layouts with min, max, and clamp

Build a bounded fluid layout, compare flexible sizes and spacing, and check that longer content fits without introducing horizontal page scrolling.

CSS Tutorial / Flexbox Alignment, Wrapping, gap, grow, and shrink

CSS Tutorial / Flexbox Alignment, Wrapping, gap, grow, and shrink

Compare Flexbox alignment and wrapping, distribute space with flex values, and prevent long content from blocking item shrinkage.

CSS Tutorial / Pseudo-Elements: ::before and ::after

CSS Tutorial / Pseudo-Elements: ::before and ::after

Add decorative pseudo-elements, compare them with the original page, and keep essential information in HTML while checking keyboard access.

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

Compare original image proportions, cover, contain, and object-position, then test responsive video sizing with a downloadable sample.

CSS Tutorial / CSS Background Colors and Images: cover and contain

CSS Tutorial / CSS Background Colors and Images: cover and contain

Create and load a local background image, compare repetition, cover, contain, and position, and diagnose image-path and cropping problems.