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 Form States: Focus, Validation, disabled, and readonly

CSS Tutorial / CSS Form States: Focus, Validation, disabled, and readonly

Compare form states, create accessible labels and error messages, and inspect which enabled, disabled, and read-only fields enter submitted form data.

CSS Tutorial / CSS Container Queries for Reusable Components

CSS Tutorial / CSS Container Queries for Reusable Components

Reuse one card in main content and sidebar containers, compare nearest and named containers, and verify the baseline layout when a query does not apply.

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 / The CSS Box Model: Content, Padding, Border, and Margin

CSS Tutorial / The CSS Box Model: Content, Padding, Border, and Margin

Measure the four box areas, compare padding shorthand and vertical margin collapse, and inspect the resulting dimensions in DevTools.

CSS Tutorial / CSS Tables: Borders, Sizing, and table-layout

CSS Tutorial / CSS Tables: Borders, Sizing, and table-layout

Style semantic tables, compare automatic and fixed layout with long content, and provide horizontal scrolling when a table needs more space.

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.

CSS Tutorial / CSS Paragraph and List Styling

CSS Tutorial / CSS Paragraph and List Styling

Style paragraphs and ordered or unordered lists, compare inside and outside markers, and check spacing and wrapped text on narrow screens.

CSS Tutorial / CSS Transforms and Transitions

CSS Tutorial / CSS Transforms and Transitions

Compare transform order and origins, add hover and keyboard transitions, and test overflow and reduced-motion behavior.

CSS Tutorial / CSS Overflow, Long Text Wrapping, and Ellipsis

CSS Tutorial / CSS Overflow, Long Text Wrapping, and Ellipsis

Compare scrolling, clipping, long-word wrapping, and single-line ellipsis, including keyboard access and minimum-size issues in layout containers.

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.