Moving Backgrounds

Avatar of Saleh Mubashar
Saleh Mubashar am

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

Wir denken oft an Hintergrundbilder als Textur oder etwas, das Kontrast für lesbare Inhalte bietet – mit anderen Worten, nicht wirklich Inhalt. Wenn es Inhalt wäre, würden Sie sich wahrscheinlich sowieso für ein <img> entscheiden, Barrierefreiheit und so weiter.

Aber es gibt Zeiten, in denen die Position oder die Skalierung eines Hintergrundbildes irgendwo zwischen den Polen von Inhalt und Dekoration liegen können. Kontext ist König, richtig? Wenn wir die Position des Hintergrundbildes ändern, kann dies etwas mehr Kontext oder Erfahrung vermitteln.

Wie so? Schauen wir uns ein paar Beispiele an, die ich habe herumschwirren sehen.

Zu Beginn möchte ich Sie warnen, dass in diesen Demos eine feine Linie zwischen Bildern, die zur Dekoration verwendet werden, und Bildern, die als Inhalt verwendet werden, verläuft. Der Unterschied hat Auswirkungen auf die Barrierefreiheit, da Hintergründe für Screenreader nicht angekündigt werden. Wenn Ihr Bild wirklich ein Bild ist, dann sollten Sie vielleicht ein <img> Tag mit richtigem alt Text in Betracht ziehen. Und während wir über Barrierefreiheit sprechen, ist es eine gute Idee, die Bewegungseinstellungen eines Benutzers zu berücksichtigen.

Zeig mir mehr!

Chris Coyier hat dieses nette kleine Demo von vor einigen Jahren.

Die Demo ist in vielerlei Hinsicht super praktisch, da sie ein großartiger Ansatz zur Anzeige von Anzeigen im Inhalt ist. Sie haben den Verkaufs-Pitch und ein ansprechendes Bild, das ihn ergänzt.

Die große Einschränkung für die meisten Anzeigen ist, wie ich vermute, der begrenzte Platz. Ich weiß nicht, ob Sie jemals eine Anzeige auf eine Seite setzen mussten, aber ich habe es getan und frage den Werbetreibenden normalerweise nach einem Bild, das exakte Pixelabmessungen erfüllt, damit das Asset in den Raum passt.

Aber Chris' Demo mildert das Platzproblem. Fahren Sie mit der Maus über das Bild und beobachten Sie, wie es sich sowohl bewegt als auch skaliert. Der Benutzer erhält tatsächlich mehr Kontext für das Produkt, als er ihn hätte, wenn das Bild in seiner ursprünglichen Position wäre. Das ist ein Win-Win, oder? Der Werbetreibende kann ein auffälliges Bild erstellen, ohne den Kontext zu beeinträchtigen. In der Zwischenzeit erhält der Benutzer einen kleinen Mehrwert durch die neu enthüllten Teile des Bildes.

Wenn Sie sich den Markup der Demo ansehen, werden Sie feststellen, dass es ziemlich dem entspricht, was Sie erwarten würden. Hier ist eine gekürzte Version

<div class="ad-container">
  <a href="#" target="_blank" rel="noopener">
    <!-- Background image container  -->
    <div class="ad-image"></div>
  </a> 
  <div class="ad-content">
    <!-- Content -->
  </div>
</div>

Wir könnten wahrscheinlich ein wenig über die Semantik streiten, aber das ist nicht der Punkt. Wir haben einen Container mit einem verknüpften <div> für das Hintergrundbild und einem weiteren <div>, um den Inhalt zu halten.

Was das Styling angeht, sind die wichtigen Teile hier

.container {
  background-image: url("/path/to/some/image.png");
  background-repeat: no-repeat;
  background-position: 0 0;
  height: 400px;
  width: 350px;
}

Nicht schlecht, oder? Wir geben dem Container einige Dimensionen und setzen ein Hintergrundbild darauf, das sich nicht wiederholt und vom unteren linken Rand aus positioniert ist.

