Jump to main content
Menu

Media Queries, Part 1

Getting Started with Media Queries

  • Let's begin by targeting the screen and print media types using the @media directive.
  • There is always a strategy when working with media queries, and that is to isolate your CSS into @media blocks to prevent too many rules from being applied to all media types.
  • Rules outside of @media default to "all" as their type, which means that they apply everywhere.
  • The more rules that are applying to all media types, the more rules you will need to override (for example, when printing).
  • It is also imperative to understand the CSS Cascade, because you won't need to make your selectors more specific if you simply sequence your code properly (rules that occur later in a stylesheet will override rules of the same specificity that occur earlier).

Media Query Examples

Example 1: Print Styles With Some Overrides

See the Pen Media Specific CSS: Example 1 by Jason Withrow (@jwithrow) on CodePen.

View the first example in full-screen and then use Ctrl + P to see the Print Preview. That will show the print styles being applied. Notice how the print styling is overriding the default "all" media styling for the h2.

Example 2: Print Styling Without Overrides

See the Pen Media-Specific CSS: Example 2 by Jason Withrow (@jwithrow) on CodePen.

View the second example in full-screen and then use Ctrl + P to see the Print Preview. That will show the print styles being applied. In this case the @media blocks contain all the styles, so there is no need for the print-specific styles to override anything.

Considerations with @media

  • As you can see from the examples, moving all the screen-related code into @media screen {} allows you to streamline the @media print {}, because there are no collisions with styles that are applying to all media.
  • Important: It is possible to nest @media blocks (so the outer block specifies the media type and inner blocks specify max or min screen widths), but this approach has its risks.
    • Nesting adds complexity and you run the very real risk of failing to close an @media block or closing it prematurely.
    • You will find yourself indenting your CSS more than usual, to keep track of what rules are in what block.
    • Old browsers may be unhappy with the nesting (just because the specification allows it does not guarantee good support).
    • The odds of having @media blocks improperly overlapping goes up significantly.

Alternate Implementations

  • The approach shown in the examples translates easily to external CSS files brought in via <link /> or @import - you can just copy the @media blocks into those files.
  • Note that the @import approach for bringing in external files is best avoided, due to performance issues. So <link /> is always the preferred approach.
  • There is also a media attribute that can be added to the <style> tag (so you could have multiple separate <style> tags, one for each media type), although in practice your CSS is going to be in external files so this would be rarely used.

Print CSS Recommendations

Implementing print-specific CSS is a quick, easy way to greatly improve the print output from a website. It is likely the most impactful and beneficial 15 minutes you will ever spend as a web developer, because that's usually the time it takes to rapidly iterate through print adjustments as you 'Print Preview'.

As with any development practice, there are recommendations for the best outcomes:

  • Switch fonts from sans-serif to serif
    • Serif fonts are slightly easier to read than sans-serif fonts on the printed page.
  • Make sure that text colors and border colors are black
    • There is no need to switch printers into color mode because one heading is a color other than black.
  • Use display: none to remove elements and their content from the print output
    • All child and descendant elements are also removed from display.
    • Typically you are hiding navigation bars and anything that is irrelevant to the print experience.
  • Use display: none to hide content from the screen display, which then appears in the print output
    • As long as screen and print styles are separated, the content will automatically appear when printing.
    • For example, you could have a printOnly class in your CSS that is defined in your screen styles to display: none:
      @media screen {
        .printOnly {
          display: none;
        }
      } 
      

      Since that is not part of the print CSS, content with that class displays when printing.

    • How might this be used?
      • As one example, you might want to output the current page URL at the bottom of the print output.
      • You hide that from screen display, and it emerges when printing.
      • This is necessary because the top-most left/middle/right and the bottom-most left/middle/right information in the print output is out of our control (we cannot change the browser's print settings, not even with JavaScript). We can only dictate what appears in the printed page's content area. We should not assume that the user would get this information otherwise.
    • Keep in mind that elements and content instructed to display: none in the screen output are ignored by screen reading software.
  • Data tables almost always require print adjustments, due to extending off the page
    • If the table content is too wide for the printed page, and shrinking the font size still doesn't get it all to fit, there are two other options: either the table is linearized (see Media Queries, Part 2) or you hide some of the table columns, using display: none to remove cells when printing (be sure to get the entire column and not just part of it).
    • If you are removing cells, the most efficient way is with th:nth-child() and td:nth-child(), although cells that are joined together (colspan) will give you difficulties and you'll probably need to use another selector to pinpoint them.
  • Allow printed output to render in the normal flow
    • Positioned elements can render off the printed page (or partially off the page), while floated elements can also get clipped. You may need to position: static if the absolute/relative/fixed/sticky positioning is being applied to print. And, of course, there is float: none, if necessary.
    • In some cases the floated element or positioned element cuts off all printing after it, so that the rest of the document is lost.
  • Allow printed output to fill up the printed page width naturally
    • Setting fixed widths for elements can cause content to be cropped.
    • It is best to allow block-level elements to naturally fill up the width of the printed page and flow content following them to the next line.
    • For block elements the easiest solution is to only have the fixed widths in the screen styles.
    • If that is not possible, then the print override would set width: auto or width: 100% (but watch out for padding and borders causing the overall space to be wider than 100%, and if that is happening switch the box model using box-sizing: border-box). Between the two, width: auto is a lot less of a headache.
  • Control page breaks via CSS
    • A way to control page breaks in printed output is via page-break-before and page-break-after, which need to have a value of always to work best across all browsers.
    • For example:
      @media print {
        .breakBefore {
          page-break-before: always;
        }
        .breakAfter {
          page-break-after: always;
        }  
      }
      
    • Be careful with page breaks inside tables; those are likely to be problematic.
    • Inserting breaks between block-level elements, or elements displayed as blocks, works best.
  • Background images will likely not be printed out
    • Keep this in mind when creating your layout.
    • This is a browser setting that is out of your control and usually is set to not print backgrounds.
    • If an image is a background, yet you feel it is important to include it when printing, you can call it twice in the screen output (once as a CSS background image and again using an <img /> positioned off the viewport).
  • If desired (and it may not be), you can display URLs after links in the print output
    • This is handled via generated content, such as:
      @media print {
        a::after {content: " (" attr(href) ") ";}
      }
      
    • A document with lots of links can also result in a very cluttered printout, so use with caution.