Print Stylesheet Approaches: Blacklist vs Whitelist

Avatar of Chris Coyier
Chris Coyier on

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der „Blacklist“-Ansatz ist bei Print-Stylesheets verbreitet. Wir wissen, dass Leute wahrscheinlich unsere Website-Navigation nicht sehen müssen, wenn sie einen Artikel auf unserer Website ausdrucken. Also verstecken wir sie vor dem Druck, so wie wir sie vor dem Bildschirm verstecken (display: none;).

Gibt es eine Möglichkeit, das umzukehren?

Die Blacklist-Technik

Sie wählen alle Elemente auf der Seite aus, die Sie nicht drucken möchten, und fügen dies in etwas CSS ein, das für das Druckmedium angewendet wird. Vielleicht in einem Block am Ende Ihres Haupt-Stylesheets.

@media print {
  .main-navigation, .comments, .sidebar, .footer {
     display: none;
   }
}

Alternativ könnten Sie die Aufgabe weitgehend dem HTML überlassen. Sie könnten eine „Nicht drucken“-Klasse erstellen und diese bei Bedarf anwenden.

@media print {
  .dont-print {
    display: none;
  }
}
<section id="comments" class="comments dont-print">
</section>

Blacklisting ist eine gängige Taktik, die in Artikeln über Print-Stylesheet-Tipps im gesamten Internet gepostet wird.

Der einzige Nachteil ist, dass es Wartung erfordert. HTML-Änderungen erfordern, dass Sie entweder Ihre Liste von Selektoren, die nicht gedruckt werden sollen, oder die Klassen im HTML, die auf den richtigen Elementen stehen sollen, pflegen. Leicht zu vergessen.

Die Whitelist-Technik

Whitelisting wäre die entgegengesetzte Technik. In Ihren Print-Styles wird alles vom Druck ausgeschlossen, außer den Elementen, die Sie explizit auswählen.

Halten Sie Ihre Erwartungen aber nicht zu hoch, es ist ziemlich schwierig, das umzusetzen. Mein erster Gedanke war, Dinge universell zu verstecken und dann mit einer Klasse zu überschreiben.

/* Bad idea #1 */
@media print {
  * {
    display: none;
  }
  .print-me {
    display: block;
  }
}
<main class="main-content print-me">
</main>

Hier gibt es zwei Probleme:

  1. Die Eigenschaft display wird nicht vererbt. Selbst wenn Sie einem Element gesagt haben, sich selbst wieder anzuzeigen, bleiben seine Kindelemente vom universellen Selektor, der sie auswählt und versteckt, verborgen.
  2. Die Elternelemente des Elements, dem Sie gesagt haben, sich selbst anzuzeigen, könnten immer noch verborgen sein.

Letzteres könnten wir vielleicht lösen mit...

/* Bad idea #2 */
@media print {
  * {
    display: none;
  }
  .print-me,
  .print-me * {
    display: block;
  }
}

... dem Auswählen der Kindelemente und sie sich selbst wieder anzeigen lassen. Aber das würde alle Kindelemente zu Block-Elementen machen, was schlecht ist. Sie möchten nicht, dass Ihre <a>-, <em>-, <strong>-Elemente und alles andere, das inline, inline-block, inline-table, inline-flex usw. ist, zu einem Block wird.

Das wäre schwieriger zu warten als eine Blacklist.

Ich habe überlegt, manuell von allen Elternelementen zu verlangen, ebenfalls die Klasse „print-me“ zu haben, aber das würde Geschwisterelemente zum Drucken freigeben, wenn sie es nicht sollten (wenn sie die Klasse nicht haben). Ich habe versucht, das mit einem zu beheben

/* Bad idea #3 (addition to previous) */
.print-me ~ *:not(.print-me) {
  display: none;
}

Aber das behandelt keine vorherigen Geschwister.

Dies könnte ein ziemlich guter Anwendungsfall für Elternelemente-Selektoren in CSS sein, da Sie potenziell einen Elternelemente-Selektor verwenden könnten, um ein Elternelement wieder anzuzeigen, wenn es ein Element mit diesem spezifischen Klassennamen enthält. Theoretisch etwas wie *:contains(.print-me) { display: block; }.

Es mag noch eine reine CSS-Lösung dafür geben. Ich habe zugegebenermaßen keine Stunden damit verbracht. Es mag hier eine clevere Taktik geben, die ich vermisse. Ich weiß, dass die visibility-Eigenschaft nicht vererbt wird, daher könnte es dort Potenzial geben, aber das beeinflusst das Layout nicht so, wie Sie es vielleicht wünschen. Ich bin mir auch nicht sicher, ob :not() hier bis zum vollen Potenzial ausgeschöpft wurde.

Wenn Sie Ideen ausprobieren möchten, hier ist eine Testseite für Sie. Sie hat nur einen Button, der eine Klasse auf dem Elternelement eines Haufens von Inhalten umschaltet, sodass Sie sich diese Klasse wie Print-Styles vorstellen und sie so gestalten können, wie Sie möchten.

Mein bisher nächster Versuch ist ein Versuch, einfach aufzugeben und JavaScript zu verwenden. Unter Verwendung von jQuery für die einfache DOM-Traversal, besteht der Kern darin, einer Klasse automatisch allen Elternelementen einer Klasse hinzuzufügen, um sicherzustellen, dass sie gedruckt werden können.

$(".print-me")
  .parents()
  .addClass("js-print-me");

Beachten Sie, dass ich einen etwas anderen Klassennamen verwende, damit er nicht von derselben Regel betroffen ist, die alle Nachkommen zum Anzeigen auswählt.

@media print {
  * {
    display: none;
  }
  .print-me,
  .print-me * {
    display: block;
  }
  .js-print-me {
    display: block;
  }
}

Es gibt sogar irgendwie Möglichkeiten, ein Druckereignis zu erkennen, sodass Sie eine Elternelementklasse anwenden/entfernen können, um die Seite in diesen Zustand zu versetzen, wenn ein Benutzer zum Drucken geht.

Dies löst jedoch nicht das Inline-Problem (bei dem sie zu Block-Elementen werden, anstatt das Anzeigewert zu behalten, das sie zuvor hatten), was es ziemlich unbrauchbar macht. Wenn Sie JavaScript als akzeptable Option betrachten, könnten Sie die Aufgabe des Verbergens ebenfalls an JavaScript übergeben und display: none; nur anwenden, nachdem der vorherige Anzeigetyp gespeichert wurde, damit Sie ihn wiederherstellen können, wenn Sie fertig sind. Ich glaube, jQuery macht das irgendwie schon?

Gerüchten zufolge gibt es zukünftig einige CSS-Änderungen, die das Umschalten der Sichtbarkeit so handhaben können, dass es nicht an das Layout gebunden ist (und dass dies ein ziemlich guter Anwendungsfall ist).