Tailwind CSS Responsive Design: Breakpoint System & Mobile-First Strategy
Breakpoint System
Tailwind provides 5 default breakpoints. You can use responsive prefixes to apply styles targeting different screen sizes.
| Prefix | Min Width | CSS Media Query | Typical Devices |
|---|---|---|---|
sm: |
640px | @media (min-width: 640px) |
Phone landscape |
md: |
768px | @media (min-width: 768px) |
Tablet |
lg: |
1024px | @media (min-width: 1024px) |
Laptop |
xl: |
1280px | @media (min-width: 1280px) |
Desktop monitor |
2xl: |
1536px | @media (min-width: 1536px) |
Large monitor |
Traditional CSS vs Tailwind The traditional approach requires writing multiple
@mediaqueries and maintaining styles across different files, whereas Tailwind uses prefixes likesm:andmd:to declare responsive styles directly in the HTML.
Mobile-First Strategy
Tailwind adopts a Mobile-First strategy: unprefixed styles apply to the smallest screens by default, and larger breakpoint prefixes override smaller screen styles.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mobile-First Strategy</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-4 md:p-8">
<div class="max-w-6xl mx-auto space-y-8">
<!-- Responsive text -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Font Size</h3>
<p class="text-sm md:text-base lg:text-lg xl:text-xl">
Small screens use text-sm by default, medium screens text-base, large screens text-lg, and extra-large screens text-xl
</p>
</div>
<!-- Responsive padding -->
<div class="bg-blue-100 rounded-lg p-2 sm:p-4 md:p-6 lg:p-8">
<p class="text-center text-blue-800">Responsive padding: p-2 → sm:p-4 → md:p-6 → lg:p-8</p>
</div>
<!-- Responsive show/hide -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Show/Hide</h3>
<div class="block md:hidden bg-red-100 p-4 rounded text-center text-red-700">
Only visible on small screens (block md:hidden)
</div>
<div class="hidden md:block bg-green-100 p-4 rounded text-center text-green-700">
Visible on medium screens and up (hidden md:block)
</div>
</div>
</div>
</body>
</html>
text-sm md:text-lg means 14px on small screens and 18px on medium screens and above.
Responsive Prefix in Practice
Responsive prefixes can be combined with any Tailwind class to achieve layout changes at different screen sizes.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Prefix in Practice</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-4 md:p-8">
<div class="max-w-6xl mx-auto space-y-8">
<!-- Responsive Flex layout -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Flex Layout</h3>
<div class="flex flex-col sm:flex-row gap-4">
<div class="flex-1 bg-blue-100 p-4 rounded text-center">Item 1</div>
<div class="flex-1 bg-blue-200 p-4 rounded text-center">Item 2</div>
<div class="flex-1 bg-blue-300 p-4 rounded text-center">Item 3</div>
</div>
<p class="text-sm text-gray-500 mt-2">Stacked vertically on small screens (flex-col), horizontal on medium screens (sm:flex-row)</p>
</div>
<!-- Responsive Grid columns -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Grid Columns</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<div class="bg-green-100 p-4 rounded text-center">1</div>
<div class="bg-green-200 p-4 rounded text-center">2</div>
<div class="bg-green-300 p-4 rounded text-center">3</div>
<div class="bg-green-400 p-4 rounded text-center">4</div>
<div class="bg-green-500 p-4 rounded text-center text-white">5</div>
<div class="bg-green-600 p-4 rounded text-center text-white">6</div>
<div class="bg-green-700 p-4 rounded text-center text-white">7</div>
<div class="bg-green-800 p-4 rounded text-center text-white">8</div>
</div>
<p class="text-sm text-gray-500 mt-2">grid-cols-1 → sm:grid-cols-2 → lg:grid-cols-3 → xl:grid-cols-4</p>
</div>
<!-- Responsive spacing -->
<div class="bg-white rounded-lg shadow p-4 sm:p-6 md:p-8">
<h3 class="font-semibold mb-2 sm:mb-4 md:mb-6">Responsive Spacing</h3>
<div class="space-y-2 sm:space-y-4 md:space-y-6">
<div class="bg-purple-100 p-4 rounded">Item A</div>
<div class="bg-purple-200 p-4 rounded">Item B</div>
<div class="bg-purple-300 p-4 rounded">Item C</div>
</div>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing multiple CSS blocks like
@media (min-width: 768px) { .grid { grid-template-columns: repeat(2, 1fr); } }, whereas Tailwind accomplishes the same in a single line withgrid-cols-1 md:grid-cols-2 lg:grid-cols-3.
Responsive Images
Responsive images ensure that images display correctly at different screen sizes, avoiding overflow or distortion.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Images</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-4 md:p-8">
<div class="max-w-6xl mx-auto space-y-8">
<!-- Responsive image width -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Image Width</h3>
<img src="https://picsum.photos/1200/400" alt="Responsive image"
class="w-full md:w-3/4 lg:w-1/2 mx-auto rounded-lg">
<p class="text-sm text-gray-500 mt-2 text-center">w-full → md:w-3/4 → lg:w-1/2</p>
</div>
<!-- Responsive image grid -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Responsive Image Grid</h3>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 md:gap-4">
<img src="https://picsum.photos/300/300?random=1" alt="Image 1" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=2" alt="Image 2" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=3" alt="Image 3" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=4" alt="Image 4" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=5" alt="Image 5" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=6" alt="Image 6" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=7" alt="Image 7" class="w-full aspect-square object-cover rounded-lg">
<img src="https://picsum.photos/300/300?random=8" alt="Image 8" class="w-full aspect-square object-cover rounded-lg">
</div>
</div>
</div>
</body>
</html>
w-full to ensure images don't overflow their parent container, combined with object-cover to maintain aspect ratio.
Responsive Tables
Responsive tables can scroll horizontally on small screens, preventing content from being squeezed.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Tables</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-4 md:p-8">
<div class="max-w-6xl mx-auto">
<div class="bg-white rounded-lg shadow p-4 md:p-6">
<h3 class="font-semibold mb-4">Responsive Table</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm md:text-base">
<thead>
<tr class="bg-gray-100">
<th class="p-2 md:p-3 text-left">ID</th>
<th class="p-2 md:p-3 text-left">Name</th>
<th class="p-2 md:p-3 text-left hidden sm:table-cell">Email</th>
<th class="p-2 md:p-3 text-left hidden md:table-cell">Phone</th>
<th class="p-2 md:p-3 text-left">Status</th>
</tr>
</thead>
<tbody>
<tr class="border-b">
<td class="p-2 md:p-3">001</td>
<td class="p-2 md:p-3">Alice</td>
<td class="p-2 md:p-3 hidden sm:table-cell">alice@example.com</td>
<td class="p-2 md:p-3 hidden md:table-cell">138-0000-0001</td>
<td class="p-2 md:p-3"><span class="bg-green-100 text-green-700 px-2 py-1 rounded text-xs">Active</span></td>
</tr>
<tr class="border-b">
<td class="p-2 md:p-3">002</td>
<td class="p-2 md:p-3">Bob</td>
<td class="p-2 md:p-3 hidden sm:table-cell">bob@example.com</td>
<td class="p-2 md:p-3 hidden md:table-cell">138-0000-0002</td>
<td class="p-2 md:p-3"><span class="bg-yellow-100 text-yellow-700 px-2 py-1 rounded text-xs">Pending</span></td>
</tr>
<tr class="border-b">
<td class="p-2 md:p-3">003</td>
<td class="p-2 md:p-3">Charlie</td>
<td class="p-2 md:p-3 hidden sm:table-cell">charlie@example.com</td>
<td class="p-2 md:p-3 hidden md:table-cell">138-0000-0003</td>
<td class="p-2 md:p-3"><span class="bg-red-100 text-red-700 px-2 py-1 rounded text-xs">Disabled</span></td>
</tr>
</tbody>
</table>
</div>
<p class="text-sm text-gray-500 mt-4">Some columns are hidden on small screens; the table scrolls horizontally</p>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing
@mediaqueries to control table column visibility, whereas Tailwind uses class names likehidden sm:table-cellto declare it directly.
Container Queries (@container)
Container queries apply styles based on the parent container's size rather than the viewport size. This is a new feature supported in Tailwind v4.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Container Queries</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-4 md:p-8">
<div class="max-w-6xl mx-auto space-y-8">
<!-- Container query basics -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Container Query Basics</h3>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Small container -->
<div class="@container bg-gray-50 rounded-lg p-4 border-2 border-dashed border-gray-300">
<div class="flex flex-col @md:flex-row gap-4">
<img src="https://picsum.photos/150/150" alt="Avatar" class="w-20 h-20 @md:w-24 @md:h-24 rounded-full object-cover">
<div>
<h4 class="font-semibold @md:text-lg">Username</h4>
<p class="text-gray-600 text-sm @md:text-base">This is a container query example. The layout changes based on the parent container's width.</p>
</div>
</div>
<p class="text-xs text-gray-400 mt-2">Small container: vertical layout</p>
</div>
<!-- Large container -->
<div class="@container bg-gray-50 rounded-lg p-4 border-2 border-dashed border-gray-300">
<div class="flex flex-col @md:flex-row gap-4">
<img src="https://picsum.photos/150/150" alt="Avatar" class="w-20 h-20 @md:w-24 @md:h-24 rounded-full object-cover">
<div class="flex-1">
<h4 class="font-semibold @md:text-lg">Username</h4>
<p class="text-gray-600 text-sm @md:text-base">Container queries use the @container class and prefixes like @md: to apply styles based on the parent container's size.</p>
<div class="hidden @lg:flex gap-2 mt-2">
<span class="bg-blue-100 text-blue-700 px-2 py-1 rounded text-xs">Tag 1</span>
<span class="bg-green-100 text-green-700 px-2 py-1 rounded text-xs">Tag 2</span>
</div>
</div>
</div>
<p class="text-xs text-gray-400 mt-2">Large container: horizontal layout with extra tags</p>
</div>
</div>
</div>
<!-- Container query cards -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Container Query Cards</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="@container bg-gray-50 rounded-lg overflow-hidden border">
<img src="https://picsum.photos/400/200?random=10" alt="Card image" class="w-full h-32 @sm:h-48 object-cover">
<div class="p-4">
<h4 class="font-semibold @sm:text-lg">Card Title</h4>
<p class="text-gray-600 text-sm @sm:text-base mt-2">Container queries let components respond to their own container size rather than the viewport size.</p>
<button class="hidden @sm:block mt-4 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Learn More</button>
</div>
</div>
<div class="@container bg-gray-50 rounded-lg overflow-hidden border">
<img src="https://picsum.photos/400/200?random=11" alt="Card image" class="w-full h-32 @sm:h-48 object-cover">
<div class="p-4">
<h4 class="font-semibold @sm:text-lg">Card Title</h4>
<p class="text-gray-600 text-sm @sm:text-base mt-2">This allows components to respond correctly across different layouts, making them more flexible.</p>
<button class="hidden @sm:block mt-4 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Learn More</button>
</div>
</div>
<div class="@container bg-gray-50 rounded-lg overflow-hidden border">
<img src="https://picsum.photos/400/200?random=12" alt="Card image" class="w-full h-32 @sm:h-48 object-cover">
<div class="p-4">
<h4 class="font-semibold @sm:text-lg">Card Title</h4>
<p class="text-gray-600 text-sm @sm:text-base mt-2">Use the @container class to mark containers, and prefixes like @sm: and @md: to apply styles.</p>
<button class="hidden @sm:block mt-4 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Learn More</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind Traditional container queries require writing
@container (min-width: 400px) { ... }media queries, whereas Tailwind uses the@containerclass and prefixes like@sm:and@md:to declare them directly.
@xs: (20rem), @sm: (24rem), @md: (28rem), @lg: (32rem), @xl: (36rem), @2xl: (42rem).
❓ FAQ
text-sm md:text-base lg:text-lg, larger breakpoints override smaller breakpoint styles.hidden and block. For example, hidden md:block hides on small screens and shows on medium screens; block md:hidden shows on small screens and hides on medium screens.sm:, md:, etc.) respond to viewport width; container queries (@container, @sm:, etc.) respond to parent container width. Container queries are better suited for reusable components that need responsive behavior across different layouts.@theme directive to customize breakpoints. For example, @theme { --breakpoint-tablet: 768px; } then use the tablet: prefix.📖 Summary
- Tailwind provides 5 default breakpoints:
sm:(640px),md:(768px),lg:(1024px),xl:(1280px),2xl:(1536px) - Adopts a Mobile-First strategy where unprefixed styles are the baseline and breakpoint prefixes are used for enhancement
- Prefixes like
sm:flex,md:grid-cols-2, andlg:grid-cols-3can be combined with any class - Use
overflow-x-autofor responsive horizontal table scrolling @containerqueries respond to parent container size, ideal for reusable componentshidden md:blockandblock md:hiddencontrol element visibility across different screens
📝 Exercises
-
⭐ Create a responsive navbar: use a hamburger menu on small screens (
block md:hidden), and show full navigation on medium screens (hidden md:flex) -
⭐⭐ Create a responsive product card grid: 1 column on small screens (
grid-cols-1), 2 columns on medium screens (md:grid-cols-2), 4 columns on large screens (lg:grid-cols-4), with cards that scale up on hover (hover:scale-105) -
⭐⭐⭐ Create a responsive dashboard layout: use container queries for a sidebar component that collapses to icons in narrow containers (
@lg:shows text) and expands to show full menu text in wide containers