Der eigentliche Trick liegt in JavaScript. Wir werden dies verwenden, um die Mausposition und den Offset des Containers zu ermitteln, dann diesen Wert in eine geeignete Skalierung umwandeln, um die background-position festzulegen. Zuerst hören wir auf Mausbewegungen auf dem .container Element

let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
    // Our function
  }
);

Von hier aus können wir die offsetX und offsetY Eigenschaften des Containers verwenden. Aber wir werden diese Werte nicht direkt verwenden, da der Wert für die X-Koordinate kleiner ist als das, was wir brauchen, und die Y-Koordinate größer ist. Wir werden ein wenig spielen müssen, um eine Konstante zu finden, die wir als Multiplikator verwenden können.

Es ist ein bisschen "Fingerspitzengefühl", aber ich habe festgestellt, dass 1.32 und 0.455 für die X- und Y-Koordinaten jeweils perfekt funktionieren. Wir multiplizieren die Offsets mit diesen Werten, fügen eine px Einheit zum Ergebnis hinzu und wenden sie dann auf die background-position Werte an.

let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
    container.style.backgroundPositionX = -e.offsetX * 1.32 + "px";
    container.style.backgroundPositionY = -e.offsetY * 0.455 + "px";
  }
);

Zuletzt können wir auch die Hintergrundpositionen auf die ursprünglichen zurücksetzen, wenn der Benutzer den Bildcontainer verlässt.

container.addEventListener("mouseleave", function() {
    container.style.backgroundPosition = "0px 0px";
  }
);

Da wir auf CSS-Tricks sind, werde ich vorschlagen, dass wir eine viel günstigere Version davon mit einem kleinen Hover-Übergang in reinem CSS hätten machen können

Mal ein größeres Bild

Zweifellos waren Sie schon in einem Online-Bekleidungsgeschäft oder so und sind auf die altbekannte Zoom-on-hover-Funktion gestoßen.

Dieses Muster gibt es schon seit Ewigkeiten (Dylan Winn-Brown teilte seinen Ansatz im Jahr 2016), aber das ist nur ein Beweis (hoffentlich) für seine Nützlichkeit. Der Benutzer erhält mehr Kontext, wenn er hineinzoomt und sich die Maschen eines Pullovers oder was auch immer genauer ansieht.

Es gibt zwei Teile davon: den Container und den Lupe. Der Container ist das Einzige, was wir im Markup brauchen, da wir das Lupenelement während der Interaktion des Benutzers einfügen werden. Also, seht her unser HTML!

<div class="container"></div>

Im CSS erstellen wir width und height Variablen, um die Abmessungen des Lupenglases selbst zu speichern. Dann geben wir diesem .container etwas Form und ein background-image.

​​:root {
​​  --magnifer-width: 85;
​​  --magnifer-height: 85;
​​}

.container {
  width: 500px;
  height: 400px;
  background-size: cover;
  background-image: url("/path/to/image.png");
  background-repeat: no-repeat;
  position: relative;
}

Es gibt einige Dinge, die wir über die Lupe wissen, noch bevor wir sie überhaupt sehen, und wir können diese Stile im Voraus definieren, insbesondere die zuvor definierten Variablen für width und height des .maginifier.

.magnifier {
  position: absolute;
  width: calc(var(--magnifer-width) * 1px);
​​  height: calc(var(--magnifer-height) * 1px);
​​  border: 3px solid #000;
​​  cursor: none;
​​  background-image: url("/path/to/image.png");
​​  background-repeat: no-repeat;
}

Es ist ein absolut positioniertes kleines Quadrat, das die gleichen Hintergrundbilddatei wie der .container verwendet. Beachten Sie, dass die calc-Funktion hier ausschließlich verwendet wird, um den einheitenlosen Wert in der Variablen in Pixel umzuwandeln. Fühlen Sie sich frei, dies nach Belieben anzuordnen, um Wiederholungen in Ihrem Code zu vermeiden.

