Type something to search...
How to style lists for better readability?

How to style lists for better readability?

To style lists for better readability, give items a little more space between them than lines within a paragraph, keep markers aligned in a hanging indent so the text forms a clean edge, and make bullets or numbers visible but quieter than the text itself. Use unordered lists for items in no particular order, ordered lists for sequences and steps, and description lists for term and definition pairs. Modern CSS lets you style markers directly with ::marker, so you rarely need to remove bullets and rebuild them by hand. Keep nesting shallow, keep items parallel in grammar and length, and make sure any custom styling doesn't strip list semantics from screen readers. Well-styled lists turn dense information into something people can scan in seconds.

Lists are one of the most scanned elements on any page. Readers skim them to find the step they're on, the feature they care about or the requirement they've missed. Default browser styling is serviceable but cramped, and many sites make lists worse by removing markers or crushing the spacing. In this article you'll learn how to choose the right list type, how to set spacing and indentation, how to customise markers, how to style numbered steps and nested lists, and how to avoid the accessibility traps of heavily customised lists.

Choose the Right List Type

HTML gives you three list elements, and picking the right one helps both readers and assistive technology.

  • Unordered list (ul): Items whose order doesn't matter, such as features, ingredients or options.
  • Ordered list (ol): Items where sequence or rank matters, such as instructions, rankings or a timeline.
  • Description list (dl): Pairs of terms and descriptions, such as a glossary, specifications or metadata.

Screen readers announce lists and how many items they contain, for example "list, 5 items". That gives users a sense of scale before they start, which is one reason to use real list markup rather than paragraphs with dashes typed at the start.

<h3>What you need</h3>
<ul>
  <li>A domain name</li>
  <li>Access to your DNS settings</li>
  <li>About 15 minutes</li>
</ul>

<h3>Steps</h3>
<ol>
  <li>Sign in to your registrar.</li>
  <li>Open the DNS settings for your domain.</li>
  <li>Add the new record and save.</li>
</ol>

Spacing Between and Around Items

The default browser style puts no space between list items, so a list of multi-line items reads like a single block. Adding a modest gap between items is the single biggest readability improvement you can make.

.prose ul,
.prose ol {
  margin-block: 0 1.25rem;
  padding-inline-start: 1.5em;
}

.prose li {
  margin-block-end: 0.5em;
  line-height: 1.6;
}

.prose li:last-child {
  margin-block-end: 0;
}

Some guidelines for spacing:

  • Short, one-line items: A small gap of around 0.25em to 0.4em is enough.
  • Multi-line items: Increase the gap to 0.5em to 0.75em so each item is clearly separate.
  • Space around the list: Use the same space above and below as you use between paragraphs, so the list feels part of the text flow.
  • Lead-in sentences: Reduce the space between a sentence ending in a colon and the list that follows, so they read as one unit.
.prose p:has(+ ul),
.prose p:has(+ ol) {
  margin-block-end: 0.5rem;
}

The :has() selector is supported in all current major browsers. Older browsers ignore the rule and keep the normal paragraph margin.

Using Flex or Grid Gap

If your list is laid out with flexbox or grid, for example a list of cards, gap is cleaner than margins:

.feature-list {
  display: grid;
  gap: 0.75rem;
  padding: 0;
  list-style: none;
}

Note that list-style: none has an accessibility side effect in Safari, covered later in this article.

Indentation and the Hanging Indent

Good list typography uses a hanging indent: the marker sits to the left, and every line of the item's text aligns to the same left edge. Browsers do this by default with list-style-position: outside, which is what you want for most content.

ul, ol {
  list-style-position: outside; /* the default */
  padding-inline-start: 1.25em;
}

Setting list-style-position: inside puts the marker in the text flow, so wrapped lines start under the marker rather than under the text. That breaks the clean edge and makes long items harder to scan. Keep it for compact, single-line lists if you use it at all.

How Much to Indent

Indent enough for the marker and a small gap, but not so much that the list looks detached. For bullets, around 1.25em to 1.5em works. Ordered lists that reach double digits need more room, around 2em, or the numbers will be cut off or crowd the text. Using em keeps the indent proportional to the font size.

In some editorial designs, lists hang the markers into the margin so the text aligns with the paragraph edge above:

.prose ul {
  padding-inline-start: 0;
  margin-inline-start: 0;
}

.prose ul > li {
  margin-inline-start: 0;
  list-style-position: outside;
}

This only works if the container has enough space on the left for the markers to sit in, so test it on narrow screens.

Styling Markers With ::marker

The ::marker pseudo-element styles the bullet or number directly. It supports a limited set of properties, including color, font properties, content and white-space.

.prose li::marker {
  color: #6b7280;
}

