Tailwind CSS 39 🎨 Media Condition Variants (portrait:, landscape:, motion-safe:, print:)
Not every responsive concern is about screen width. A phone held upright has a different shape than the same phone turned sideways. A user who has enabled reduced motion in their operating system expects animations to be gentler or absent. A printed page has different constraints than a screen — colors may not render, interactive elements are useless, and the layout must fit on paper. These are media conditions, and Tailwind exposes them as variants: portrait:, landscape:, motion-safe:, motion-reduce:, and print:.
These variants are different from breakpoint variants. md: asks how wide the viewport is. portrait: asks about the shape of the viewport. motion-safe: asks about the user’s motion preference. print: asks whether the document is being printed. Each maps to a native CSS media query, and each can be combined with any utility in the framework. The syntax is consistent: a prefix, a colon, and the utility. The mental model is the same: the utility applies only when the condition is true.
The conditions themselves are not new. prefers-reduced-motion, orientation, and print have been CSS media features for years. What Tailwind provides is a naming convention that makes them usable alongside every other utility, without writing a single @media block. The variants compose with each other and with the breakpoint variants, so a single class list can express a layout that changes by width, orientation, and motion preference simultaneously.
This chapter covers three areas. First, why media condition variants exist — what each condition represents and the user experience problem it addresses. Second, how each variant works — the portrait: and landscape: orientation variants, the motion-safe: and motion-reduce: variants for vestibular safety, and the print: variant for print stylesheets. Third, how to combine and structure these variants — stacking them with breakpoints, choosing between motion-safe and motion-reduce, and the print-specific patterns that make documents readable on paper. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the media conditions and their effects.
Key point: Media condition variants apply utilities based on the device’s orientation, the user’s motion preference, or the output medium. portrait: and landscape: respond to viewport shape. motion-safe: and motion-reduce: respond to prefers-reduced-motion. print: responds to the print medium. Each is a native CSS media query wrapped in Tailwind’s variant syntax.
Why media condition variants exist
The orientation problem. A viewport has two dimensions, and their relationship changes when a device is rotated. A phone in portrait mode is tall and narrow; the same phone in landscape mode is short and wide. A layout that works well in one orientation may break in the other. A video player that fills the width in landscape might be too large in portrait. A sidebar that sits beside content in landscape might need to stack above it in portrait. The orientation media feature exposes this relationship, and the portrait: and landscape: variants make it available without a custom media query. They allow a component to respond to the shape of the viewport, not just its width .
The vestibular safety problem. Not everyone can tolerate motion. For users with vestibular disorders, animations that slide, scale, or rotate can cause dizziness, nausea, or migraine. Operating systems provide a setting — “Reduce motion” on macOS and iOS, “Show animations in Windows” on Windows — that signals this preference to applications. The prefers-reduced-motion media feature exposes the setting, and the motion-safe: and motion-reduce: variants apply styles based on it. The goal is not to remove all animation, but to replace motion-heavy effects with gentler alternatives. A slide-up entrance becomes a fade-in. A bouncing notification becomes a static badge. The user still receives the state change, but without the movement .
The print medium problem. A web page and a printed page are different media. A screen can show hover states, background colors, and infinite scrolling. Paper cannot. A print stylesheet is a second set of styles that applies only when the document is sent to a printer. The print: variant exposes this. It allows an element to be hidden in print (navigation menus, sidebars, call-to-action buttons), or shown only in print (URLs after links, page numbers, a print-specific header). The variant compiles to @media print, and any utility can be prefixed with it. The pattern print:hidden is as common as md:flex, and it solves a problem that would otherwise require a separate stylesheet .
The composability problem. Media conditions are not mutually exclusive. A page can be in portrait orientation, on a device with reduced motion enabled, and being printed — all at once. Tailwind’s variants compose. portrait:motion-reduce:print:hidden is valid, and it applies only when all three conditions are true. This composability means a single class list can express complex conditional logic without nesting media queries or writing custom CSS. The variants stack in the order they are written, and the conditions are combined .
The native-CSS fallback problem. Each variant maps to a standard CSS media feature. There is no runtime, no JavaScript, and no polyfill. The browser evaluates the condition natively. If the browser does not support a feature, the condition is false, and the utility is not applied. This is progressive enhancement by default: a browser that supports prefers-reduced-motion respects it; a browser that does not simply receives the base styles. The variant does not break the page in older browsers — it degrades gracefully .
The trade-off. Media condition variants introduce conditions that are invisible in the code. A motion-reduce:hidden class hides an element, but the condition that triggers the hiding is not visible in the class name beyond the variant prefix. The developer must understand what motion-reduce means and when it applies. Print styles require testing with the browser’s print preview, which is a separate mode that many developers rarely open. And orientation variants can produce layouts that are difficult to test without physically rotating a device or using device emulation. The trade-off is between the precision of condition-specific styles and the effort required to verify them.
a. Orientation variants
The portrait: and landscape: variants apply utilities based on the viewport’s orientation. They map to @media (orientation: portrait) and @media (orientation: landscape) respectively .
A common use is sizing media to fit the available space. A video player that should fill the width in landscape but not overflow in portrait:
<video class="w-full portrait:max-h-[50vh] landscape:max-h-screen">
In portrait, the video is full width but capped at half the viewport height. In landscape, it is full width and can fill the screen height. The orientation variant changes the constraint without changing the base width .
Orientation can also change layout direction. A card that stacks vertically in portrait and spreads horizontally in landscape:
<div class="flex flex-col portrait:flex-col landscape:flex-row">
<img class="portrait:w-full landscape:w-1/2" />
<div class="portrait:w-full landscape:w-1/2">Content</div>
</div>
In portrait, the card remains stacked. In landscape, the image and content sit side by side. The orientation variant replaces a JavaScript resize listener with a single class .
Orientation is independent of width. A phone in landscape may have a wider viewport than the same phone in portrait, but orientation variants respond to the shape, not the dimensions. Combining orientation with breakpoints is common:
<div class="md:flex-row portrait:flex-col">
At md and above, the layout is a row. In portrait orientation, it overrides to a column, regardless of width. The portrait variant wins because it is more specific in intent, though both apply at the same breakpoint .
b. Motion preference variants
The motion-safe: and motion-reduce: variants apply utilities based on the prefers-reduced-motion media feature. motion-safe: applies when the user has not requested reduced motion. motion-reduce: applies when the user has requested it .
The pattern is to gate motion behind motion-safe: and provide a non-motion fallback:
<div class="opacity-100 transition-opacity duration-300 motion-safe:transition-transform motion-safe:translate-y-0">
The base styles include an opacity transition, which is generally safe. The motion-safe: variants add a transform transition and a translate that only run when motion is allowed. A user with reduced motion sees the fade; a user without it sees the slide and fade .
The motion-reduce: variant is the inverse. It applies only when reduced motion is requested, and it is useful for explicitly removing motion:
<div class="animate-bounce motion-reduce:animate-none">
The element bounces by default. When reduced motion is requested, the motion-reduce:animate-none removes the animation entirely. This is simpler than the motion-safe: approach when the base style is motion-heavy and the only need is to disable it .
The choice between motion-safe: and motion-reduce: depends on which state is the baseline. If the baseline is safe (opacity only) and motion is an enhancement, use motion-safe:. If the baseline includes motion and the reduced state is the exception, use motion-reduce:. Both are valid; the question is which one makes the default state clearer .
Motion preference is independent of other conditions. Combining with orientation or breakpoints is possible:
<div class="motion-safe:portrait:animate-slide-in">
The animation runs only when motion is safe and the orientation is portrait. Stacking variants creates compound conditions .
c. Print variant
The print: variant applies utilities when the document is being printed. It maps to @media print and is enabled by default in Tailwind v4 .
The most common pattern is hiding elements that do not belong in print:
<nav class="print:hidden">...</nav>
<button class="print:hidden">Submit</button>
<aside class="print:hidden">Advertisements</aside>
Navigation menus, buttons, and ads are meaningless on paper. The print:hidden variant removes them from the printed output without affecting the screen layout .
The inverse is showing elements only in print. A URL after a link, a print-specific header, or a page number:
<a href="/about" class="text-blue-500 print:text-black">
About
<span class="hidden print:inline"> (/about)</span>
</a>
The link text is blue on screen and black in print, and the URL is hidden on screen and shown in print. This is the standard pattern for making links useful on paper .
Print styles can also override colors. A dark background that wastes ink on paper should become white, and text should become black:
<div class="bg-gray-900 text-white print:bg-white print:text-black">
The screen version is dark; the print version is light. The print: variants override only the colors that matter, leaving other styles unchanged .
Print variants can be combined with other conditions. An element hidden on screen and in print, but shown only when printed in landscape orientation:
<div class="hidden print:portrait:block print:landscape:hidden">
This is rare, but it demonstrates the composability. The print medium is a condition like any other, and it stacks with orientation, motion, and breakpoints .
Complete Example Session
<!-- ============================================
PART 1: ORIENTATION — VIDEO PLAYER
============================================ -->
<!-- In portrait, cap the height. In landscape,
allow the video to fill the screen. -->
<video
class="w-full portrait:max-h-[50vh] landscape:max-h-screen"
src="/intro.mp4"
></video>
<!-- ============================================
PART 2: ORIENTATION — CARD LAYOUT
============================================ -->
<!-- Portrait: stacked. Landscape: side by side. -->
<div class="flex flex-col landscape:flex-row gap-4">
<img
src="/cover.jpg"
class="w-full landscape:w-1/2 object-cover"
/>
<div class="w-full landscape:w-1/2">
<h3>Article Title</h3>
<p>Description text.</p>
</div>
</div>
<!-- ============================================
PART 3: ORIENTATION COMBINED WITH BREAKPOINTS
============================================ -->
<!-- Stack on mobile. Row on tablet and up,
except in portrait orientation. -->
<div class="flex flex-col md:flex-row portrait:md:flex-col">
<div>Sidebar</div>
<div>Content</div>
</div>
<!-- ============================================
PART 4: MOTION-SAFE — GATING TRANSFORMS
============================================ -->
<!-- Opacity is safe. Transform is gated behind
motion-safe. Reduced motion sees only the fade. -->
<div class="opacity-100 transition-opacity duration-300 motion-safe:transition-transform motion-safe:translate-y-0">
Notification
</div>
<!-- ============================================
PART 5: MOTION-REDUCE — REMOVING ANIMATION
============================================ -->
<!-- The base animation runs by default. Reduced
motion removes it entirely. -->
<div class="animate-bounce motion-reduce:animate-none">
New message
</div>
<!-- ============================================
PART 6: MOTION — COMBINING BOTH
============================================ -->
<!-- Use motion-safe for enhancement, motion-reduce
for explicit removal. -->
<button class="transition-transform hover:scale-105 motion-reduce:transition-none motion-reduce:hover:scale-100">
Hover me
</button>
<!-- ============================================
PART 7: PRINT — HIDING NON-ESSENTIAL CONTENT
============================================ -->
<!-- Navigation, buttons, and ads do not belong
in print. -->
<nav class="print:hidden">
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<button class="print:hidden">Subscribe</button>
<aside class="print:hidden">Advertisement</aside>
<!-- ============================================
PART 8: PRINT — SHOWING URLS
============================================ -->
<!-- Links are useless on paper without URLs.
Show the URL only in print. -->
<a href="/pricing" class="text-blue-600 print:text-black">
Pricing
<span class="hidden print:inline"> (/pricing)</span>
</a>
<!-- ============================================
PART 9: PRINT — COLOR OVERRIDES
============================================ -->
<!-- Dark backgrounds waste ink. Override for print. -->
<div class="bg-gray-900 text-white print:bg-white print:text-black">
<h1>Report Title</h1>
<p>This content will print on a white background with black text.</p>
</div>
<!-- ============================================
PART 10: STACKING ALL MEDIA CONDITIONS
============================================ -->
<!-- A single element with multiple media conditions. -->
<div class="
bg-white text-black
portrait:bg-blue-50
landscape:bg-green-50
motion-safe:animate-fade-in
motion-reduce:animate-none
print:bg-white print:text-black print:portrait:bg-gray-50
">
<p>This element responds to orientation, motion, and print.</p>
</div>
The ten parts show orientation variants for layout and media sizing, motion variants for vestibular safety, print variants for hiding, showing, and recoloring, and the combination of multiple media conditions in a single class list.
Quick Reference
Media Condition Variants
| Variant | Media query | Applies when |
|---|---|---|
portrait: | (orientation: portrait) | Viewport is taller than wide |
landscape: | (orientation: landscape) | Viewport is wider than tall |
motion-safe: | (prefers-reduced-motion: no-preference) | User has not requested reduced motion |
motion-reduce: | (prefers-reduced-motion: reduce) | User has requested reduced motion |
print: | print | Document is being printed |
Orientation vs Breakpoints
| Variant | Responds to |
|---|---|
md: | Viewport width (min-width) |
portrait: | Viewport shape (tall) |
landscape: | Viewport shape (wide) |
Motion Preference
| Pattern | Meaning |
|---|---|
motion-safe:animate-slide | Animation only when motion is allowed |
motion-reduce:animate-none | No animation when motion is reduced |
transition-opacity motion-safe:transition-transform | Safe fade always; transform gated |
Print Patterns
| Pattern | Purpose |
|---|---|
print:hidden | Remove element from printed output |
hidden print:block | Show element only in print |
print:text-black | Black text in print |
print:bg-white | White background in print |
Stacking Media Conditions
| Example | Condition |
|---|---|
portrait:md:flex-col | Portrait and md and above |
motion-safe:portrait:animate-slide | Motion allowed and portrait |
print:portrait:bg-gray-50 | Printing and portrait |
Best Practices
✅ Do This:
<!-- Cap media in portrait, fill in landscape -->
<video class="w-full portrait:max-h-[50vh] landscape:max-h-screen"> <!-- ✅ -->
<!-- Gate transforms behind motion-safe -->
<div class="transition-opacity motion-safe:transition-transform"> <!-- ✅ -->
<!-- Remove animation for reduced motion -->
<div class="animate-bounce motion-reduce:animate-none"> <!-- ✅ -->
<!-- Hide navigation in print -->
<nav class="print:hidden"> <!-- ✅ -->
<!-- Show URLs only in print -->
<span class="hidden print:inline"> (/page)</span> <!-- ✅ -->
<!-- Override colors for print -->
<div class="bg-gray-900 print:bg-white print:text-black"> <!-- ✅ -->
<!-- Stack media conditions -->
<div class="portrait:motion-reduce:print:hidden"> <!-- ✅ -->
❌ Don’t Do This:
<!-- Don't rely on orientation alone for responsive layout -->
<div class="landscape:flex-row"> <!-- ❌ -->
<!-- Don't remove all animation without a fallback -->
<div class="motion-reduce:hidden"> <!-- ❌ -->
<!-- Don't forget the base style when gating with motion-safe -->
<div class="motion-safe:translate-y-0"> <!-- ❌ (no base) -->
<!-- Don't hide essential content in print -->
<article class="print:hidden">Main content</article> <!-- ❌ -->
<!-- Don't use print variants for screen-only concerns -->
<div class="print:flex print:gap-4"> <!-- ❌ -->
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Orientation not applying | Viewport meta tag missing | Add width=device-width meta tag |
| Motion variant has no effect | Browser doesn’t support prefers-reduced-motion | Graceful degradation — base styles apply |
| Print styles not visible | Testing on screen, not print preview | Use browser print preview (Cmd/Ctrl+P) |
| Motion-safe with no base style | Utility only applies when condition true | Always provide a base style |
| Landscape layout breaks | Assuming landscape means wide | Test on actual rotated device |
| Print colors ignored | print: variant missing | Add print:bg-white print:text-black |
| Stacking order confusion | Variants apply in fixed order | Breakpoints → state → media conditions |
Real-World Examples
1. Portrait Video Cap
<video class="w-full portrait:max-h-[50vh]">
2. Landscape Card Layout
<div class="flex flex-col landscape:flex-row">
3. Motion-Safe Transform
<div class="motion-safe:translate-y-0 motion-safe:transition-transform">
4. Motion-Reduce Disable
<div class="animate-bounce motion-reduce:animate-none">
5. Print Hidden Nav
<nav class="print:hidden">
6. Print-Only URL
<span class="hidden print:inline"> (/about)</span>
7. Print Color Override
<div class="bg-gray-900 print:bg-white print:text-black">
8. Orientation with Breakpoint
<div class="md:flex-row portrait:md:flex-col">
9. Motion-Safe Hover
<button class="motion-safe:hover:scale-105 motion-reduce:hover:scale-100">
10. Stacked Media Conditions
<div class="portrait:motion-safe:animate-slide">
Visual
Orientation Variants
┌──────────────────────────────────────────────────────────────┐
│ ORIENTATION │
│ │
│ PORTRAIT LANDSCAPE │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ TALL │ │ WIDE │ │
│ │ NARROW │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ └──────────────┘ └──────────────────────┘ │
│ │
│ portrait: applies landscape: applies │
│ (height > width) (width > height) │
│ │
│ Independent of breakpoint. A phone in landscape may │
│ be wider than the same phone in portrait, but the │
│ orientation variant responds to shape, not width. │
│ │
└──────────────────────────────────────────────────────────────┘
Motion Preference
┌──────────────────────────────────────────────────────────────┐
│ MOTION PREFERENCE │
│ │
│ User has NOT requested User HAS requested │
│ reduced motion reduced motion │
│ │
│ motion-safe: applies motion-reduce: applies │
│ motion-reduce: ignored motion-safe: ignored │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Base: opacity transition (safe for all) │ │
│ │ │ │
│ │ motion-safe:translate-y-0 │ │
│ │ → slide runs only when motion is allowed │ │
│ │ │ │
│ │ motion-reduce:animate-none │ │
│ │ → animation removed when motion is reduced │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ The base style should be safe. Motion is the enhancement. │
│ │
└──────────────────────────────────────────────────────────────┘
Print Medium
┌──────────────────────────────────────────────────────────────┐
│ PRINT MEDIUM │
│ │
│ SCREEN PRINT │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ [Nav] │ │ │ │
│ │ ┌────────────────┐ │ │ Article Title │ │
│ │ │ Article │ │ │ │ │
│ │ │ Title │ │ │ Body text without │ │
│ │ │ │ │ │ navigation or ads. │ │
│ │ │ Body text │ │ │ │ │
│ │ └────────────────┘ │ │ Link URL shown │ │
│ │ [Ad] │ │ after link text. │ │
│ │ [Subscribe] │ │ │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ print:hidden removes nav, ads, buttons. │
│ hidden print:block shows print-only elements. │
│ print:bg-white print:text-black saves ink. │
│ │
└──────────────────────────────────────────────────────────────┘
Stacking Media Conditions
┌──────────────────────────────────────────────────────────────┐
│ STACKING MEDIA CONDITIONS │
│ │
│ class="portrait:motion-safe:animate-slide" │
│ │
│ Condition 1: orientation is portrait │
│ Condition 2: motion is safe (not reduced) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Portrait? Motion safe? Result │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ Yes Yes animate-slide applies │ │
│ │ Yes No no animation │ │
│ │ No Yes no animation │ │
│ │ No No no animation │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ All stacked conditions must be true for the utility to │
│ apply. The order of variants in the class name does not │
│ affect the result. │
│ │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
portrait: | @media (orientation: portrait) — viewport is tall |
landscape: | @media (orientation: landscape) — viewport is wide |
motion-safe: | @media (prefers-reduced-motion: no-preference) |
motion-reduce: | @media (prefers-reduced-motion: reduce) |
print: | @media print |
| Orientation | Independent of width; responds to shape |
| Motion | Base style should be safe; motion is enhancement |
| Hide non-essential, show URLs, override colors | |
| Stacking | Multiple conditions can be combined |
| Native CSS | Each variant maps to a standard media query |
Key takeaways:
- Orientation variants respond to viewport shape, not size.
portrait:andlandscape:apply based on the relationship between width and height. They are independent of breakpoints and can be combined with them. - Motion variants protect vestibular health.
motion-safe:gates motion behind the user’s preference.motion-reduce:removes motion when the user has requested it. The base style should be safe (opacity), and motion should be the enhancement. - The print variant applies only when printing.
print:hiddenremoves navigation, buttons, and ads.hidden print:blockshows print-only elements like URLs.print:bg-white print:text-blacksaves ink. - Media conditions compose.
portrait:motion-safe:print:hiddenis valid and applies only when all three conditions are true. The variants stack in a fixed order, and the conditions are combined. - Each variant maps to native CSS. There is no runtime, no JavaScript, and no polyfill. The browser evaluates the media query, and the utility applies or does not apply accordingly.
- Test print styles with print preview. The
print:variant only applies in the print medium. Browser print preview (Cmd/Ctrl+P) is the only way to verify print styles without printing. - Orientation is not a replacement for breakpoints. A landscape phone may be narrower than a portrait tablet. Use orientation for shape-dependent layouts and breakpoints for width-dependent layouts.
- The base style is always present.
motion-safe:animate-slideonly adds the animation when motion is safe. The element still renders without it. There is no need for amotion-reduce:counterpart unless the base style itself includes motion.
Remember: Media condition variants extend Tailwind’s conditional styling beyond screen width. Orientation variants respond to the shape of the viewport, motion variants respect the user’s vestibular preferences, and the print variant adapts the document for paper. Each maps to a native CSS media query, each composes with the others, and each follows the same prefix-and-utility syntax as every other variant. The result is a responsive system that accounts for the device’s physical orientation, the user’s accessibility needs, and the output medium — without writing a single @media block by hand.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!