How to use list-style-type to control marker appearance (disc, circle, square, decimal, alpha, roman)
Master list-style-position for inside and outside marker placement
Create custom markers using the modern ::marker pseudo-element
Design custom bullets with the ::before pseudo-element for maximum control
Use CSS counters with counter-reset, counter-increment, and counter()
Style nested lists with different markers at each level
Build modern list designs including card-style, checklists, and feature lists
Understand browser support for list styling features
Introduction to List Styling
Lists are fundamental HTML elements used to organize related items, steps, or information. CSS provides powerful tools to transform basic bulleted and numbered lists into visually compelling components that enhance readability and user experience. From simple marker customization to complex counter systems, list styling gives you complete control over how sequential information appears on your page.
The default browser styling for lists is functional but limited. By mastering list styling techniques, you can create everything from elegant numbered steps to interactive checklists and feature lists. These techniques are essential for navigation menus, table of contents, pricing tables, and any content that benefits from structured, sequential presentation.
list-style-type Property
The list-style-type property controls the appearance of list markers. CSS provides a wide range of built-in marker styles for both unordered lists (bullets) and ordered lists (numbers, letters, or Roman numerals). This property is the simplest way to change list markers without requiring pseudo-elements.
Unordered List Markers
Unordered lists typically use bullet points. The three standard bullet styles are disc (filled circle, the default), circle (hollow circle), and square (filled square).
ul {
list-style-type: disc; /* ● filled circle (default) */
}
ul {
list-style-type: circle; /* ○ hollow circle */
}
ul {
list-style-type: square; /* ■ filled square */
}
ul {
list-style-type: none; /* no marker */
}
Ordered List Markers
Ordered lists offer numerous numbering systems including decimal numbers, alphabetic characters, and Roman numerals. You can use lowercase or uppercase variants to match your design needs.
ol {
list-style-type: decimal; /* 1, 2, 3 */
}
ol {
list-style-type: decimal-leading-zero; /* 01, 02, 03 */
}
ol {
list-style-type: lower-alpha; /* a, b, c */
}
ol {
list-style-type: upper-alpha; /* A, B, C */
}
ol {
list-style-type: lower-roman; /* i, ii, iii */
}
ol {
list-style-type: upper-roman; /* I, II, III */
}
list-style-position Property
The list-style-position property determines whether list markers appear inside or outside the list item's content box. This affects text wrapping behavior and is crucial for achieving the desired visual alignment.
Outside Position (Default)
With list-style-position: outside, markers are positioned outside the content box. When text wraps to multiple lines, subsequent lines align with the first line of text, not with the marker. This is the default behavior and typically provides the most readable layout.
Inside Position
With list-style-position: inside, markers are treated as part of the content. When text wraps, subsequent lines start at the same left edge as the marker, creating a different visual effect that can be useful in constrained layouts.
ul {
list-style-position: outside; /* default */
}
ul {
list-style-position: inside;
}
/* Shorthand for both properties */
ul {
list-style: square inside;
}
Custom Markers with ::marker
The ::marker pseudo-element is a modern CSS feature that allows direct styling of list markers. You can change the marker content, color, font size, and font weight without removing the default list structure. This approach maintains semantic HTML while providing enhanced visual control.
Styling Default Markers
You can style existing markers by targeting the ::marker pseudo-element. This is particularly useful for changing the color or size of default bullets or numbers.
The true power of ::marker is the ability to replace default markers with custom content using the content property. You can use Unicode characters, emojis, or custom text.
The ::before pseudo-element provides maximum control over list markers but requires removing the default list styling. This technique involves setting list-style: none and creating custom markers with positioned pseudo-elements. It offers unlimited styling possibilities including gradients, shapes, and animations.
Basic Custom Bullets
To create custom bullets with ::before, remove the default list style, add relative positioning to list items, and create absolutely positioned pseudo-elements for your custom markers.
You can create geometric shapes as bullets using CSS. This technique is perfect for creating colored circles, squares, or triangles that match your design system.
CSS counters provide a powerful way to create custom numbering systems without relying on ordered lists. They work through three properties: counter-reset to initialize a counter, counter-increment to increase its value, and counter() function to display the current value. This system allows for complex numbering schemes with complete styling control.
Basic Counter Implementation
The fundamental pattern for CSS counters involves resetting a counter on the parent element, incrementing it on each child, and displaying the value in a pseudo-element.
ul {
list-style: none;
counter-reset: item; /* Initialize counter named 'item' */
}
li {
counter-increment: item; /* Increase counter by 1 */
}
li::before {
content: counter(item) ". "; /* Display counter value */
font-weight: bold;
color: #2563eb;
margin-right: 8px;
}
Styled Counter Numbers
Since counters use pseudo-elements, you can apply any CSS styling including backgrounds, borders, positioning, and transforms. This enables you to create visually distinctive numbering systems.
Nested lists create hierarchical relationships between items. CSS provides several approaches to differentiate between list levels, from using different marker types at each level to creating custom visual hierarchies with colors and indentation.
Progressive Marker Styles
A common pattern is to use different markers at each nesting level. This provides visual cues about the hierarchy without requiring complex styling.
/* Level 1: filled circle */
ul {
list-style-type: disc;
}
/* Level 2: hollow circle */
ul ul {
list-style-type: circle;
margin-top: 8px;
margin-left: 20px;
}
/* Level 3: square */
ul ul ul {
list-style-type: square;
}
Custom Nested Styling
For more sophisticated nested lists, use descendant selectors with custom markers and colors to create clear visual separation between parent and child items.
Beyond basic bullets and numbers, CSS enables you to transform lists into sophisticated UI components. Modern list designs include card-style layouts, interactive checklists, feature lists with icons, and step-by-step guides. These patterns are commonly used in pricing tables, onboarding flows, and feature showcases.
Card-Style Lists
Card-style lists treat each item as a distinct visual block with backgrounds, shadows, and hover effects. This design pattern works well for navigation, feature lists, and content previews.
Checklists use checkbox-style markers to indicate completion status. While this example shows static styling, the pattern easily extends to interactive implementations with JavaScript.
Step lists combine CSS counters with styled layouts to create instructional content. They typically feature prominent step numbers and generous spacing for readability.