{"id":204525,"date":"2015-07-14T07:40:14","date_gmt":"2015-07-14T14:40:14","guid":{"rendered":"http:\/\/css-tricks.com\/?p=204525"},"modified":"2015-07-14T10:38:49","modified_gmt":"2015-07-14T17:38:49","slug":"print-stylesheet-approaches-blacklist-vs-whitelist","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/print-stylesheet-approaches-blacklist-vs-whitelist\/","title":{"rendered":"Print Stylesheet Approaches: Blacklist vs Whitelist"},"content":{"rendered":"
The “blacklist” is a common approach to print stylesheets. We know that people probably don’t need to see our site navigation if they print out an article on our site. So we hide it from print like we would hide it from the screen ( Is there a way to reverse that?<\/p>\n <\/p>\n You select all the elements on the page you don’t want printed, and put that into some CSS that is applied to the print media. Perhaps in a block at the bottom of your main stylesheet.<\/p>\n Alternatively, you could leave the job mostly the the HTML. You could create a “don’t print” class and apply it as needed.<\/p>\n Blacklisting is a common tactic, posted in print stylesheet tip articles all around the internet. <\/p>\n The only trouble with it is that it requires maintenance.<\/strong> HTML changes, so you’ll need to maintain either your list of selectors to not print, or the classes in the HTML to be on the right elements. Easy to forget.<\/p>\n Whitelisting would be the opposite technique. In your print styles, everything would be hidden from print except for elements you explicitly choose. <\/p>\n Don’t get your hopes up too much though, it’s pretty tricky to pull off.<\/strong> My first thought was to universally hide things, then override with a class.<\/p>\n There are two problems here:<\/p>\n The latter of which we could maybe solve with…<\/p>\n … selecting the child elements and having them show themselves again. But that would make all child elements block-level, which is bad. You don’t want your That would be harder to maintain than a blacklist.<\/p>\n I considered manually requiring all parent elements to also have “print-me” class, but that will expose sibling elements to being printed when they shouldn’t be (don’t have the class). I tried fixing that with a <\/p>\n But that doesn’t handle previous siblings.<\/p>\n This could be a pretty good use case for parent selectors in CSS, since you could potentially use a parent selector to un-hide a parent element if it contained an element with that specific class name. Theoretically something like There may be a pure CSS solution to this yet. I admittedly didn’t spend hours and hours on this. There may be a clever tactic here I’m missing. I know that the visibility<\/a> property doesn’t inherit, so there may be potential there, but that doesn’t effect layout like you may want it to. I’m not sure If you want to play with ideas, here’s a test page for you.<\/a> It just has a button that toggles a class on the parent of a bunch of content, so you can pretend that class is like print styles and get it to do what you want.<\/p>\n My closest attempt<\/a> so far is a just give up and use JavaScript<\/strong> attempt. Using jQuery here for easy DOM traversal, the crux of it is automatically applying a class to all parents of an element ensuring they can be printed:<\/p>\n Note I’m using a slightly different class name, so it’s not affected by the same rule that selects all descendants to display.<\/p>\ndisplay: none;<\/code>). <\/p>\n
The Blacklist Technique<\/h3>\n
@media print {\r\n .main-navigation, .comments, .sidebar, .footer {\r\n display: none;\r\n }\r\n}<\/code><\/pre>\n
@media print {\r\n .dont-print {\r\n display: none;\r\n }\r\n}<\/code><\/pre>\n
<section id=\"comments\" class=\"comments dont-print\">\r\n<\/section><\/code><\/pre>\n
The Whitelist Technique<\/h3>\n
\/* Bad idea #1 *\/\r\n@media print {\r\n * {\r\n display: none;\r\n }\r\n .print-me {\r\n display: block;\r\n }\r\n}<\/code><\/pre>\n
<main class=\"main-content print-me\">\r\n<\/main><\/code><\/pre>\n
\n
display<\/code> property isn’t inherited, so even though you told an element to show itself again, it’s child elements will still be hidden by the universal selector selecting and hiding them.<\/li>\n
\/* Bad idea #2 *\/\r\n@media print {\r\n * {\r\n display: none;\r\n }\r\n .print-me,\r\n .print-me * {\r\n display: block;\r\n }\r\n}<\/code><\/pre>\n
<a><\/code>,
<em><\/code>,
<strong><\/code>‘s and anything else that is
inline<\/code>,
inline-block<\/code>,
inline-table<\/code>,
inline-flex<\/code>, etc to become a block.<\/p>\n
\/* Bad idea #3 (addition to previous) *\/\r\n.print-me ~ *:not(.print-me) {\r\n display: none;\r\n}<\/code><\/pre>\n
*:contains(.print-me) { display: block; }<\/code>. <\/p>\n
:not()<\/code> was explored to its fullest potential here either.<\/p>\n
$(\".print-me\")\r\n .parents()\r\n .addClass(\"js-print-me\");<\/code><\/pre>\n
@media print {\r\n * {\r\n display: none;\r\n }\r\n .print-me,\r\n .print-me * {\r\n display: block;\r\n }\r\n .js-print-me {\r\n display: block;\r\n }\r\n}<\/code><\/pre>\n