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

  1. Preheat oven
  2. Mix ingredients
  3. 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).

  • ul common defaults: disc, circle, square
  • ol common 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-type can 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;
}
  
  1. Wake up
  2. Drink water
  3. Write CSS
  4. 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 ::marker with text/emoji and change font-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.
  • ::marker is perfect for text-like markers.
  • ::before gives you full pixel control for images.
Learn more about ::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;
}
  
  1. Pick a base list style.
  2. Decide if you need custom markers.
  3. 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;
}
  
  1. Planning
    1. Goals
    2. Constraints
  2. Build
    1. HTML structure
    2. CSS styling
  3. Ship
    1. Test
    2. Deploy
    3. 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;
}
  
  1. Plan
  2. Build
  3. Ship

Quick Debugging Checklist (When List Styles “Don’t Work”)

  • Markers missing? Check if you (or a reset) applied list-style: none; to ul or ol.
  • Indentation weird? Remember that browsers add default padding-left and margins to lists.
  • Marker color not changing? Use li::marker (not li) 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-reset and the child items have counter-increment.

CSS List Style Wrap-Up

You now have the full list-styling toolkit:

  • list-style-type for built-in bullets and numbering systems.
  • list-style-position for alignment behavior with wrapped lines.
  • list-style-image for quick image markers (limited control).
  • ::marker for 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.