Skip to main content

    Lesson 43 • Advanced Track

    Print Stylesheets & Export-Friendly Layouts

    By the end of this lesson you'll be able to give any page a clean printed (and "Save as PDF") version — hiding the nav and ads, setting paper margins, controlling where pages break, and printing link URLs so the paper is actually useful on its own.

    What You'll Learn

    Write an @media print block that only applies on paper
    Hide navigation, ads, and buttons with display: none
    Set page margins and paper size with the @page rule
    Control page breaks with break-before / break-after / break-inside
    Print a link's URL using a::after { content: attr(href) }
    Keep wanted backgrounds with print-color-adjust
    Before this lesson: you should be comfortable writing CSS rules and selectors and have seen a media query before. If @media is new, review Responsive Design & Media Queries first — a print stylesheet is just a media query whose condition is "this page is being printed".

    💡 Think of It Like This

    A print stylesheet is like the "export to PDF" filter on a document. Your web page is full of things that only make sense on a screen — a sticky navbar, ads, a cookie banner, a video player, a "Buy now" button. None of that belongs on a sheet of paper.

    @media print is the filter that runs the moment someone hits Print. It strips away the digital chrome, flattens the colours so they don't drink ink, and leaves a clean, readable document behind — the same content, dressed for paper instead of for a browser. You write it once, and every printout (or saved PDF) comes out looking professional.

    1. The @media print Block

    Everything you wrap in @media print { … } applies only when the page is printed or shown in print preview. On screen those rules do nothing, so they can never break your normal layout. The single most important thing print CSS does is hide the chrome: display: none on the nav, ads, and buttons so they don't waste paper.

    You can't see print CSS by looking at the page. To check your work, open print preview with Ctrl+P (Windows/Linux) or Cmd+P (Mac) — no paper required.

    Worked example: hide the screen-only chrome

    Open print preview (Ctrl/Cmd+P) to see the navbar and button vanish

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Hide chrome on print</title>
      <style>
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; }
        .navbar {
          background: #1976D2; color: white; padding: 16px;
          border-radius: 8px; margin-bottom: 24px;
          display: flex; justify-content: space-between; align-items: center;
        }
        .btn { background: white; color: #1976D2; border: none;
               padding: 8px 16px; border-radius: 6px; cur
    ...

    2. @page — Margins & Paper Size

    The @page rule styles the printed sheet itself — its margins and its size. @page { margin: 2cm; } gives every page a 2cm border of white space; size: A4 landscape picks the paper and orientation. Use real print units here — cm, mm, in, or pt — never vh/vw, because a printout has no viewport.

    You can even target specific pages: @page :first styles only page one (handy for a bigger top margin on a cover page), and @page :left / :right style even and odd pages for double-sided binding.

    Worked example: page margins and a roomier first page

    @page sets the sheet margins; @page :first overrides page one

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>@page rules</title>
      <style>
        body { font-family: Georgia, serif; line-height: 1.7; color: #222; }
        h1 { color: #1565C0; }
    
        @media print {
          /* Every printed sheet gets a 2cm margin of white space all round. */
          @page { margin: 2cm; }
    
          /* The FIRST page gets extra space at the top, like a title page. */
          @page :first { margin-top: 5cm; }
        }
      </style>
    </head>
    <body>
      <h1>The Print Report<
    ...

    3. Page Breaks — Where New Pages Start

    On screen content scrolls forever; on paper it has to be sliced into pages, and by default the browser slices wherever it runs out of room — sometimes mid-table or mid-heading. Three properties let you take control: break-before: page forces a new page before an element, break-after: page forces one after, and break-inside: avoid tells the browser "don't split this element across two pages" — perfect for tables, images, and cards.

    For the fine detail, orphans and widows set the minimum number of lines a paragraph may leave at the bottom or carry to the top of a page, so you never strand a single lonely line.

    Worked example: force breaks and keep tables whole

    break-before starts new pages; break-inside: avoid protects the table

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Page breaks</title>
      <style>
        body { font-family: system-ui, sans-serif; padding: 24px; color: #333; }
        h2 { color: #1565C0; }
        section { margin-bottom: 32px; padding: 16px; border: 2px dashed #e0e0e0; border-radius: 8px; }
        table { width: 100%; border-collapse: collapse; margin-top: 12px; }
        th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }
        th { background: #f5f5f5; }
    
        @media 
    ...

    4. Printing Link URLs with attr(href)

    A link is useless on paper — you can't click it, and "see our report" tells the reader nothing about where to look. The fix is generated content: a::after { content: " (" attr(href) ")"; }. The attr(href) function reads the URL out of the link's markup and prints it in brackets after the text, so the printout shows both the words and the address.

    Scope it to a[href^="http"] if you only want to expand external links and leave in-page anchors like #top alone.

    Worked example: expand links into readable URLs

    attr(href) pulls the URL into print; only external links are expanded

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Print link URLs</title>
      <style>
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; line-height: 1.8; }
        a { color: #1976D2; }
    
        @media print {
          a { color: black; text-decoration: underline; }
    
          /* Only external links get their URL printed after the text. */
          a[href^="http"]::after {
            content: " (" attr(href) ")";   /* attr(href) = the link's URL */
            font-size: 0.
    ...

    5. Backgrounds & print-color-adjust

    By default browsers drop background colours and images when printing — it saves ink and keeps text legible on white paper. Most of the time that's exactly what you want, so prefer borders over coloured fills to show structure. But sometimes a background is the point: a coloured invoice header, a code block, a status badge.

    To force a background to print, set print-color-adjust: exact (add the -webkit- prefix for Chrome and Safari). It tells the browser "print these colours as I designed them, don't optimise them away." Use it sparingly — only on the few elements that genuinely need their colour.

    Worked example: keep one background, drop the rest

    print-color-adjust: exact forces the header colour onto paper

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>print-color-adjust</title>
      <style>
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; }
        .banner {
          background: #1976D2; color: white;
          padding: 16px 20px; border-radius: 8px; font-weight: 700;
        }
        .note { background: #E3F2FD; padding: 16px; border-radius: 8px; margin-top: 16px; }
    
        @media print {
          /* The banner colour is part of the brand, so keep it. */
          .banner {
    ...

    6. Putting It Together — A Print-Optimised Article

    Here's a complete article that uses every idea from this lesson at once: it hides the nav and ads, sets page margins, prints link URLs, keeps the figure whole, forces the references onto a fresh page, and keeps just the one background it needs. Read the comments, then open print preview to see the screen version melt into a clean document.

    Worked example: a fully print-ready article

    Every print technique combined on one realistic page

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Print-optimised article</title>
      <style>
        * { box-sizing: border-box; }
        body { font-family: Georgia, serif; line-height: 1.7; color: #222; margin: 0; }
    
        .topbar { background: #1976D2; color: white; padding: 12px 20px;
                  display: flex; justify-content: space-between; align-items: center; }
        .topbar button { background: white; color: #1976D2; border: none;
                         padding: 8px 14px; bo
    ...

    🎯 Your Turn #1 — Hide the chrome and set margins

    This receipt prints with its toolbar and a cramped layout. Add a print block that hides the toolbar and gives the page sensible margins. Fill in the blanks marked ___, then open print preview and check the comments.

    Your Turn #1: a clean printed receipt

    Hide the toolbar with display: none and add @page margins

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Your Turn 1</title>
      <style>
        /* 🎯 YOUR TURN — fill in the blanks marked ___ */
    
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; }
        .toolbar { background: #1976D2; color: white; padding: 12px 16px;
                   border-radius: 8px; margin-bottom: 20px; display: flex;
                   justify-content: space-between; align-items: center; }
        .toolbar button { background: white; color: #197
    ...

    🎯 Your Turn #2 — Show link URLs and protect a table

    This report's links print as plain text (no URL) and its table can split across pages. Add generated content to show the URLs and a rule to keep the table whole. Fill in the blanks, then verify in print preview.

    Your Turn #2: printable links and an unbreakable table

    Use attr(href) for URLs and break-inside: avoid for the table

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Your Turn 2</title>
      <style>
        /* 🎯 YOUR TURN — fill in the blanks marked ___ */
    
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; line-height: 1.7; }
        a { color: #1976D2; }
        table { width: 100%; border-collapse: collapse; margin-top: 16px; }
        th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }
        th { background: #f5f5f5; }
    
        @media print {
          a { color: bl
    ...

    🧩 Mini-Challenge — A print-ready invoice from scratch

    Support is faded now — only an outline is given. Write the print stylesheet for this invoice yourself. Use the worked examples in sections 1–6 as your reference if you get stuck.

    Mini-Challenge: print stylesheet from scratch

    Hide the button, set margins, keep the table whole, print the footer link's URL

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Mini-Challenge</title>
      <style>
        body { font-family: system-ui, sans-serif; padding: 24px; color: #222; }
        .print-btn { background: #1976D2; color: white; border: none;
                     padding: 10px 18px; border-radius: 8px; cursor: pointer; font-weight: 700; }
        h1 { color: #1565C0; }
        table { width: 100%; border-collapse: collapse; margin: 16px 0; }
        th, td { padding: 8px 12px; border: 1px solid #ddd; tex
    ...

    ⚠️ Common Errors (and the fix)

    • Forgetting to hide the chrome. The printout comes out with the navbar, ads, cookie banner, and buttons, wasting ink and space. Fix: inside @media print, set display: none on every screen-only element (a .no-print class is a handy catch-all).
    • Never testing the print styles. Print CSS is invisible in the normal page view, so it's easy to ship rules that don't work. Fix: always check with Ctrl+P / Cmd+P (or emulate the print media type in DevTools) before you trust it.
    • Awkward page breaks splitting tables and figures. A table or image gets cut in half across two pages and becomes unreadable. Fix: add break-inside: avoid to those elements, and break-after: avoid on headings to keep them with their text.
    • Relying on background colour for meaning. Browsers drop backgrounds when printing, so a coloured "Paid" badge or status box vanishes. Fix: prefer borders and weight for structure; where a colour is essential, opt in with print-color-adjust: exact (plus the -webkit- prefix).
    • Burning ink with full-colour text and big images. Bright body text and dark backgrounds drain cartridges and read poorly on white paper. Fix: set text to color: black and remove decorative backgrounds in the print block.
    • Using vh/vw units. Print has no viewport, so viewport units behave unpredictably. Fix: size print layouts with cm, mm, in, or pt.

    📋 Quick Reference

    GoalUse this
    Apply rules only on paper@media print { … }
    Hide screen-only elements.no-print { display: none; }
    Set page margins@page { margin: 2cm; }
    Set paper size / orientation@page { size: A4 landscape; }
    Style the first page only@page :first { margin-top: 5cm; }
    Force a new page before/afterbreak-before: page; / break-after: page;
    Keep an element wholebreak-inside: avoid;
    Avoid stranded linesorphans: 3; widows: 3;
    Print a link's URLa::after { content: " (" attr(href) ")"; }
    Force a background to printprint-color-adjust: exact;

    ❓ Frequently Asked Questions

    Why don't I see any difference when I add @media print?

    Print styles are invisible on screen by design — they only apply when the page is actually printed. To see them, open the browser's print preview with Ctrl+P (Windows/Linux) or Cmd+P (Mac), or in DevTools use the rendering panel to emulate the 'print' media type. If you never check the preview, you'll have no idea whether your rules work, because nothing changes in the normal page view.

    Why are my background colours missing in the printout?

    Browsers strip background colours and images when printing by default — it saves ink and keeps text readable on white paper. If a background is essential (a coloured invoice header, a code block, a chart), opt back in with print-color-adjust: exact (and the -webkit- prefix for Safari/Chrome). But for most pages the better fix is to not depend on backgrounds at all: use borders, weight, and spacing to show structure instead.

    What's the difference between break-before: page and the old page-break-before?

    They do the same thing — force a page break before the element — but break-before is the modern, standardised property and page-break-before is the legacy one. break-before also supports more values (like 'column' and 'region'). For maximum browser coverage you can write both, putting page-break-before first and break-before second so the modern one wins where it's supported.

    How do I show a link's URL on paper when the text just says 'click here'?

    Use generated content: a[href]::after { content: " (" attr(href) ")"; }. The attr(href) function pulls the link's URL out of the markup and prints it in brackets after the link text, so a reader holding the paper can still find the page. Scope it to a[href^="http"] if you only want to expand external links and leave in-page anchors alone.

    Can I control the paper size and orientation from CSS?

    Yes, with the @page rule. @page { size: A4; } picks the paper size, @page { size: landscape; } rotates it, and you can combine them: @page { size: A4 landscape; }. You can also set margins there — @page { margin: 2cm; } — and target the first page separately with @page :first. The browser's own print dialog can still override these, but they're a strong default.

    Should I use a separate print.css file or an @media print block?

    Either works and both are equally valid. A <link rel="stylesheet" media="print" href="print.css"> keeps print rules in their own file, which is tidy for large sites. An @media print { } block inside your main stylesheet keeps everything in one place, which is simpler for small projects. The rules behave identically; pick whichever keeps your codebase easiest to maintain.

    🎉 Lesson Complete

    You can now give any page a clean, professional printout. The essentials:

    • @media print applies styles only when printing or in print preview
    • ✅ Hide the chrome — nav, ads, buttons — with display: none
    • @page { margin / size } sets paper margins and dimensions; @page :first targets page one
    • break-before / break-after start new pages; break-inside: avoid keeps elements whole
    • a::after { content: attr(href) } prints link URLs so paper is self-contained
    • ✅ Backgrounds are dropped by default — use borders, or print-color-adjust: exact to keep the ones that matter

    Next up: CSS Performance Optimization, where you'll make your styles render as fast as they look good.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service

    Install LearnCodingFast

    Learn faster with the app on your home screen.