Der folgende Beitrag ist ein Gastbeitrag von Dylan Winn-Brown, der uns eine performante Methode zeigt, um diesen Designeffekt zu erzielen.
Als ich kürzlich an der Website eines Kunden arbeitete, wurde ich gebeten, einen Effekt wie diesen zu replizieren.

Diese Art von Effekt wird vor allem in Portfoliosituationen eingesetzt, in denen das Design sowohl visuelle als auch informative Details zeigen soll.
Es gibt viele verschiedene mögliche Methoden
Da ich noch nie einen solchen Effekt erstellt hatte, begann ich, mir verschiedene Möglichkeiten anzusehen und stieß auf eine Reihe von verschiedenen Methoden.
Eine Option war die Verwendung eines jQuery Plugins. Dieses entsprach nicht ganz dem Effekt, den ich suchte, und war sicherlich nicht sehr leichtgewichtig.
Eine weitere Option war, ein <img> innerhalb des Containers zu positionieren und es mit CSS zu manipulieren. Hier könnten einige Vorteile liegen, wie z. B. die Möglichkeit, die Quelle mit srcset festzulegen, damit das verwendete Bild leistungs- und gerätegerecht ist.
In meiner Situation wollte ich den Effekt komplett in CSS verwalten, also habe ich mich dafür entschieden.
Grundlegende Funktionalität
Um eine optimale Leistung zu erzielen, habe ich mich entschieden, die CSS-Eigenschaft transform für die Vergrößerung des Bildes zu verwenden. (CSS-Animationen profitieren von Hardwarebeschleunigung und erscheinen daher flüssiger als andere Animationsmethoden.)
Anstelle eines <img> habe ich ein zusätzliches <div> innerhalb des Elternelements verwendet, das als Bild fungiert. Die Struktur ist wie folgt:
<div class="parent">
<div class="child"></div>
</div>
Zuerst legen wir die Abmessungen für das Elternelement fest. Dann kann das Kindelement das Elternelement mit width: 100% und height: 100%; füllen und das Hintergrundbild festlegen, sodass es sich abdeckt.
.parent {
width: 400px;
height: 300px;
}
.child {
width: 100%;
height: 100%;
background-color: black; /* fallback color */
background-image: url("images/city.jpg");
background-position: center;
background-size: cover;
}
Anschließend fügen wir Hover-Effekte zu unserem Elternelement hinzu, die sich auf unser Kindelement auswirken. Ein Fokusstil ist auch gut für die Zugänglichkeit.
.parent:hover .child,
.parent:focus .child {
transform: scale(1.2);
}
Sie möchten möglicherweise ein Tool zur Hinzufügung von Präfixen für die bestmögliche Browserunterstützung verwenden.
Um den grundlegenden Effekt zu vervollständigen, können wir unserem normalen Zustand des Kindelements einige Übergänge hinzufügen.
transition: all .5s;
Wenn Sie eine Farbüberlagerung hinzufügen möchten, können Sie Pseudoelemente wie ::before verwenden.
.child::before {
content: "";
display: none;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(52, 73, 94, 0.75);
}
.parent:hover .child:before,
.parent:focus .child:before {
display: block;
}
Wenn wir nun mit der Maus über das Elternelement fahren, sollte das Kindelement eine Farbüberlagerung anzeigen!
Schließlich behandeln wir, wie man etwas Text hinzufügt, der auf unserer Überlagerung angezeigt werden soll. Wir können ein Element zu unserem aktuellen Kindelement hinzufügen, wie folgt:
<div class="parent">
<div class="child">
<span>Hello</span>
</div>
</div>
Wir können unserem <span> etwas Stil verleihen.
span {
color: white; /* Good thing we set a fallback color! */
font-family: sans-serif;
padding: 25%;
position: absolute;
}
und wir können es nur sichtbar machen, wenn wir mit der Maus über .parent fahren.
.parent:hover span,
.parent:focus span {
display: block;
}
Live-Demo
Siehe den Pen Image zoom on hover – portfolio websites von Dylan (@dwinnbrown) auf CodePen.
Mobile Unterstützung
Wenn die Container Links sind und die Hover-Zustände keine wesentlichen Informationen preisgeben, können Sie sie auch so belassen.
Wenn die Hover-Zustände wichtig sind und damit dies auf Touchscreens funktioniert, können wir leere onclick="" Handler auf unseren .parent Containern verwenden. Leider konnte ich keine andere Möglichkeit finden, dies zu tun, aber wenn Ihnen eine einfällt, lassen Sie es mich in den Kommentaren wissen!
Ich glaube, iOS löst Hover-Zustände aus, wenn das Element
cursor: pointerhat; ist es das einzige?Mobile Unterstützung – funktionierte im Silk Browser auf meinem Kindle (5. Generation/2015)
Ich weiß, dass Sie versuchen, den Effekt zu zeigen, aber ich würde vorschlagen, ihn subtiler zu gestalten. Viele sogenannte Coder kommen auf Ihre Website und kopieren ihn einfach. Und dann würden wir den augentränen-Effekt überall sehen. Danke für Ihre Berücksichtigung.
—
Wie http://codepen.io/anon/pen/GqPqpG
Danke
Sie haben die Methode, mit der die Fitbit-Website, die im einleitenden Absatz verwendet wurde, den Effekt erzielt (und die Art und Weise, wie ich ursprünglich diesen Effekt angehen wollte), nicht diskutiert, nämlich die Verwendung der Eigenschaft
background-size.Die Verwendung von Hintergrundbildern und die anschließende Animation der Größe beim Überfahren mit der Maus scheint ein solider Ansatz zu sein, da er den gesamten Code in der Stylesheet-Datei belässt, was Sie als Anforderung erwähnt haben, und keine zusätzlichen Elemente zum HTML hinzufügt, um Styling-Belange zu erzielen, wie bei der von Ihnen gewählten Methode.
Das Problem dabei ist, dass
background-sizebei weitem nicht so flüssig animiert wie ein Transform. Mir gefällt auch, wie sauber und einfach dieser Code ist, aber der Leistungsvorteil durch die reine Verwendung eines Transforms ist es wert.Etwas an der Verwendung von Hintergrundbildern für eine Bildergalerie erscheint mir falsch.
Ich weiß, dass es darum ging, diesen Effekt nur mit einigen
<div>Tags und CSS anzuwenden, aber ich habe eine Version für alle erstellt, die dies mit<img>Tags tun möchten: http://codepen.io/anon/pen/EyGmQxUnd es ist auch ein unangenehmer Ressourcenfresser. Die CPU steigt auf 11, sobald ich mit der Maus über die Bilder fahre ... also ... nein. nicht meins (das ist auf einem einfachen i5-2520 / T520).
Meiner Meinung nach liegt der Vorteil der Hintergrundlösung darin, dass das Skalieren a) viel flüssiger (und ressourcenschonender) ist und b) Spaß mit Media Queries macht = man muss sich nicht mit dem aktuellen, tristen Zustand von „responsive images“ auseinandersetzen.
cu, w0lf.
Ich möchte auch auf ein weiteres Problem mit
background-imagehinweisen – wenn Sie Bildquellen vom Server beziehen, können Sie diese nicht so einfach verwenden, wie Sie es mit einem normalen<img>Tag tun können.@fwolf, ich bin mir nicht sicher, warum Sie einen CPU-Anstieg sehen würden, wenn Sie mit der Maus über die Bilder fahren, da CSS-Transformationen von der GPU behandelt würden.
Wenn es tatsächlich einen Leistungsgewinn durch die Verwendung von Hintergrundbildern gibt, dann sollte progressive Verbesserung durch JavaScript verwendet werden, um die Bilder durch die Hintergrundbildversion zu ersetzen, aber ich bin nicht davon überzeugt, dass es *irgendein* Leistungsproblem gibt.
Meine Hauptbeschwerden bei Hintergrundbildern beziehen sich auf die Trennung von Belangen, Semantik und Zugänglichkeit. Best Practices scheinen mit der Weiterentwicklung des Internets immer öfter hinter das Schöne zurückzutreten.
Es gibt ein Problem mit Ihrer Hintergrundbild-Demo. Der Viewport (sichtbarer Bereich der Demoseite) scrollt automatisch auf und ab, wenn man mit der Maus über die Bilder fährt und sie wieder verlässt. (Die Bilder können auf meinem [MacBook]-Monitor nicht vollständig angezeigt werden.) Das passiert bei der CSS-Tricks-Demo nicht.
Warum nicht die Ideen kombinieren und das Hintergrundbild in ::before platzieren, dies transformieren und das Bildelement so ausblenden, dass Screenreader es trotzdem zugreifen können. Außerdem sind die Elemente figure und figcaption definitiv besser geeignet als div.parent, div.child und ein span.
Kleine Ergänzung: Ein weiterer Kommentar, dem ich zugestimmt habe, ist, dass die Animation viel zu stark ist. Ich fand Werte von ca. 0,9 s Transformationszeit und ein Skalierungsfaktor zwischen 5 und 10 % viel angenehmer. Dieser Effekt sollte subtil sein. Aber das ist natürlich subjektiv.
Darf ich fragen, warum es ein weiteres
<div>(class 'child')im Container gibt und nicht stattdessen ein Pseudoelement verwendet wird? Es gibt keinen Grund, den Code zu komplizieren. Außerdem könnte hier Semantik besser sein.Er verwendet bereits Pseudoelemente für das Kindelement selbst.
Wenn Sie das Kind absolut positionieren, oben 0, links 0 und so weiter, können Sie den Z-Stack leichter steuern. Dies ist nützlich, wenn Sie Schichten mit .sibling für Bildeffekte hinzufügen möchten, z. B. eine Vignette mit einem inneren Schatten. Sie sollten auch Sichtbarkeit und Opazität verwenden, nicht display: none, da Sie dies nicht animieren/übergangsgestalten können. Folgen Sie mir auf Codepen @CodeBoomer und YouTube +Boomer, ich werde in ein paar Tagen ein Beispiel erstellen, wenn ich Zeit habe.
Um eine noch bessere Leistung zu erzielen, können Sie
will-change:transform;verwenden, um das Kind in eine eigene GPU-Ebene zu verschieben. Ich habe eine schnelle Demo gemacht, und die Framerate während der eigentlichen Animation halbiert sich auf meinem Computer!+1
Fantastisch!
Ich bevorzuge es, von <1 auf 1 zu skalieren, anstatt von 1 auf höher, damit das Bild nicht verschwimmt.
Mit CSS würde es wahrscheinlich darum gehen, ein DIV zu verwenden, um das Bild fixiert zu halten und immer 100 % der angezeigten Fläche abzudecken. Von
natürlich werden CSS und HTML vom Server generiert und gesendet, daher sollten Sie das DIV mit JavaScript skalieren.
Es ist wahrscheinlich schöner (semantischer), ein tatsächliches Bildelement zu verwenden. Sie erhalten die gleiche Kontrolle wie bei einem Hintergrundbild (mit object-fit anstelle von background-size und srcset für verschiedene Größen). Das Einzige, was Sie tun müssten, ist das richtige Seitenverhältnis für das Bild zu erstellen (was Sie bereits abgedeckt haben) https://css-tricks.de/snippets/sass/maintain-aspect-ratio-mixin/
Tauschen Sie den Standard-Linear-Übergang gegen einen Cubic-Bezier aus und siehe da, überall sexy Zooms!
Eine mögliche (wenn auch kaum semantische) Lösung für Mobiltelefone sind versteckte Radio-Buttons und ihre zugehörigen Labels: Sie verstecken den
input, wickeln daslabelum das, was Sie anzeigen/ausblenden möchten, und verwenden dann diechecked-Eigenschaft (Attribut?), um zwischen den gewünschten Zuständen zu wechseln, ohne JavaScript zu benötigen. Diese Seite verwendet ein Beispiel dieser Technik: http://coxlawpdx.com/results/Schwächen: Macht keinen semantischen Sinn; keine wirkliche Möglichkeit, alle Elemente abzuwählen.
Ich bevorzuge es, die Überlagerung und den Text zu animieren, wenn sie erscheinen, damit es nicht so abrupt ist, wie beim Wechseln von
display: nonezudisplay: block. Hier ist ein Beispiel, bei dem ich die Eigenschaftenvisibilityundopacityverwende, um einen flüssigeren Übergang zu erzielen.http://codepen.io/praliedutzel/pen/GqPXPo
Das gefällt mir. Gute Ergänzung.
+1
Zuerst einmal vielen Dank an Dylan Winn-Brown für das Teilen dieses sehr schönen Effekts.
Hier ist mein Beitrag.
Ich habe versucht, nur zwei Elemente ohne Pseudoelemente :before oder :after zu verwenden. Der Text ist ursprünglich auf „color: transparent;“ gesetzt und wird dann mit einem Übergang zu „color: #f2f2f2;“ animiert.
Mit „background-blend-mode“ und „background-color“ im Hover-Zustand habe ich einen dunkleren Hintergrund erstellt.
Hier ist der Link zu Codepen: http://codepen.io/anon/pen/oLJaOB
Ok, ich habe diesen Pen erstellt: http://codepen.io/CodeBoomer/pen/ZOVPZb
Ich habe
– Das Hintergrundbild mit Inline-Stil injiziert, um JS zu replizieren, da Sie dies nicht in CSS deklarieren würden.
– 3 Kinder für das (Elternelement) erstellt, weil:
a) Das Bild benötigt einen eigenen Kindknoten, da Sie dieses Element beim Überfahren mit der Maus skalieren. Durch die Anwendung von will-change wird der Transform nur auf das Bild angewendet.
b) Jegliche Bildfilter können bei Pseudoelementen genutzt werden (performen jedoch schlecht bei Transforms).
c) Farbüberlagerungen beim Hover müssen nicht transformiert werden (ich habe einen radialen Verlauf und eine Schattierung angewendet, um eine Vignette zu erzeugen).
d) Sie können Zugänglichkeit mit dem Namen/der Beschreibung in einem eigenen Knoten ausgleichen. Außerdem können Sie dies mit anderer Zeitsteuerung für einen halb-perspektivischen Effekt transformieren.
e) Es erleichtert die Steuerung der Stapelreihenfolge.
Sichtbarkeit und Opazität anstelle von display: none/block verwendet, da display nicht animierbar ist.
Einfaches Flexbox-Layout zur Unterbringung der Elemente erstellt.
Obwohl ich den Pen geforkt habe, habe ich ihn gestrippt und das Ganze neu aufgebaut und SASS verwendet.
Den CSS-Code mit Flex-Eigenschaften aufgebläht, um ihn etwas leichter verständlich zu machen.
Eigene Mixin für absolute Positionierung erstellt, da niemand die lange Version schreiben möchte.
Ich freue mich über Feedback/Kritik. Denken Sie daran, mir auf Codepen zu folgen, und ich werde bald ein Video dazu in meiner Let's Codepen-Serie auf YouTube veröffentlichen. Abonnieren Sie meinen Kanal https://www.youtube.com/channel/UCydykDsTWRIVnxKHW3SHPQA
Vielen Dank für all das Feedback, Jungs – ich hoffe, es hilft einigen von Ihnen, wenn Sie jemals einen solchen Effekt benötigen.
Obwohl es SASS verwendet, scheint dieser Code ^ die beste Leistung unter den von mir gesehenen alternativen Methoden zu haben :)
Meine einzige Änderung wäre am Kind-Pseudoelement, anstatt „display:none“ und „display:block“ zu machen, warum nicht einfach die Alpha auf 0 und .75 ändern und die display-Eigenschaft entfernen?
.child::before {
content: “”;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(52, 73, 94, 0);
}
.parent:hover .child:before,
.parent:focus .child:before {
background-color: rgba(52, 73, 94, 0.75);
}
Ein Gedanke zur „mobilen“ Unterstützung
Ich verwende eine kleine Feature-Erkennung per JS. Wenn Touch-Unterstützung vorhanden ist, ersetze ich die Body-Klasse „no-touch“ durch „has-touch“.
Das gibt mir die Möglichkeit, den Titel dauerhaft anzuzeigen. So bekommt der Benutzer eine bessere Erfahrung. Im Fall Ihrer Demo muss der Benutzer nicht raten, wo sich das Bild befindet.
Außerdem würde ich die Vorschläge von @praliedutzel und @Filip Bech-Larsen integrieren, die die Demo nahezu perfekt machen würden.