Nun zum JavaScript, das dies alles zusammenbringt. Zuerst müssen wir auf die zuvor definierte CSS-Variable zugreifen. Wir werden sie später an mehreren Stellen verwenden. Dann müssen wir die Mausposition innerhalb des Containers ermitteln, denn das ist der Wert, den wir für die Hintergrundposition der Lupe verwenden werden.

​​// Get the css variables
​​let root = window.getComputedStyle(document.documentElement);
​​let magnifier_width = root.getPropertyValue("--magnifer-width");
​​let magnifier_height = root.getPropertyValue("--magnifer-height");

let container = document.querySelector(".container");
let rect = container.getBoundingClientRect();
let x = (e.pageX - rect.left);
let y = (e.pageY - rect.top);

// Take page scrolling into account
x = x - window.pageXOffset;
y = y - window.pageYOffset;

Was wir brauchen, ist im Grunde ein mousemove Event-Listener auf dem .container. Dann verwenden wir die event.pageX oder event.pageY Eigenschaft, um die X- oder Y-Koordinate der Maus zu erhalten. Aber um die exakte relative Position der Maus auf einem Element zu erhalten, müssen wir die Position des Elternelements von der Mausposition, die wir aus dem obigen JavaScript erhalten, abziehen. Eine "einfache" Methode hierfür ist die Verwendung von getBoundingClientRect(), das die Größe eines Elements und seine Position relativ zum Viewport zurückgibt.

Beachten Sie, wie ich das Scrollen berücksichtige. Wenn Überlauf vorhanden ist, stellt das Subtrahieren der Fenster-pageX und pageY Offsets sicher, dass der Effekt wie erwartet funktioniert.

Wir werden zuerst die Lupe-Div erstellen. Als Nächstes erstellen wir eine mousemove Funktion und fügen sie dem Bildcontainer hinzu. In dieser Funktion geben wir der Lupe ein Klassenattribut. Wir werden auch die Mausposition berechnen und der Lupe die zuvor berechneten linken und oberen Werte zuweisen.

Lassen Sie uns die magnifier erstellen, wenn wir ein mousemove Event auf dem .container hören

// create the magnifier
let magnifier = document.createElement("div");
container.append(magnifier);

Jetzt müssen wir sicherstellen, dass sie einen Klassennamen hat, den wir im CSS einschränken können