.prose ol > li::marker {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

Muting marker colour lets the text lead while the marker still guides the eye. Tabular numerals keep numbers the same width so they align neatly as the list grows.

Custom Bullet Characters

You can change the marker shape with list-style-type, which accepts a string:

.checklist {
  list-style-type: "✓  ";
}

.arrows {
  list-style-type: "→  ";
}

.checklist li::marker {
  color: #15803d;
}

Be aware that some screen readers announce string markers, so a check mark may be read aloud as "check mark" before every item. For purely decorative shapes, consider an image or SVG marker instead.

Image and SVG Markers

.ticks {
  list-style-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Ccircle cx='6' cy='6' r='4' fill='%232f6fdb'/%3E%3C/svg%3E");
}

Image markers are harder to size and align precisely. If you need fine control, the older pseudo-element approach still works:

.custom-bullets {
  list-style: none;
  padding-inline-start: 1.5em;
}

.custom-bullets li {
  position: relative;
}

.custom-bullets li::before {
  content: "";
  position: absolute;
  inset-inline-start: -1.1em;
  top: 0.65em;
  width: 0.4em;
  height: 0.4em;
  border-radius: 50%;
  background: #2f6fdb;
}

The top value is tied to the line height, so adjust it if you change line height to keep the bullet centred on the first line.

Styling Numbered Steps

Instructions benefit from prominent numbers. CSS counters let you build styled step numbers while keeping a real ol:

<ol class="steps">
  <li>Download the installer.</li>
  <li>Run it and accept the licence.</li>
  <li>Restart your computer.</li>
</ol>
.steps {
  list-style: none;
  counter-reset: step;
  padding: 0;
}

.steps > li {
  counter-increment: step;
  position: relative;
  padding-inline-start: 2.75rem;
  margin-block-end: 1rem;
  min-height: 2rem;
}

.steps > li::before {
  content: counter(step);
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: #1e3a8a;
  color: #fff;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

If a step list is split by other content, use the start attribute on the second ol so numbering continues, for example start="4". Use the reversed attribute for countdowns. Both attributes affect the browser's built-in list-item counter, but a custom counter like the one above ignores them, so you'd set counter-reset: step 3 on the second list to continue from four.

Nested Lists

Nesting shows relationships, but more than two levels becomes hard to follow. Make nested levels visually distinct:

.prose ul ul {
  list-style-type: circle;
  margin-block: 0.4em 0;
}

.prose ul ul ul {
  list-style-type: square;
}

.prose ol ol {
  list-style-type: lower-alpha;
  margin-block: 0.4em 0;
}

The nested list must sit inside an li, not directly inside the parent ul or ol:

<ul>
  <li>Fruit
    <ul>
      <li>Apples</li>
      <li>Pears</li>
    </ul>
  </li>
  <li>Vegetables</li>
</ul>

Writing Lists That Read Well

Styling only goes so far. The content matters just as much.

  1. Keep items parallel: Start every item with the same part of speech, such as all verbs or all nouns.
  2. Keep items similar in length: One short item among long paragraphs looks like an error.
  3. Use bold lead-ins for long items: A bold phrase followed by a colon lets readers scan the lead-ins and read details only where they need them.
  4. Be consistent with punctuation: Either end every item with a full stop or none, unless the items are complete sentences.
  5. Limit length: Lists of more than about seven to ten items are easier to scan when grouped under subheadings.

Keeping Lists Accessible

A well-known quirk: Safari with VoiceOver removes list semantics from ul and ol elements styled with list-style: none. This was a deliberate decision by WebKit to reduce "list" announcements on navigation menus. If the content really is a list, restore the role explicitly:

<ul class="feature-list" role="list">
  <li>Unlimited projects</li>
  <li>Daily backups</li>
</ul>

Other checks:

  • Don't fake lists: Lines of text with typed bullets or line breaks aren't announced as lists.
  • Contrast for markers: Markers that carry meaning, such as step numbers, should meet the 3:1 non-text contrast guideline at minimum; text inside them needs 4.5:1.
  • Don't use colour alone: A green tick and a red cross need text or an accessible label to explain the difference.

For tabular data that's outgrown a list, see how to design readable tables.


FAQ: Styling Lists

For single-line items, about 0.25em to 0.4em is enough. For items that wrap onto several lines, use around 0.5em to 0.75em so each item is clearly separate. The space around the whole list should match your paragraph spacing.

Use the ::marker pseudo-element, for example setting its color to a grey or brand colour. It works on standard list items in all current major browsers without removing the default bullets.

WebKit removes list semantics from lists styled with list-style none when read by VoiceOver. Add role="list" to the ul or ol element to restore it when the content really is a list.

If each item is a complete sentence, end it with a full stop. If items are short fragments, leave punctuation off. Whatever you choose, be consistent within a list.

Outside places the marker in the margin so wrapped lines align with the first line of text, creating a hanging indent. Inside places the marker in the text flow, so wrapped lines start under the marker. Outside is more readable for most content.

Two levels is a practical limit for most content. Beyond that, readers lose track of the structure. Consider subheadings or splitting the content into separate lists instead.


Conclusion

Readable lists come from a few simple decisions: the right list type, clear space between items, a hanging indent that keeps text aligned and markers that guide the eye without competing with the words. The ::marker pseudo-element and CSS counters let you add personality without abandoning real list markup.

Keep nesting shallow, keep items parallel and concise, and use bold lead-ins when items grow long. Finally, check how your lists behave with a screen reader, especially in Safari when markers are removed. Lists styled this way let readers find what they need quickly and move on.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper