Topic 4.6
Styling Lists and Links
In one line
list-style and ::marker control the bullets and numbers of lists, and link styles are written in the order :link, :visited, :hover, :focus-visible, :active so each state wins at the right moment, while staying easy to spot for everyone.
Think of it like this
A shopping list and signposts. On a list, each item starts with a dot or a number (the marker) so your eye can count the items. A signpost (a link) must look like a signpost: if it blends into the wall, nobody follows it. It also changes when you've already been somewhere (visited), when you point at it (hover), and when you press it (active).
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Marker
- The bullet or number shown before each list item.
- list-style-type
- Which kind of marker a list uses: disc, square, decimal, roman numerals, a string, or none.
- list-style-position
- Whether the marker sits outside the text (default) or inside it, as part of the first line.
- ::marker
- The pseudo-element that styles the marker box of a list item.
- Pseudo-class
- A selector for a state, like
:hoveror:visited, written with one colon. - :visited
- Matches links whose address is in the browser's history.
- :focus-visible
- Matches an element focused in a way that should show a focus ring, usually by keyboard.
- :active
- Matches a link or button while it's being pressed.
- LVHFA
- The order for link state rules: link, visited, hover, focus-visible, active.
Step by step
01Change the markers
Pick a marker type for each list. Ordered lists can count in letters or roman numerals; the start and reversed attributes in HTML still work.
ul.features {
list-style-type: square;
}
ol.steps {
list-style-type: upper-roman;
}
ul.arrows {
list-style-type: "→ ";
}02Colour the markers
::marker styles only the bullet or number, leaving the item text alone.
li::marker {
color: tomato;
font-weight: 700;
}03Reset a list used as a menu
Navigation menus are lists of links. Remove the markers and the browser's padding and margin. Safari with VoiceOver may stop announcing "list, 4 items" once list-style: none is set, so add role="list" in the HTML when the list meaning matters.
nav ul {
list-style: none;
padding: 0;
margin: 0;
}04Style link states in LVHFA order
Write the rules in this order. If :hover came before :visited, a visited link would ignore your hover colour, because the later :visited rule wins.
a:link { color: #1d4ed8; }
a:visited { color: #6d28d9; }
a:hover { color: #1e40af; text-decoration-thickness: 3px; }
a:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
a:active { color: #b91c1c; }05Keep links findable
Inside text, keep the underline and restyle it (Topic 4.4) rather than removing it. In navigation bars, where everything is a link, removing the underline is fine, but keep a clear hover and focus style.
article a {
text-underline-offset: 0.2em;
text-decoration-thickness: 1px;
}
article a:hover {
text-decoration-thickness: 2px;
}Try it yourself
- 1
Try other marker types
In the first example, change
upper-romantolower-alpha, thendecimal-leading-zero, thendevanagari. Predict the second item's marker each time. - 2
Break the order on purpose
In the second example, move the
a:hoverrule abovea:link. Predict: does hovering still change the colour? It doesn't, because the later:linkrule has the same specificity and wins. Put it back. - 3
Check the marker limits
Add
padding: 10px; background: yellow;toli::markerin the first example. Predict what changes. Nothing does: those properties aren't allowed on markers.
Code & diagrams
`getComputedStyle(el, "::marker")` reads the marker's own styles. The 40px padding comes from the browser's built-in stylesheet.
Preview
Console
Nothing logged yet.Expected console output
marker colour: rgb(255, 99, 71)
list-style-type: "→ "
default ul padding: 40pxHover a link, press Tab to focus one with the keyboard, then press and hold the mouse button on one. Each state shows its style. (`display: flex` lays the menu out in a row; it's taught in the Flexbox phase.)
Preview
Console
Nothing logged yet.`::before` can have padding, backgrounds and positions that `::marker` won't accept. Positioning is taught in a later phase; here it pins the tick to the left of each item.
Preview
Console
Nothing logged yet.Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Hover written before visited
Write the link rules as a:hover { color: red; } then a:visited { color: purple; }.
Break #2
Bullets gone but the indent stays
Set only list-style: none; on a menu <ul>.
Break #3
Removing link underlines in body text
Set a { text-decoration: none; } on a page where links are only a slightly different blue from the text.
Myth vs fact
Myth
list-style: none removes all list styling.
Fact
It removes the markers only. The browser's padding and margins stay until you reset them, and some screen readers may drop the list semantics.
Myth
You can style :visited links any way you like.
Fact
Browsers only allow colour changes for :visited and hide the result from JavaScript, to protect your browsing history.
Myth
Removing the focus outline makes the design cleaner and harms nobody.
Fact
Keyboard users rely on it to see where they are. Replace it with a clear :focus-visible style instead of deleting it.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Ordered list numbers are CSS counters: every
lihasdisplay: list-item, which increments a built-in counter namedlist-item. You can usecounter-reset,counter-incrementandcounter()for your own numbering (for example "Step 1:"), and@counter-styleto define new marker systems. - ▸
:visitedstyles are painted with the visited colour, but reading them back (getComputedStyle, element screenshots via canvas) returns the unvisited values. The colour's alpha channel is taken from the unvisited style, so:visitedcan't make a link transparent. - ▸
:focus-visibleuses browser heuristics: keyboard focus shows it, mouse clicks on links and buttons usually don't, and text inputs always do. That's why it replaced the old:focus { outline: none }habit;:focusalone also matches mouse focus. - ▸
WebKit with VoiceOver removes list semantics from lists styled with
list-style: nonethat aren't in anav, a deliberate heuristic against "lists" used only for layout. Addingrole="list"restores it. Check the current WebKit behaviour when it matters to you.
Remember this
- 1
Lists (
<ul>unordered,<ol>ordered, from the HTML course) show a marker before each<li>.list-style-typepicks it:disc(●, the default forul),circle,square,decimal(1, 2, 3, the default forol),decimal-leading-zero(01, 02),lower-alpha,upper-roman, many language systems likedevanagari, a string such as"→ ", ornone.list-style-positionputs the markeroutsidethe text box (default) orinsideit, andlist-style-imageuses a picture. The shorthand islist-style: square inside;. - 2
The browser gives lists
padding-inline-start: 40px(left padding in English) so the outside markers have room, plus top and bottom margins. That's why a list withlist-style: nonestill looks indented: remove the bullets and setpadding: 0(andmargin: 0if needed) for menus and card lists. - 3
::markeris a pseudo-element (Phase 1) for the marker box itself. It accepts only a small set of properties:color, thefont-*properties,content,white-space,direction,unicode-bidi,text-combine-upright, and animations/transitions of those. Soli::marker { color: tomato; font-weight: 700; }works, butpaddingorbackgroundon a marker are ignored. For full control, people uselist-style: noneand draw their own marker withli::before. - 4
Links have states, each a pseudo-class:
:link(not visited yet),:visited(already visited, from the browser's history),:hover(pointer over it),:focus-visible(focused by keyboard), and:active(being pressed). These selectors all have the same specificity (Phase 2), so the one written last wins when several apply. The order that works is L-V-H-F-A::link,:visited,:hover,:focus-visible,:active, remembered as "LoVe Hate Focus Active" or "LoVe HAte". - 5
For privacy,
:visitedis limited: only colour properties (color,background-color,border-color,outline-color,text-decoration-color,column-rule-color, and SVGfill/stroke) can change, andgetComputedStylealways reports the unvisited style. Otherwise a page could read your browsing history by checking which links are styled as visited. - 6
Accessible links: inside paragraphs, keep an underline (or another non-colour cue). WCAG 1.4.1 says colour can't be the only way to tell a link from text; if you remove the underline, the link colour needs at least 3:1 contrast with the surrounding text and a non-colour cue on hover and focus. Never remove focus outlines without replacing them (
:focus-visiblestyles), make link text describe the destination (not "click here"), and give touch targets enough size.
Explain it without notes
Why must link state rules be written in LVHFA order?
Why is :visited restricted, and what can you still change with it?
What can ::marker style, and what do you do when you need more?
How do you keep links accessible if the design wants no underlines?
Practice
Make an ordered list count with lowercase letters and show the letters in bold seagreen.
Turn nav ul into a plain menu without bullets or indentation, and style its links in LVHFA order: blue, purple when visited, underlined on hover, an orange outline on keyboard focus, red while pressed.
Trade-offs
- ↔
::markerkeeps real list semantics and needs little CSS but allows only a few properties; a::beforemarker is fully stylable but needs a reset and care with semantics. - ↔
Underlined links are the most recognisable and accessible; underline-free links look cleaner but need extra contrast and hover/focus cues.
Done when you can
I can change list markers with
list-style-type, position and the shorthand.I can style markers with
::markerand know its limits.I can reset a list for use as a menu.
I can write link states in LVHFA order and explain why.
I know what
:visitedmay change and why.I can keep links and focus states accessible.