CSS Tutorial

CSS Tables Tutorial: border-collapse, Striped Rows And Responsive Tables (2026-27 Guide)

By Pramod Behera  ·  Updated: June 2026  ·  14 min read
✅ In this CSS Tutorial - CSS Tables: Complete Guide to Styling HTML Tables

Today we are discuss topic CSS Tables.The HTML <table> element is the correct, accessible way to display genuinely tabular data - price lists, schedules, comparison charts, data reports - but its default browser styling is plain and cramped. CSS transforms a bare table into something clean and readable. In this complete guide you will learn border-collapse and border-spacing, table sizing with width and table-layout, building striped (zebra) rows with :nth-child(), adding row hover effects, creating a sticky table header that stays visible while scrolling, and making any table fully responsive on mobile devices using horizontal scroll containers. Includes live code panels, an interactive table playground, comparison tables, common mistakes, a quiz, and FAQ - everything you need to design professional, accessible data tables.This tutorial or document breaks down the process step by step, using simple language and real-world examples to help you master the skill.

📋 Table of Contents

  1. What Are CSS Tables?
  2. border-collapse Property
  3. border-spacing Property
  4. Table Width & table-layout
  5. Striped (Zebra) Rows
  6. Row Hover Effects
  7. Sticky Table Header
  8. Responsive Tables
  9. CSS Table Properties Reference Table
  10. Best Practices
  11. Common Mistakes to Avoid
  12. Try It Yourself - Interactive Editor
  13. 🎨 Interactive Table Playground
  14. Practice Quiz
  15. Frequently Asked Questions (FAQ)

✅ What Are CSS Tables?

An HTML table is built from <table>, with rows defined by <tr>, header cells by <th>, and data cells by <td>. Grouping rows into <thead> and <tbody> adds semantic structure that both CSS and screen readers can target. CSS itself doesn't create the table, but it controls every visual detail - borders, spacing, row colors, hover states, and responsiveness.

<table>
  <thead>
    <tr>
      <th>Product</th>
      <th>Price</th>
      <th>Stock</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Notebook</td>
      <td>$4.50</td>
      <td>In Stock</td>
    </tr>
  </tbody>
</table>
🔲
border-collapse
Merge or separate adjacent cell borders.
↔️
border-spacing
Gap between cells when borders are separate.
🦓
nth-child rows
Alternating colors for easier scanning.
📱
overflow-x: auto
Horizontal scroll for responsive tables.
💡 Key Concept: Always reach for <table> when your data is genuinely row-and-column structured - it's more accessible to screen readers than recreating a grid with <div>s, and CSS gives you full visual control anyway.

✅ border-collapse Property

By default, table borders are separate - each cell has its own border, creating a doubled-line look at shared edges. border-collapse: collapse; merges adjacent borders into a single clean line:

table {
  border-collapse: collapse;  /* merged, single borders */
}

table {
  border-collapse: separate;  /* default - each cell has its own border */
}

border-collapse: separate

ItemQty
Pen12
Notebook5

border-collapse: collapse

ItemQty
Pen12
Notebook5
💡 Best Practice: Almost every modern, professionally-styled table uses border-collapse: collapse; as one of the very first rules applied - it's the foundation for clean grid lines.

✅ border-spacing Property

border-spacing only has an effect when border-collapse is separate (the default). It controls exactly how much horizontal and vertical gap appears between neighboring cells:

table {
  border-collapse: separate;
  border-spacing: 6px;        /* equal horizontal and vertical gap */
}

table {
  border-collapse: separate;
  border-spacing: 10px 4px;   /* 10px horizontal, 4px vertical */
}
border-spacing - Live Preview
table {
  border-collapse: separate;
  border-spacing: 10px;
}
👁 Live Output
AB
12
ℹ️ Note: border-spacing is silently ignored if border-collapse: collapse; is set, since collapsed borders share a single line with no room for a gap.

✅ Table Width & table-layout

Set width on the <table> to control its overall size, and use table-layout: fixed; to make column widths predictable and based on the <th>/<td> widths rather than content length:

table {
  width: 100%;
  table-layout: fixed;   /* columns size evenly, ignoring content length */
}

th:nth-child(1) { width: 40%; }
th:nth-child(2) { width: 30%; }
th:nth-child(3) { width: 30%; }
⚠️ Performance tip: table-layout: fixed; also makes large tables render faster, since the browser doesn't need to inspect every cell's content before deciding column widths - it uses only the first row (or explicit widths) to set column sizing immediately.

✅ Striped (Zebra) Rows

