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:
- Die Eigenschaft
displaywird 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. - 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).
Ich habe gestern bei der Arbeit mit diesen Techniken herumgespielt! Danke, dass Sie einige Dinge für mich geklärt haben. Toller Artikel.
Ich bin mir nicht ganz sicher, ob es ein reales Beispiel dafür gibt, und ich bin persönlich noch nie auf ein Problem gestoßen, bei dem ich das Drucken aktivieren müsste. Erstellt jemand ‚erst drucken‘ CSS?
Wenn man die HTML5-Spezifikation verwendet, würde man mit
<nav>diesen Block normalerweise standardmäßig ausblenden (interaktive Menüs sind im Druck nicht funktionsfähig) und Anker-Link-Anpassungen vornehmen und sonst nicht viel mehr, wenn ich es vermeiden kann!Ich habe am Vortag ebenfalls mit diesen Dingen herumgespielt, nachdem ich deinen Tweet verfolgt hatte. Ich bin zu einer ähnlichen Schlussfolgerung mit JavaScript gekommen, habe aber einfach über Elemente mit der Klasse
print-meiteriert und sie an denbodyangehängt. Auf diese Weise ist die Verschachtelung irrelevant. Schau es dir an: http://codepen.io/hkfoster/pen/LVmwWoWie bereits erwähnt, habe ich dafür keinen wirklichen Anwendungsfall, aber es war trotzdem eine interessante Übung.
.print-me * {display: block;}ist meiner Meinung nach keine gute Idee. Vielleicht gibt es Inline-Nachkommen.Richtig! Deshalb habe ich gesagt
Hoffentlich kann zukünftiges CSS uns mit einem echten Hiding-Toggle mit Einzelverantwortung retten.
Eigentlich muss es nicht so unordentlich sein.
Sie setzen einfach
visibility: hiddenfür das html-Element im Print-Stylesheet und erstellen dann eineprintable-Klasse mitvisibility: visibleund wenden diese selektiv an (effektiv eine Whitelisting-Technik).Dies funktioniert, weil
visibilityin CSS in Kindknoten überschrieben werden kann, währenddisplay: noneden gesamten Teilbaum aus der Anzeigeliste entfernt.Beim Drucken der Seite erhalten Sie stattdessen einen leeren Bereich statt versteckter Elemente.
Richtig! Im Artikel
Das klassische Beispiel ist wahrscheinlich eine Seitenleiste. Sie möchten nicht, dass sie einfach leer ist, sondern dass sie auf null reduziert wird, damit der Hauptinhaltsbereich auf der gedruckten Seite erweitert werden kann.
@Chris: In der Demo, in der Sie die Klasse
.print-meauf einem Kind eines gefloateten Elements und nicht auf dem gefloateten Element selbst haben, gibt es keine Möglichkeit, dass es sich „heraussbricht“ und volle Breite hat. Sie könnten versuchen,width: 100vwzu verwenden, aber das könnte unordentlich werden.Vielen Dank für dieses nützliche Tutorial.
Wie wäre es mit
display: initial;, wie vor einer Weile auf CSS Tricks diskutiert? Wenn dies auf den Selektor.print-me,.print-me * {}angewendet wird, sollte es alle Kindelemente ihren ursprünglichen Zustand erben lassen, richtig?Jelle
Nein,
display: initial;würde genau dasselbe Ergebnis liefern wiedisplay: block;(der initiale Wert für die display-Eigenschaft ist block).Interessant, es gibt einen Vorschlag in CSS Selectors Level 4 für ein Schlüsselwort, das so funktioniert, wie Sie es möchten. Es heißt derzeit
default(obwohl sich das wahrscheinlich noch ändern wird), und es würde die Deklaration auf die User-Agent-Stylesheet (oder die User-Stylesheet, falls vorhanden) zurücksetzen. Da User-Agent-Stylesheets typischerweise Dinge wiep{display:block;}undspan{display:inline;}setzen, bräuchten Sie nur.print-me,.print-me * {display:default;}.Ugh, ich hasse es, wenn man Fehler bemerkt, *nachdem* man einen Kommentar abgeschickt hat. Ich meinte natürlich CSS Cascading and Inheritance Level 4!
Wenigstens habe ich den Link richtig gemacht…
Eilmeldung! Das Schlüsselwort, das früher
defaulthieß, ist jetztrevert.Es gibt andere Möglichkeiten als
display: none, um Inhalt zu verstecken – wir müssen nur eine finden, die leicht in ihren vorherigen Zustand zurückversetzt werden kann.Ooo, das wirft einen interessanten Punkt auf. Ja, wir brauchen einen besseren Hiding-Toggle. Aber vielleicht könnten uns einige dieser alternativen Verbergungsmethoden kurzfristig helfen, wie z. B.
clip()oder position-absolute-kick-off-page.Sie können das Druckereignis nicht verwenden, da es ziemlich schnell ausgelöst wird. Der Browser hat keine Zeit, die JavaScript-Klassenänderungen anzuwenden und das Druckergebnis richtig zu rendern. Der Browser erlaubt Ihnen auch nicht, das Druckereignis zu verzögern, wenn es über die Browser-Oberfläche ausgelöst wird, da es als Browserfehler wahrgenommen werden kann.
Das Druck-Rendering ist in einigen Browsern fehlerhaft, selbst wenn Sie ein verantwortungsbewusstes Print-Stylesheet verwenden müssen. Manchmal funktioniert es nicht, wenn Sie versuchen, die Schriftart, Schriftgröße zu ändern oder ein Bild für den Druck zu ersetzen, da das Rendering ziemlich schnell erfolgt.
Print-Media-Styling sollte so gemacht werden
@media print { * { display:none; } }Um unseres Planeten willen! So mache ich das auf meiner Website, weil das, was online ist, nicht auf Papier sein muss. Möchten Sie es behalten? Setzen Sie ein Lesezeichen. Ganz einfach.
Wahrscheinlich sind Sie derjenige, der Rechtsklick und Strg+C deaktiviert.
Nein, das rettet unseren Planeten nicht.
Hier ist mein bester Versuch: http://codepen.io/shshaw/pen/QbxObX
Zuerst wird alles auf
visibility: hiddengesetzt, außer.print-meund seine Kinder, sodass zumindest die unerwünschten Elemente nicht erscheinen.Dann werden direkte Nachkommen, die nicht
.print-mesind, auf keine Höhe, keinen Rand und keine Polsterung gesetzt. Wenn sie ein.print-me-Element enthalten, sorgtdisplay: tabledafür, dass es sich ausdehnt, um es auszufüllen.width: 100%ist optional, hilft aber Elementen, die volle Breite einzunehmen.Das Setzen von
font-size: 0stellt sicher, dass es sich vollständig zusammenzieht, wobei die Größe mit.print-me { font-size: initial; }zurückgesetzt wird.Keine Ahnung zur Browserunterstützung, aber es scheint ein guter Anfang zu sein.
Das ist eine gute Idee. Ziemlich hacky, aber wenn es sich zu einem CSS-Reset für jede Website entwickeln kann.
Das Problem in Ihrem Fall ist, dass die Seitenleiste, selbst unsichtbar, immer noch realen Platz einnimmt. Wenn es auf ein komplexeres Layout angewendet wird (oder selbst wenn die Seitenleiste links war), können Sie leere Bereiche auf Ihrer Seite haben.
Sie können es jedoch beheben, aber dann müssen Sie Polsterungen beheben und wahrscheinlich einzelne Elemente beheben.
@Kyrodes Das größte Problem mit der Seitenleiste im Beispiel, das Chris erstellt hat, ist, dass die Klasse
.print-meauf einem Kind eines gefloateten Elements liegt und nicht auf dem gefloateten Element selbst. Um dieses Kind volle Breite zu geben, müssten Sie wirklich ins Hack-Territorium geraten undwidth: 100vwsetzen, möglicherweise mit negativen Rändern.Wenn die Klasse
.print-meauf dem gefloateten Element läge, könnten Sie einfach.print-me { float: none; width: 100%; }hinzufügen und fertig. Ich habe die Demo aktualisiert, um das zu veranschaulichen.Es gibt auch den Medientyp
screen, der beim Drucken nicht verwendet wird, sodass Sie bestimmte Elemente nur für den Bildschirm aktivieren können.Um es mit älteren Browsern kompatibel zu machen, könnten Sie
display:nonewahrscheinlich inonly alleinpacken.Das mache ich für Shower-Themes: Ich
screeneinfachall code, den ich nicht im Druck benötige, ein.+1, das ist die sauberste Lösung (der Code beschreibt sich perfekt und erfordert eigentlich keine Dokumentation) und funktioniert überall, wo ich sie getestet habe. Beachten Sie, dass, obwohl einige Geräte/Plattformen andere Nicht-Druck-@media-Typen wie „handheld“ und „projector“ implementiert haben, meines Wissens nach keiner von ihnen dies getan hat, ohne auch für „screen“ true zurückzugeben (wahrscheinlich aus eben diesen Gründen).
PS, Sie müssen nichts tun, wie in Ihrem zweiten Codeblock, um ältere Browser zu unterstützen – einfache @media-Typen wurden überall implementiert, lange bevor Media Queries aufkamen.
Ich bin ziemlich sicher, dass
handheldundprojectorveraltet sind. Aktuell sind nurall,screen,printundspeecherlaubt.IE8 unterstützt
@medianicht, nur<link rel="stylesheet" media="print" href="/print.css" type="text/css" />Wie wäre es mit dem Hinzufügen von
width: initial;zu.fake-print-state *?Blockelemente würden damit die volle Breite einnehmen, es sei denn, ich irre mich.
Sie könnten sogar den Float entfernen, wenn Sie möchten.
Hier ist ein Beispiel: http://codepen.io/TheDutchCoder/pen/GJGQLd
Ich empfehle einen Blick auf jxnblk's ReadRead.
Auf einer Website, die ich entworfen habe, habe ich die Blacklist-Methode verwendet. Es gab jedoch bestimmte Elemente auf der Seite, die ich *nur* anzeigen wollte, wenn sie gedruckt wurden. Ich hatte eine Klasse .noprint und eine Klasse .printonly. Funktionierte ganz gut.
Sie könnten auch die tatsächliche Klasse
.print-megar nicht in Ihr Markup einfügen und einfach einen Präprozessor verwenden, um sie dort zu erweitern, wo sie nützlich ist.So (in LESS)
Durch die Erweiterung der Klasse anstatt sie überall im Markup zu verteilen, umgehen Sie viele der oben genannten Probleme.
Sie können diese Strategie verwenden, um alle möglichen coolen Dinge zu tun.
Ist die Verwendung des universellen Selektors als Nachfahrenelement-Selektor nicht schlecht für die Leistung und gilt als schlechte Praxis? D. h., um zu sehen, ob
.print-me *angewendet werden soll, müssten wir den DOM für jedes Element durchlaufen, um zu sehen, ob eines seiner Eltern die Klasse.print-mehat.Hier ist ein reiner CSS-Whitelist-Ansatz. Die Schlüssel sind: (1) Verwendung von visibility; (2) Verschieben des Druckbereichs nach links oben.
Siehe meine Stack Overflow-Antwort für (ein wenig) mehr Erklärung.
Das gefällt mir!
Aber es schränkt die „Whitelist“ auf eine einzige Liste ein. Daher die ID, die im Demo verwendet wird, nehme ich an.
Robert Stewart schreibt mit einem Plugin für einen alternativen Ansatz
https://github.com/erikzaadi/jQueryPlugins/tree/master/jQuery.printElement/Sample