What Is List Style In CSS?
HTML lists come in two main flavors: unordered lists (<ul>) and ordered lists
(<ol>).
By default, <ul> shows bullet points, and <ol> shows numbers.
CSS gives you control over those markers (the bullet/number) with the list-style family:
list-style-type, list-style-position, and list-style-image.
And when the built-in markers aren’t enough? We’ll also learn modern marker styling using ::marker,
plus custom numbering using CSS counters (including nested numbering like 1,
1.1, 1.2, 2…).
.demo ul {
list-style-type: disc;
}
.demo ol {
list-style-type: decimal;
}
.demo ul {
list-style-type: square;
}
.demo ol {
list-style-type: upper-roman;
}
.demo ul {
list-style-type: circle;
}
.demo ol {
list-style-type: lower-alpha;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
display: grid;
gap: 16px;
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.panel {
padding: 14px;
border: 2px solid #111;
border-radius: 12px;
background: #fff;
}
.panel h4 {
margin: 0 0 10px 0;
font-size: 16px;
}
ul,
ol {
margin: 0;
padding-left: 1.5rem;
}
li {
padding: 4px 0;
}
Unordered list
- Milk
- Eggs
- Chocolate (important)
Ordered list
- Preheat oven
- Mix ingredients
- Profit
CSS list-style-type Basics
list-style-type controls the shape (for <ul>) or the counting
system (for <ol>).
You apply it to the list itself (ul / ol) or to individual list items (li).
ulcommon defaults:disc,circle,squareolcommon defaults:decimal,lower-alpha,upper-roman
.menu {
list-style-type: disc;
}
.menu {
list-style-type: square;
}
.menu {
list-style-type: "→ ";
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.menu {
margin: 0;
padding-left: 3.6rem;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding-top: 12px;
padding-bottom: 12px;
}
.menu li {
padding: 6px 0;
}
.note {
margin: 14px 0 0 0;
font-size: 14px;
opacity: 0.85;
}
Yes,
list-style-typecan even be a string. It’s like giving your bullets a tiny personality.
CSS list-style Options (Default Options You’ll Actually Use)
There are many list-style-type values. Here are the ones you’ll see most often.
Think of this as a “starter pack” that covers 95% of real-world list styling.
- Unordered:
disc,circle,square,none - Ordered:
decimal,decimal-leading-zero,lower-alpha,upper-alpha,lower-roman,upper-roman - Bonus: custom strings like
"✓ "or"→ "
.demo ol {
list-style-type: decimal;
}
.demo ol {
list-style-type: decimal-leading-zero;
}
.demo ol {
list-style-type: upper-roman;
}
.demo ol {
list-style-type: lower-alpha;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.card {
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 34px;
}
ol {
margin: 0;
padding-left: 1.8rem;
}
li {
padding: 6px 0;
}
- Wake up
- Drink water
- Write CSS
- Wonder why CSS is like this
The list-style Shorthand
list-style is a shorthand for three properties:
list-style-type, list-style-position, and list-style-image.
Example patterns:
list-style: square;(type only)list-style: inside;(position only)list-style: url(...) inside;(image + position)list-style: none;(turn markers off)
.list {
list-style: square;
}
.list {
list-style: square inside;
}
.list {
list-style: "★ " outside;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
margin: 0;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 14px 14px 4rem;
}
li {
padding: 6px 0;
}
- Spacing changes when position is
inside.- Custom strings can be used as markers.
- Shorthand is convenient, but be explicit when debugging.
CSS list-style: none (Removing Bullets And Numbers)
list-style: none; removes the marker entirely. This is common for navigation menus.
But remember: removing markers also removes the default indentation, so you’ll often reset padding too.
Also: if your list is acting like a menu, it’s still okay to keep semantic HTML <ul>.
Screen readers like semantics.
.nav {
list-style: none;
padding-left: 0;
margin: 0;
}
.nav {
list-style: none;
padding-left: 0;
margin: 0;
display: flex;
gap: 10px;
}
.nav {
list-style: none;
padding-left: 0;
margin: 0;
display:flex;
gap:10px;
}
.nav a {
display: inline-block;
padding: 10px 12px;
border: 2px solid #111;
border-radius: 999px;
background: #fff;
text-decoration: none;
color: #111;
}
.nav a:hover {
background: #111;
color: #fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
CSS list-style-position (inside vs outside)
list-style-position decides where the marker is placed:
- outside (default): the marker sits “outside” the content box of the list item.
- inside: the marker becomes part of the content flow, so long lines align differently.
The difference is easiest to see when list items wrap onto multiple lines.
.list {
list-style-position: outside;
}
.list {
list-style-position: inside;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
margin: 0;
padding-left: 1.8rem;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 14px 14px 4rem;
}
li {
padding: 8px 0;
}
- Wrapping demo: this list item is intentionally long so it wraps to a second line and you can compare alignment.
- Short item.
- Another short item.
CSS list-style Color (Marker Color) With ::marker
There’s no list-style-color property, but modern CSS gives you a better tool:
::marker.
Use ::marker to style the bullet/number itself (color, size, sometimes font).
It’s clean, semantic, and you don’t need extra HTML.
.list li::marker {
color: #d10;
}
.list li::marker {
color: #0a6;
font-size: 1.2em;
}
.list li::marker {
color: #15c;
content: "✦ ";
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
margin: 0;
padding-left: 1.8rem;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 14px 14px 4rem;
}
li {
padding: 6px 0;
}
- Markers can have their own color.
- They can be bigger, too.
- And yes, you can swap the marker with
content.
CSS list-style-image (And Why It’s A Bit Limited)
list-style-image lets you use an image as the marker:
list-style-image: url(...);
The catch: it doesn’t give you much control over size, alignment, or color. Browsers treat it as a marker image with limited styling hooks. So it works, but it’s not the most flexible tool.
.list {
list-style-image: url("https://picsum.photos/18/18");
}
.list {
list-style-image: url("https://picsum.photos/26/26");
}
.list {
list-style-image: url("https://picsum.photos/18/18");
list-style-position: inside;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
margin: 0;
padding-left: 2rem;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 14px 14px 4rem;
}
li {
padding: 8px 0;
}
- Image marker
- Another item
- Wrapping text to show alignment behavior with images as markers
In the real world, you will probably want to use an image with transparency for better results.
CSS list-style-image Size (Practical Ways That Actually Work)
Since list-style-image doesn’t have a “size” property, you typically use one of these approaches:
- Use
::markerwith text/emoji and changefont-size. - Remove default markers and build your own with
::before(full control, works everywhere). - Use an SVG mask (advanced, great for “colorable icon bullets”).
Below are two solid beginner-friendly approaches: (1) ::marker with emoji, and (2) a custom bullet using
::before with a background image you can size.
.list li::marker {
content: "🍪 ";
font-size: 1.2em;
}
.list {
list-style: none;
padding-left: 0;
margin: 0;
}
.list li {
position: relative;
padding-left: 34px;
}
.list li::before {
content: "";
position: absolute;
left: 0.4em;
top: 0.7em;
width: 18px;
height: 18px;
background-image: url("https://interactivecss.com/wp-content/uploads/2026/02/IonLogoCss3.png");
background-size: cover;
background-repeat: no-repeat;
border-radius: 6px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 16px;
padding-left: 54px;
}
.list li {
padding: 8px 0;
}
- Custom marker sizing is about choosing the right technique.
::markeris perfect for text-like markers.::beforegives you full pixel control for images.
::before in the CSS ::before and ::after
Pseudo-Elements Interactive Tutorial.
Custom Bullets With ::marker
If your custom marker can be expressed as text (symbols, arrows, emoji), ::marker is the nicest solution.
It keeps your list semantics intact and usually needs less CSS than the ::before approach.
.list li::marker {
content: "→ ";
}
.list li::marker {
content: "✓ ";
color: #0a6;
font-size: 1.1em;
}
.list li::marker {
content: "⚡ ";
color: #f80;
font-size: 1.2em;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.list {
margin: 0;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 14px 14px 4rem;
}
li {
padding: 7px 0;
}
- Markers can be text.
- They can be colored.
- They can be a vibe.
CSS List Style Number With Counters (Total Control)
Ordered lists are great, but sometimes you want a custom numbering format, custom styling, or nested numbering like: 1, 1.1, 1.2, 2, 2.1…
That’s when you use CSS counters. The idea:
- Create a counter with
counter-reset. - Increase it with
counter-increment. - Display it using
::before
Counters: Basic Numbering
.steps {
list-style: none;
margin: 0;
counter-reset: step;
}
.steps > li {
counter-increment: step;
}
.steps > li::before {
content: counter(step) ". ";
font-weight: 700;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.steps {
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 16px;
display: grid;
gap: 10px;
}
.steps > li {
padding: 8px 0;
border-bottom: 1px dashed rgba(0, 0, 0, 0.25);
}
.steps > li:last-child {
border-bottom: 0;
}
.steps p {
margin: 0;
}
- Pick a base list style.
- Decide if you need custom markers.
- Use counters when the default numbering isn’t enough.
Nested Counters: 1, 1.1, 1.2, 2, 2.1, 2.2
For nested lists, you typically reset a new counter for each level, and then display both levels together. The most important part is indentation and alignment, so the numbering doesn’t wobble around.
.outline {
list-style: none;
padding-left: 0;
margin: 0;
counter-reset: section;
}
.outline > li {
counter-increment: section;
padding-left: 60px;
}
.outline > li::before {
content: counter(section) ".";
width: 48px;
text-align: right;
font-weight: 800;
}
.outline > li > ol {
list-style: none;
padding-left: 0;
margin: 10px 0 0 0;
counter-reset: sub;
}
.outline > li > ol > li {
counter-increment: sub;
padding-left: 60px;
}
.outline > li > ol > li::before {
content: counter(section) "." counter(sub) " ";
text-align: right;
font-weight: 800;
}
.outline {
list-style: none;
padding-left: 0;
margin: 0;
counter-reset: section;
}
.outline > li {
counter-increment: section;
padding-left: 70px;
}
.outline > li::before {
content: counter(section) ".";
font-weight: 800;
border: 2px solid #111;
border-radius: 999px;
padding: 2px 10px;
background: #fff;
margin-right: 6px;
}
.outline > li > ol {
list-style: none;
padding-left: 0;
margin: 12px 0 0 0;
counter-reset: sub;
}
.outline > li > ol > li {
counter-increment: sub;
padding-left: 70px;
}
.outline > li > ol > li::before {
content: counter(section) "." counter(sub);
font-weight: 800;
border: 2px solid #111;
border-radius: 999px;
padding: 2px 10px;
background: #fff;
margin-right: 10px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.outline {
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 16px;
display: grid;
gap: 12px;
}
.outline li {
padding: 6px 0;
}
.outline p {
margin: 0;
}
.outline ol li {
padding: 6px 0;
}
.label {
font-size: 13px;
opacity: 0.85;
margin: 0 0 10px 0;
}
- Planning
- Goals
- Constraints
- Build
- HTML structure
- CSS styling
- Ship
- Test
- Deploy
- Celebrate responsibly
Learn much more about CSS Counters in the CSS Counters Interactive Tutorial.
Common Recipes
Recipe: Checklist Bullets
A classic: remove the default marker and add your own. This makes the “marker” align beautifully and remain consistent.
.checklist {
list-style: none;
padding-left: 0;
margin: 0;
}
.checklist li {
padding-left: 34px;
}
.checklist li::before {
content: "✓";
margin-right: 10px;
border: 2px solid #111;
border-radius: 7px;
place-items: center;
font-weight: 900;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.checklist {
background: #fff;
border: 2px solid #111;
border-radius: 12px;
padding: 14px 16px;
}
.checklist li {
padding: 8px 0;
}
- Use semantic HTML lists.
- Style markers intentionally.
- Keep spacing consistent.
Recipe: Fancy Ordered List Using ::marker
If you want styled numbers without full counter logic, ::marker is a great middle ground.
You keep the normal <ol> behavior, but you get a nicer marker.
.fancy {
list-style-type: decimal;
}
.fancy li::marker {
font-weight: 900;
color: #15c;
}
.fancy {
list-style-type: upper-roman;
}
.fancy li::marker {
font-weight: 900;
color: #d10;
font-size: 1.1em;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 920px;
padding: 18px;
border: 3px solid #111;
border-radius: 16px;
background: #f6f6f6;
font-family: system-ui, Arial, sans-serif;
}
.fancy {
margin: 0;
background: #fff;
border: 2px solid #111;
border-radius: 12px;
}
.fancy li {
padding: 8px 0;
}
- Plan
- Build
- Ship
Quick Debugging Checklist (When List Styles “Don’t Work”)
- Markers missing? Check if you (or a reset) applied
list-style: none;toulorol. - Indentation weird? Remember that browsers add default
padding-leftand margins to lists. - Marker color not changing? Use
li::marker(notli) to style the marker. - list-style-image not sizing? That’s normal. Switch to
::before(image background) or::marker(text markers). - Nested numbering off? With counters, make sure each nested list has its own
counter-resetand the child items havecounter-increment.
CSS List Style Wrap-Up
You now have the full list-styling toolkit:
list-style-typefor built-in bullets and numbering systems.list-style-positionfor alignment behavior with wrapped lines.list-style-imagefor quick image markers (limited control).::markerfor marker color and custom symbol markers.- Counters for fully custom numbering, including nested formats like 1.1.
Learn more about <ul> styling in particular in the CSS UL Style Interactive Tutorial.