Alternating row background colors - "zebra striping" - is one of the most effective ways to make a wide data table easier to scan. Achieve it with the :nth-child() pseudo-class:

tbody tr:nth-child(even) {
  background-color: #F0F9FF;
}

tbody tr:nth-child(odd) {
  background-color: #ffffff;
}
EmployeeDepartmentStatus
Pooja SharmaSalesActive
Rohit PhalkeMarketingActive
Riya NairFinanceOn Leave
Suresh VeerIT SupportActive
Megha PatilHRActive
💡 Best Practice: Apply :nth-child() to tbody tr rather than just tr, so the striping logic only counts data rows and doesn't accidentally include the header row in the alternating pattern.

✅ Row Hover Effects

Highlighting the row under the user's mouse pointer makes it much easier to track which row you're reading across a wide table, especially with many columns:

tbody tr:hover td {
  background-color: #E0F2FE;
  transition: background-color 0.15s;
}
ProductCategoryPrice
Wireless MouseElectronics₹699
Office ChairFurniture₹4,299
Notebook PackStationery₹199
LED Desk LampElectronics₹899
ℹ️ Try it: Move your mouse over the rows above - each row highlights individually as you hover, making cross-column reading noticeably easier on data-dense tables.

For long tables, pinning the header row in place while the body scrolls keeps column labels visible at all times. Wrap the table in a scrollable container and apply position: sticky; to the header cells:

.scroll-container {
  max-height: 300px;
  overflow-y: auto;
}

thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background-color: #1E3A5F;   /* must have a background to cover scrolling rows */
}
Order IDCustomerAmount
#1001Ankit Bhat₹2,450
#1002Sneha Kulkarni₹1,200
#1003Vikram Rathod₹3,800
#1004Pooja Mehara₹950
#1005Ramesh Malhotra₹4,600
#1006Divya Patel₹1,750
#1007Arjun Desai₹2,100
💡 Try it: Scroll inside the table box above - notice the header row ("Order ID", "Customer", "Amount") stays pinned at the top while the data rows scroll underneath it.

✅ Responsive Tables

Wide tables can break a mobile layout by forcing horizontal page scroll. The simplest, most reliable fix is to wrap the table in a container with overflow-x: auto;, so only the table itself scrolls horizontally:

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;  /* smooth momentum scroll on iOS */
}

.table-scroll table {
  width: 100%;
  min-width: 600px;   /* prevents columns from squashing too tightly */
}
Order DateProductQuantityUnit PriceTotalPayment MethodStatus
12 Jun 2026Mechanical Keyboard1₹3,499₹3,499UPIDelivered
15 Jun 2026USB-C Hub2₹899₹1,798CardShipped
18 Jun 2026Monitor Stand1₹1,299₹1,299UPIProcessing
⚠️ Try it on mobile: Shrink your browser window or view this on a phone - the table above scrolls horizontally within its own box instead of stretching the entire page width.

✅ CSS Table Properties - Reference Table

PropertyPurposeCommon Values
border-collapseMerge or keep separate adjacent cell borderscollapse, separate
border-spacingGap between cells (only with separate borders)6px, 10px 4px
table-layoutHow column widths are calculatedauto, fixed
:nth-child(even/odd)Target alternating rows for stripingused on tbody tr
position: stickyPin header row while body scrollscombined with top: 0;
overflow-x: autoEnable horizontal scroll on a wrapperused on a container <div>

✅ Best Practices for CSS Tables

✔️ 1) Use Semantic Table Markup
Always structure tables with <thead>, <tbody>, and proper <th scope="col"> attributes - this isn't just good practice, it directly improves how screen readers announce table data.

✔️ 2) Collapse Borders First

table { border-collapse: collapse; width: 100%; }

✔️ 3) Always Wrap Wide Tables for Mobile

.table-scroll { overflow-x: auto; }

✔️ 4) Use Zebra Striping on Data-Heavy Tables
Any table with more than 5-6 rows benefits significantly from alternating row colors via :nth-child() - it reduces eye strain when scanning across long rows.

✔️ 5) Keep Header Background Solid for Sticky Headers
When using position: sticky; on header cells, always give them an opaque background-color - otherwise scrolling content will show through the "sticky" header as it passes underneath.

💡 Pro Tip: Pair vertical-align: middle; on table cells with consistent padding to keep multi-line content visually balanced, especially in tables mixing short and long text cells.

✅ Common Mistakes to Avoid