// run the function on `mousemove`
container.addEventListener("mousemove", (e) => {
  magnifier.setAttribute("class", "magnifier");
}

Das Beispielvideo, das ich zuvor gezeigt habe, positioniert die Lupe außerhalb des Containers. Wir halten es einfach und überlagern es stattdessen auf dem Container, wenn sich die Maus bewegt. Wir verwenden if Anweisungen, um die Position der Lupe nur dann festzulegen, wenn die X- und Y-Werte größer oder gleich Null und kleiner als die Breite oder Höhe des Containers sind. Das sollte sie im Rahmen halten. Stellen Sie nur sicher, dass Sie die Breite und Höhe der Lupe von den X- und Y-Werten abziehen.

// Run the function on mouse move.
container.addEventListener("mousemove", (e) => {
  magnifier.setAttribute("class", "magnifier");

  // Get mouse position
  let rect = container.getBoundingClientRect();
  let x = (e.pageX - rect.left);
  let y = (e.pageY - rect.top);
  
  // Take page scrolling into account
  x = x - window.pageXOffset;
  y = y - window.pageYOffset;

  // Prevent magnifier from exiting the container
  // Then set top and left values of magnifier
  if (x >= 0 && x <= container.clientWidth - magnifier_width) {
    magnifier.style.left = x + "px";
  }
  if (y >= 0 && y <= container.clientHeight - magnifier_height) {
    magnifier.style.top = y + "px";
  }
});

Zuletzt, aber keineswegs unwichtig... wir müssen ein wenig mit dem Hintergrundbild der Lupe spielen. Der ganze Sinn ist, dass der Benutzer eine GRÖSSERE Ansicht des Hintergrundbildes erhält, basierend darauf, wo die Überlagerung stattfindet. Definieren wir also eine Lupe, mit der wir die Dinge skalieren können. Dann definieren wir Variablen für die Breite und Höhe des Hintergrundbildes, damit wir etwas haben, auf dem wir die Skalierung basieren können, und weisen all diese Werte den .magnifier Styles zu.

// Magnifier image configurations
let magnify = 2;
let imgWidth = 500;
let imgHeight = 400;

magnifier.style.backgroundSize = imgWidth * magnify + "px " + imgHeight * magnify + "px";

Lassen Sie uns die X- und Y-Koordinaten des Bildes der Lupe nehmen und sie auf die background-position des .magnifier Elements anwenden. Wie zuvor bei der Position der Lupe müssen wir die Breite und Höhe der Lupe von den X- und Y-Werten unter Verwendung der CSS-Variablen abziehen.

// the x and y positions of the magnifier image
let magnify_x = x * magnify + 15;
let magnify_y = y * magnify + 15;

// set backgroundPosition for magnifier if it is within image
if (
  x <= container.clientWidth - magnifier_width &&
  y <= container.clientHeight - magnifier_height
) {
  magnifier.style.backgroundPosition = -magnify_x + "px " + -magnify_y + "px";
}

Tada!

Machen Sie es filmisch

Haben Sie den Ken Burns-Effekt gesehen? Es ist eine klassische und zeitlose Sache, bei der ein Bild größer ist als der Container, in dem es sich befindet, und dann langsam wie eine Schnecke gleitet und skaliert. Fast jeder Dokumentarfilm der Welt scheint ihn für Standbilder zu verwenden. Wenn Sie einen Apple TV haben, haben Sie ihn sicherlich auf dem Bildschirmschoner gesehen.

Es gibt jede Menge Beispiele auf CodePen, wenn Sie sich eine bessere Vorstellung machen möchten.

Sie werden feststellen, dass es eine Reihe von Möglichkeiten gibt, dies anzugehen. Einige verwenden JavaScript. Andere sind 100% CSS. Ich bin sicher, dass die JavaScript-Ansätze für einige Anwendungsfälle gut sind, aber wenn das Ziel einfach nur das subtile Skalieren des Bildes ist, ist CSS perfekt geeignet.

Wir könnten die Dinge mit mehreren Hintergründen anstelle eines einzigen aufpeppen. Oder, noch besser, wenn wir die Regeln erweitern, um Elemente anstelle von Hintergrundbildern zu verwenden, können wir die gleiche Animation auf alle Hintergründe anwenden und einen Schuss animation-delay verwenden, um den Effekt zu staffeln.

Viele Wege, dies zu tun, natürlich! Es kann sicherlich mit Sass und/oder CSS-Variablen optimiert werden. Verdammt, vielleicht schaffen Sie es mit einem einzigen <div>. Wenn ja, teilen Sie es in den Kommentaren!

Bonus: Machen Sie es immersiv

Ich weiß nicht, ob etwas cooler ist als Sarah Drasners "Happy Halloween"-Stift... und das ist aus dem Jahr 2016! Es ist ein großartiges Beispiel, das Hintergründe schichtet und sie mit unterschiedlichen Geschwindigkeiten bewegt, um ein fast filmisches Erlebnis zu schaffen. Meine Güte, ist das cool!

GSAP ist der Haupttreiber dort, aber ich stelle mir vor, wir könnten eine abgespeckte Version machen, die einfach jede Hintergrundschicht mit unterschiedlichen Geschwindigkeiten von links nach rechts verschiebt. Nicht so cool natürlich, aber sicherlich das Grunderlebnis. Man muss sicherstellen, dass Anfang und Ende jedes Hintergrundbildes konsistent sind, damit es sich nahtlos wiederholt, wenn die Animation wiederholt wird.


Das war's für jetzt! Ziemlich cool, dass wir Hintergründe für viel mehr als nur Textur und Kontrast verwenden können. Ich bin absolut sicher, dass es unzählige andere clevere Interaktionen gibt, die wir auf Hintergründe anwenden können. Temani Afif hat genau das mit ein paar netten Hover-Effekten für Links getan. Was haben Sie vor? Teilen Sie es mir in den Kommentaren mit!