Styling lists and tables
Lists and tables help organize information.
Lists are useful for grouped items, steps, menus, and short sets of related content. Tables are useful for structured data, such as schedules, prices, scores, or comparisons.
Plain HTML lists and tables work, but they often need CSS to become easier to read.
Quick reminder: lists and tables
HTML has two common list types:
<ul>creates an unordered list, usually with bullets.<ol>creates an ordered list, usually with numbers.
Inside both list types, <li> creates each list item.
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>Tables use a few different tags:
<table>creates the table.<tr>creates a table row.<th>creates a header cell.<td>creates a normal data cell.
Use tables for data, not for page layout.
Styling list spacing
Browsers add default spacing to lists.
You can control that spacing with margin and padding.
<ul class="lesson-list">
<li>Read the lesson</li>
<li>Try the example</li>
<li>Practice on your own</li>
</ul>
<style>
.lesson-list {
padding-left: 24px;
line-height: 1.8;
background-color: #eff6ff;
border-radius: 8px;
font-family: Arial, sans-serif;
}
</style>The padding-left creates space for the list markers. The line-height adds breathing room between list items.
List marker position
The list-style-position property controls where the marker sits.
outside: the marker sits outside the text area. This is the default.inside: the marker becomes part of the text line.
<ul class="outside-list">
<li>A longer list item that wraps onto a second line so you can see the marker position.</li>
</ul>
<ul class="inside-list">
<li>A longer list item that wraps onto a second line so you can see the marker position.</li>
</ul>
<style>
ul {
width: 260px;
font-family: Arial, sans-serif;
}
.outside-list {
list-style-position: outside;
}
.inside-list {
list-style-position: inside;
}
</style>Most lists use outside. Use inside only when you want the marker to stay inside the content box.
Changing bullet and number styles
The list-style-type property changes the marker.
For unordered lists, common values include:
disccirclesquare
For ordered lists, common values include:
decimaldecimal-leading-zerolower-alphaupper-roman
<h3>Topics</h3>
<ul class="square-list">
<li>Selectors</li>
<li>Colors</li>
<li>Spacing</li>
</ul>
<h3>Steps</h3>
<ol class="roman-list">
<li>Write HTML</li>
<li>Add CSS</li>
<li>Check the result</li>
</ol>
<style>
.square-list {
list-style-type: square;
}
.roman-list {
list-style-type: upper-roman;
}
</style>Use marker styles that match the meaning of the list. Numbers are best for steps. Bullets are best for simple groups.
Removing default bullets
Sometimes a list is used for structure, but you do not want visible bullets.
A navigation menu is a common example.
<ul class="nav-list">
<li>Home</li>
<li>Lessons</li>
<li>Contact</li>
</ul>
<style>
.nav-list {
list-style-type: none;
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
.nav-list li {
padding: 8px 0;
}
</style>When you remove bullets, also check the default margin and padding. Otherwise, the list may still have unwanted spacing.
Creating custom bullets
You can create simple custom bullets with the ::marker pseudo-element.
This lets you change the marker content and color without adding extra HTML.
<ul class="check-list">
<li>Save your file</li>
<li>Refresh the browser</li>
<li>Check the layout</li>
</ul>
<style>
.check-list {
line-height: 1.8;
font-family: Arial, sans-serif;
}
.check-list li::marker {
content: "✓ ";
color: #16a34a;
font-weight: bold;
}
</style>Keep custom bullets simple. A clear marker is better than a decorative marker that distracts from the content.
Note: changing content inside ::marker needs a modern browser. Older browsers may show the default bullet instead.
Styling table borders
Tables are easier to scan when rows and cells are separated clearly.
You can add borders with the border property.
<table class="basic-table">
<tr>
<th>Language</th>
<th>Use</th>
</tr>
<tr>
<td>HTML</td>
<td>Structure</td>
</tr>
<tr>
<td>CSS</td>
<td>Style</td>
</tr>
</table>
<style>
.basic-table,
.basic-table th,
.basic-table td {
border: 1px solid black;
}
</style>This adds a border around the table and each cell.
Using border-collapse
By default, table cell borders can show small gaps between cells.
The border-collapse property fixes this.
<table class="clean-table">
<tr>
<th>Day</th>
<th>Task</th>
</tr>
<tr>
<td>Monday</td>
<td>Practice CSS</td>
</tr>
<tr>
<td>Tuesday</td>
<td>Build a menu</td>
</tr>
</table>
<style>
.clean-table {
border-collapse: collapse;
font-family: Arial, sans-serif;
}
.clean-table th,
.clean-table td {
border: 1px solid #9ca3af;
padding: 10px;
}
</style>Use border-collapse: collapse; when you want one clean border line between cells.
Adding table padding and alignment
Table text should not touch the borders.
Add padding to <th> and <td> cells.
You can also align content:
text-aligncontrols horizontal alignment.vertical-aligncontrols vertical alignment.
<table class="score-table">
<tr>
<th>Student</th>
<th>Score</th>
</tr>
<tr>
<td>
Alice<br />
Extra practice completed
</td>
<td>92</td>
</tr>
<tr>
<td>Bob</td>
<td>85</td>
</tr>
</table>
<style>
.score-table {
border-collapse: collapse;
font-family: Arial, sans-serif;
}
.score-table th,
.score-table td {
border: 1px solid #d1d5db;
padding: 12px;
vertical-align: middle;
}
.score-table th {
text-align: left;
}
.score-table th:last-child,
.score-table td:last-child {
text-align: right;
}
</style>Text is often easier to read on the left. Numbers are often easier to compare when they align to the right.
Alternating row colors
Long tables are easier to read when every other row has a different background color.
This is often called zebra striping.
Use :nth-child(even) to select every even row.
<table class="striped-table">
<thead>
<tr>
<th>Course</th>
<th>Lessons</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML</td>
<td>12</td>
</tr>
<tr>
<td>CSS</td>
<td>15</td>
</tr>
<tr>
<td>JavaScript</td>
<td>16</td>
</tr>
</tbody>
</table>
<style>
.striped-table {
border-collapse: collapse;
font-family: Arial, sans-serif;
}
.striped-table th,
.striped-table td {
border: 1px solid #d1d5db;
padding: 10px;
text-align: left;
}
.striped-table tbody tr:nth-child(even) {
background-color: #f3f4f6;
}
</style>Using tbody tr:nth-child(even) keeps the alternating color on the data rows, not the header row.
Making tables easier to read
A readable table has clear structure.
Helpful table styling habits:
- Make headers stand out from normal cells.
- Use enough padding inside cells.
- Use borders or row colors to separate data.
- Align similar data in the same way.
- Avoid using tables for page layout.
<table class="readable-table">
<thead>
<tr>
<th>Plan</th>
<th>Price</th>
<th>Best for</th>
</tr>
</thead>
<tbody>
<tr>
<td>Basic</td>
<td>$0</td>
<td>Trying lessons</td>
</tr>
<tr>
<td>Plus</td>
<td>$9</td>
<td>Daily practice</td>
</tr>
</tbody>
</table>
<style>
.readable-table {
border-collapse: collapse;
width: 100%;
font-family: Arial, sans-serif;
}
.readable-table th,
.readable-table td {
border: 1px solid #d1d5db;
padding: 12px;
text-align: left;
}
.readable-table th {
background-color: #1f2937;
color: white;
}
.readable-table tbody tr:nth-child(even) {
background-color: #f9fafb;
}
</style>The header row is dark, the cells have padding, and the alternating row color helps readers follow the data.
Common beginner mistakes
- Using tables for page layout: use tables for data, not for headers, sidebars, or whole page structure.
- Forgetting
border-collapse: table borders may look doubled or separated without it. - Leaving cells cramped: add padding to
<th>and<td>so the text has room. - Removing list markers but keeping old spacing: after
list-style-type: none;, checkmarginandpadding. - Using custom markers that are too decorative: markers should help readers scan the list, not distract them.
Mini practice task
Look at this CSS rule:
What visual effect does this create in a table?
Check the quiz answers when you are ready.
Short quiz with answers
- Which CSS property removes the gap between table cell borders?
- Which
list-style-typevalue removes bullets entirely? - Which property controls whether table cell content sits at the
top,middle, orbottom?
Answers:
border-collapsenonevertical-align
Mini practice task answer: it creates zebra striping by applying a light gray background color to every even data row.
Small challenge
Style the list and table below.
Your goals:
- Hide the default list bullets.
- Remove the default list spacing.
- Add
border-collapseto the table. - Give the table headers a black background and white text.
- Zebra-stripe the even table rows with a light gray background.
<div>
<ul class="nav-menu">
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
<table class="data-table">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>25</td>
</tr>
<tr>
<td>Bob</td>
<td>30</td>
</tr>
<tr>
<td>Charlie</td>
<td>35</td>
</tr>
</tbody>
</table>
</div>
<style>
.nav-menu {
/* Hide list bullets */
/* Remove default spacing */
font-family: Arial, sans-serif;
}
.data-table {
/* Collapse table borders */
font-family: Arial, sans-serif;
}
.data-table th,
.data-table td {
border: 1px solid black;
padding: 8px;
}
.data-table th {
/* Add a black background */
/* Add white text */
}
.data-table tbody tr:nth-child(even) {
/* Add a light gray background */
}
</style>Summary
- Lists use
<ul>,<ol>, and<li>. - Tables use
<table>,<tr>,<th>, and<td>. - Use
list-style-typeto change or remove list markers. - Use
list-style-positionto control whether markers sit outside or inside the text area. - Use
::markerfor simple custom bullets. - Use
border-collapse: collapse;for clean table borders. - Use padding to make table cells easier to read.
- Use
text-alignandvertical-alignto align table content. - Use
tbody tr:nth-child(even)to create alternating row colors.