Eine Reise mit Vignettierung (die nicht sehr weit kommt)

Avatar of Chris Coyier
Chris Coyier am

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

Ol’ Trent postete einen kurzen Tipp-Post über die Verwendung von `inset` box-shadow für einige einfache, aber klassische Effekte. Eine dieser Techniken führte zu einem Vignettierungseffekt über einem Bild. So:

Ja, das könnte man in Photoshop machen, aber wenn man es über CSS macht, bedeutet das 1) es ist nicht-destruktiv 2) kann es programmatisch geändert werden 3) ist es super konsistent.

Als ich das Beispiel zum ersten Mal sah, dachte ich: „Hey, das ist ziemlich cool, aber warum die umgebende div?“ Browser erlauben box-shadow für <img>-Elemente, also warum nicht einfach einen inset box-shadow darauf anwenden. Das wäre saubereres HTML.

<img src="amazinglandscape.jpg" alt="ooooh ahhhh" class="vignette">
.vignette {
	-webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4);
	-moz-box-shadow:    inset 0px 0px 85px rgba(0,0,0,0.4);
	box-shadow:         inset 0px 0px 85px rgba(0,0,0,0.4);
}

Es stellt sich heraus, dass man inset box-shadows auf Bildern verwenden kann, nur dass der Browser sie hinter das Bild setzt, was bedeutet, dass man den Schatten überhaupt nicht sieht, wenn man ein vollständig opakes Bild verwendet (was sehr wahrscheinlich ist, wenn man daran interessiert ist, es zu vignettieren). Worauf Trent sagt:

Während dies ziemlich nutzlos erscheint, ergibt es Sinn, wenn man andere Arten von Inhalten betrachtet. Zum Beispiel würde man, wenn man einen Schatten einfügt, wahrscheinlich nicht wollen, dass er den Text darin überschattet.

Ich stimme auch einem anderen Punkt von Trent zu: Vielleicht sollte die offizielle Spezifikation für box-shadow geändert werden, um zu besagen, dass der Schatten, wenn er direkt auf ein Bild angewendet wird, oben liegen sollte. Nun, weder die Spezifikation noch die Implementierungen tun dies.

Dann dachte ich: „Hey, Moment mal, lass uns noch nicht zu einem umgebenden Element greifen.“ Schließlich ist es ein ehrenwertes Ziel, unser HTML frei von nicht-semantischen Umgebungen zu halten. Warum verwenden wir nicht ein Pseudo-Element auf dem Bild, das wir zwingen können, oben zu sitzen und die genaue Größe des Bildes zu haben, und wenden den inset box-shadow darauf an?

.vignette:after {
	-webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4);
	-moz-box-shadow:    inset 0px 0px 85px rgba(0,0,0,0.4);
	box-shadow:         inset 0px 0px 85px rgba(0,0,0,0.4);

	position: absolute;
	top: 0; left: 0; bottom: 0; right: 0;
	content: "";
}

Als ich an einer Demo dafür arbeitete, funktionierte es immer wieder nicht und verwirrte mich total. Für einen Moment dachte ich: „Ich frage mich, ob :before und :after Pseudo-Elemente einfach nicht auf Inline-Elemente funktionieren*“, aber ich habe bewiesen, dass sie mit Spans funktionieren, also war das ausgeschlossen.

Dann hörte ich von Nicholas Gallagher

Keine Elemente mit einem „leeren“ Inhaltsmodell unterstützen generierten Inhalt über Pseudo-Elemente.

Damit meint Nicolas im Wesentlichen jedes Element, das keinen innerHTML hat. Denk an

<br />
<br />
<input />
<img />

Dies liegt anscheinend daran, dass die Spezifikation nicht erklärt hat, wie mit Elementen dieser Art umzugehen ist.

Ähnlich wie bei der Sache mit dem inset box-shadow ergibt es irgendwie Sinn. Man kann sich ein :before Pseudo-Element als innerhalb der Tags, aber vor anderem Inhalt vorstellen, und ein :after Pseudo-Element als innerhalb der Tags, aber nach anderem Inhalt.

<div>
   <!-- :before pseudo element -->
   Hi! I'm content!
   <!-- :after pseudo element -->
</div>

<img /> <!-- Where would pseudo content go? -->

Für jQuery-Leute erklärt Tim Wright

es ist so, dass :after mehr wie das .append() von jQuery ist als .after(), so dass man nichts in die Mitte von <img> werfen kann.

Wenn Sie denken: „Alter, pack die Pseudo-Elemente EINFACH NACH oder VOR das verdammte Element“, sind Sie nicht allein. Das Problem ist, dass dies nicht mit anderen Elementen übereinstimmt und die Spezifikation dies nicht abdeckt. Um die Sache noch komplizierter zu machen, ist dies tatsächlich das, was Opera tut.

Also, das war's für Ideen, wie man es sauber machen kann. Nehmen wir einfach die umgebende div und machen wir es hinter uns.

<div class="vignette">
	<img src="handsomepeople.jpg" alt="ooooh ahhhh">
</div>
.vignette {
	-webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4);
	-moz-box-shadow:    inset 0px 0px 85px rgba(0,0,0,0.4);
	box-shadow:         inset 0px 0px 85px rgba(0,0,0,0.4);
	
	line-height: 0;         /* ensure no space between bottom */
		
	display: inline-block;  /* don't go wider than image */
}
.vignette img {
	position: relative; 
	z-index: -1;            /* position beneath */
}

Ein möglicherweise wünschenswerter, möglicherweise ärgerlicher Nebeneffekt? Mit dem div-Overlay kann man nicht mit der rechten Maustaste klicken, um das Bild zu speichern, oder es auf den Desktop ziehen. Super primitiver Bildschutz.

Demo ansehen

Verwandt

  • Eine weitere Technik von Dudley Storey, bei der das Bild als Hintergrundbild des vignettierten Elements verwendet wird. Wahrscheinlich besser für einmalige Anlässe, aber schwieriger für Websites, auf denen man es einfach überall verwenden möchte, ohne ständig CSS ändern zu müssen.

* Übrigens habe ich Introducing HTML5 gelesen und einen interessanten Punkt gelernt. In HTML5 gibt es wirklich keinen Unterschied zwischen einem „Inline“-Element und einem „Block“-Element. Alle Elemente sind inline, bis sie anderweitig von einem Browser- oder Benutzerstylesheet spezifiziert werden.