❌ Mistake 1 - Forgetting border-collapse
Leaving the default border-collapse: separate; often produces an unintentional doubled-border look. Add border-collapse: collapse; as a baseline reset for most tables.
❌ Mistake 2 - No Responsive Wrapper for Wide Tables
A table with many columns and no overflow-x: auto; wrapper will force the entire page to scroll horizontally on mobile, breaking the layout. Always wrap wide tables in a scrollable container.
❌ Mistake 3 - Striping the Header Row Along With Data Rows
Applying :nth-child() to all tr elements (including inside <thead>) can accidentally stripe the header too. Scope the selector to tbody tr instead.
❌ Mistake 4 - Transparent Background on Sticky Headers
position: sticky; without a solid background-color lets scrolling rows show through the header visually. Always set an opaque background on sticky <th> elements.
❌ Mistake 5 - Using a Table for Page Layout Instead of Data
Tables should hold genuinely tabular data, not be used as a layout tool for arranging unrelated page sections - that's what CSS Grid and Flexbox are for, and using tables for layout creates accessibility problems.

✅ Try It Yourself - Interactive CSS Table Editor

Edit the HTML and CSS below to experiment with table styling. Try different border-collapse values, striped rows, or hover effects. The preview updates automatically.

🎨 Interactive CSS Table Editor
👁 Live Preview

✅ 🎨 Interactive Table Playground

Use the controls below to build a custom CSS table style in real time. Adjust border style, header color, row striping, and hover effect - then copy the generated CSS in one click.

🎨 CSS Table Playground
NameScore
Aditi92
Rahul85
Sneha78
Generated CSS
table { border-collapse: collapse; width: 100%; font-size: 14px; } th { background: #1E3A5F; color: #fff; padding: 10px; } td { padding: 10px; border-bottom: 1px solid #e5e7eb; } tbody tr:nth-child(even) { background: #F0F9FF; } tbody tr:hover td { background: #E0F2FE; }
💡 How to use: Adjust the controls and watch the live table preview update instantly. Hover over the preview rows to test the highlight effect. Copy the generated CSS with one click and paste it directly into your stylesheet.

✅ Practice - Yes / No Quiz

1. border-collapse: collapse; merges adjacent table cell borders into a single shared line?

2. border-spacing has a visible effect even when border-collapse is set to collapse?

3. tbody tr:nth-child(even) is used to create alternating striped row colors?

4. A sticky table header needs an opaque background-color, or scrolling rows will show through it?

5. Wrapping a wide table in a container with overflow-x: auto; is a common way to make it responsive?

0/5
Your Score - Keep Practising! 🎯

✅ Frequently Asked Questions (FAQ)

What does border-collapse: collapse do in CSS?
border-collapse: collapse; merges the borders of adjacent table cells into a single shared border line, removing the default gap and doubled-border appearance you get with the default border-collapse: separate. It's one of the very first properties most developers apply when styling a table.
How do I create striped (zebra) rows in a CSS table?
Use the :nth-child() pseudo-class on table rows, e.g. tbody tr:nth-child(even) { background-color: #f5f7fb; }. This applies a background color to every second row, creating the classic alternating zebra-stripe pattern that makes wide tables easier to scan.
How do I make an HTML table responsive on mobile?
The simplest method is to wrap the <table> in a <div> with overflow-x: auto;, which lets the table scroll horizontally on narrow screens instead of squeezing or breaking the layout. For more advanced cases, CSS can also reflow a table into stacked card-like rows using display: block on rows and cells at small breakpoints.
What is the difference between border-collapse and border-spacing?
border-collapse controls whether adjacent cell borders merge into one (collapse) or remain separate with gaps (separate, the default). border-spacing only has an effect when border-collapse is separate, and it controls exactly how much space appears between neighboring cells.
How do I make a table header stay visible while scrolling?
Apply position: sticky; top: 0; to the <th> elements (or the <thead>, depending on browser support) inside a scrollable container. This keeps the header row pinned at the top of the visible area as the user scrolls down through the table body.
Should I use CSS Grid or Flexbox instead of an HTML table for tabular data?
For genuinely tabular data - rows and columns of related data points, like a price comparison or schedule - the semantic <table> element is still the right, most accessible choice. CSS Grid and Flexbox are better suited for general page layout rather than for data that is inherently row-and-column structured, since tables provide built-in semantics for screen readers.
✍️ About the Author - Pramod Behera

Pramod Behera is the founder of LearnToSAP.com and an experienced web development educator. He creates beginner-friendly tutorials on HTML, CSS, SAP SD/MM, and frontend development, helping thousands of learners worldwide build practical skills.