Hiding Text - Teil 3

Hiding Text - Teil 3

Tauchen Sie ein in die faszinierende Welt der Animation mit GSAP (GreenSock Animation Platform). Erleben Sie die Magie fließender Bewegungen, atemberaubender Effekte und dynamischer Interaktionen. Mit GSAP können Sie Ihre Website zum Leben erwecken und Ihren Benutzern ein unvergessliches Erlebnis bieten. Entdecken Sie die grenzenlosen Möglichkeiten von GSAP und lassen Sie Ihrer Kreativität freien Lauf!

GSAP, ScrollTrigger und ScrollToPlugin

In diesem Tutorial nutzen wir GSAP, ScrollTrigger und ScrollToPlugin um noch weitere Effekte zu bekommen. Erst binden diese scripte in unsere html ein, über unsere script Datei.
// index.html
...
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"
      integrity="sha512-7eHRwcbYkK4d9g/6tD/mhkf++eoTHwpNM9woBxtPUBWm67zeAfFC+HrdoE2GanKeocly/VxeLvIqwvCdk7qScg=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.1/ScrollTrigger.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.1/ScrollToPlugin.min.js"></script>
...

Texteffekt (Text scrollen)

Als nächste wollen wir einen Texteffekt beim scrollen haben, um dieses zu erreichen werden wir unseren text etwas durchsichtiger machen.
// assets/styles.css

:root {
  --bg: #272c3b;
  --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --color-body: #b7ab98;
  --color-text: rgb(183, 171, 152, 1);
  --color-text-transparent: rgb(183, 171, 152, 0.2);
  --color-text-navi: rgb(183, 171, 152, 0.5);
}
color-text-transparent setzen wir rgb(183, 171, 152, 0.2).
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                                 text scroll                                */
/* -------------------------------------------------------------------------- */

gsap.registerPlugin(ScrollTrigger);

const textElements = gsap.utils.toArray(".text");

textElements.forEach((text) => {
  gsap.to(text, {
    backgroundSize: "100%",
    ease: "none",
    scrollTrigger: {
      trigger: text,
      start: "center 70%",
      end: "center 30%",
      scrub: true,
    },
  });
});
Dieser Code verwendet die GSAP-Bibliothek (GreenSock Animation Platform) zusammen mit dem ScrollTrigger-Plugin, um einen Effekt zu erzeugen, bei dem der Hintergrund von Textelementen beim Scrollen animiert wird.

  1. Zuerst wird das ScrollTrigger-Plugin registriert, um es mit GSAP zu verwenden.
  2. Dann werden alle Elemente mit der Klasse "text" ausgewählt und in ein Array namens "textElements" gespeichert.
  3. Anschließend wird für jedes dieser Textelemente eine GSAP-Animation definiert. Die Animation ändert die Hintergrundgröße des Textelements auf "100%" beim Scrollen. Der Parameter "scrub: true" ermöglicht eine sanfte Interpolation während des Scrollens.
  4. Die ScrollTrigger-Optionen legen fest, dass die Animation starten soll, wenn das Textelement zu 70% im sichtbaren Bereich des Viewports liegt, und enden soll, wenn es zu 30% im sichtbaren Bereich liegt.

31.mp4 17.8 MB

Magnetischer Cursor

Im nächsten Schritt entwickeln wir einen magnetischen Cursor, der am Logo und den Icons haftet.
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                               magnetic cursor                              */
/* -------------------------------------------------------------------------- */

var magnets = document.querySelectorAll(".magnetic");
var strength = 50;

magnets.forEach((magnet) => {
  magnet.addEventListener("mousemove", moveMagnet);
  magnet.addEventListener("mouseout", function (event) {
    TweenMax.to(event.currentTarget, 1, { x: 0, y: 0, ease: Power4.easeOut });
  });
});

function moveMagnet(event) {
  var magnetButton = event.currentTarget;
  var bounding = magnetButton.getBoundingClientRect();

  TweenMax.to(magnetButton, 1, {
    x:
      ((event.clientX - bounding.left) / magnetButton.offsetWidth - 0.5) *
      strength,
    y:
      ((event.clientY - bounding.top) / magnetButton.offsetHeight - 0.5) *
      strength,
    ease: Power4.easeOut,
  });
}
  1. Die Variable magnets wird verwendet, um alle Elemente mit der Klasse "magnetic" zu selektieren. Diese Elemente dienen als Magneten, an denen sich der Cursor anheften soll. Die Stärke des Magnetismus wird durch die Variable strength festgelegt.
  2. Eine Schleife durchläuft jedes Element in der magnets-Liste und fügt für jedes Element zwei Event-Listener hinzu:
    • mousemove: Wird ausgelöst, wenn sich der Mauszeiger über das Magnet-Element bewegt. Dadurch wird die Funktion moveMagnet aufgerufen, um den Cursor entsprechend zu bewegen.
    • mouseout: Wird ausgelöst, wenn der Mauszeiger das Magnet-Element verlässt. In diesem Fall wird der Cursor sanft in seine ursprüngliche Position zurückbewegt.
  3. Die Funktion moveMagnet(event) wird definiert, um den magnetischen Cursor zu bewegen. Sie wird jedes Mal aufgerufen, wenn sich der Mauszeiger über einem Magnet-Element bewegt. Diese Funktion berechnet die Position des Cursors relativ zur Position des Magnet-Elements und wendet eine entsprechende Verschiebung an, um den magnetischen Effekt zu erzeugen. Die Berechnung basiert auf dem Abstand zwischen der aktuellen Mauszeigerposition und der Position des Magnet-Elements. Diese Verschiebung wird mit der TweenMax-Bibliothek animiert, um einen sanften Bewegungseffekt zu erzielen.

32.mp4 3.48 MB

Erstellen eines Kreises

Nun erstellen wir einen kleinen Kreis, der später die Größe ändert und dem Mauszeiger folgt. Hier die css:
// assets/styles.css

.hidden-content {
  --x: 0px;
  --y: 0px;
  --size: 20px;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-color: #eb5939;
  color: var(--bg);
  --mask: radial-gradient(
    circle at var(--x) var(--y),
    black var(--size),
    transparent 0
  );
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  pointer-events: none;
  visibility: hidden;
  display: none;
}

.hidden-content.active {
  display: block;
}

#hiddenContents {
  -webkit-transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
  1. --x, --y, --size: Diese benutzerdefinierten CSS-Variablen werden verwendet, um die Position und Größe des Maskierungsgradienten zu steuern.
  2. position: absolute;: Das Element wird relativ zum nächsten positionierten Elternelement positioniert.
  3. left: 0; right: 0; top: 0; bottom: 0;: Dies setzt die Abstände des Elements von den Rändern des nächsten positionierten Elternelements auf 0, wodurch das Element das gesamte Elternelement ausfüllt.
  4. background-color: #eb5939;: Hintergrundfarbe des Elements.
  5. color: var(--bg);: Textfarbe des Elements, wobei --bg eine benutzerdefinierte CSS-Variable ist, die an anderer Stelle definiert werden muss.
  6. --mask: Diese benutzerdefinierte CSS-Variable definiert einen radialen Gradienten, der als Maskierung für das Element verwendet wird. Die Position und Größe des Kreises werden durch die zuvor definierten Variablen --x, --y und --size gesteuert.
  7. -webkit-mask-image: var(--mask); mask-image: var(--mask);: Hier wird die Maskierung auf das Element angewendet, sowohl für WebKit-basierte Browser als auch für andere Browser.
  8. pointer-events: none;: Damit wird festgelegt, dass das Element keine Mausereignisse empfängt, sodass Klicks und Hovereffekte durch das verdeckte Element nicht beeinträchtigt werden.
  9. visibility: hidden;: Das Element wird unsichtbar gemacht, jedoch nimmt es weiterhin Platz im Layout ein.

Zusammengefasst wird diese Klasse verwendet, um Inhalte auszublenden, während sie dennoch vorhanden sind und Platz im Layout einnehmen. Der Ausblendeffekt wird durch eine Maskierung mit einem radialen Gradienten erzeugt, wobei die Position und Größe des Gradients durch benutzerdefinierte CSS-Variablen gesteuert werden.
// index.html
...
<div class="hidden-content" id="hiddenContents"></div>
...
In den main Tag hinter die content classe vor den aside.
Dieser Code implementiert eine visuelle Interaktion, die auf Mausbewegungen reagiert und eine Animation auslöst.
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                                    Kreis                                   */
/* -------------------------------------------------------------------------- */

gsap.set(".hidden-content", { xPercent: -0, yPercent: -0 });
const pos = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
const speed = 0.08;

const hiddenContent = document.getElementById("hiddenContents");
const content = document.querySelector(".content");
const mouse = { x: 0, y: 0 };

const xSet = gsap.quickSetter(hiddenContent, "--x", "px");
const ySet = gsap.quickSetter(hiddenContent, "--y", "px");

let linkAnimated = false;

let xTo = gsap.quickTo(hiddenContent, "--x", {
    duration: 1,
    ease: "power4.out",
  }),
  yTo = gsap.quickTo(hiddenContent, "--y", {
    duration: 1,
    ease: "power4.out",
  });

let tl = gsap.timeline({ paused: true });
if (window.innerWidth < 1249) {
  tl.to(hiddenContent, {
    "--size": 250,
    position: "absolute",
    display: "block",
    duration: 0.75,
    ease: Expo.ease,
  });
} else {
  tl.to(hiddenContent, {
    "--size": 250,
    position: "absolute",
    duration: 0.75,
    ease: Expo.ease,
  });
}

let hoveringContent = gsap.utils.toArray(".display", content);

hoveringContent.forEach((el) => {
  el.addEventListener("mouseenter", () => {
    tl.restart();
  });
  el.addEventListener("mouseleave", () => {
    tl.reverse();
  });
});

/* -------------------------------------------------------------------------- */
/*               Füge eine Maske beim ersten Mausbewegung hinzu.              */
/* -------------------------------------------------------------------------- */

window.addEventListener("mousemove", onFirstMove);

function onFirstMove(e) {
  window.removeEventListener("mousemove", onFirstMove);
  gsap.set(hiddenContent, { autoAlpha: 1, "--x": e.pageX, "--y": e.pageY });

  window.addEventListener("mousemove", (e) => {
    if (!linkAnimated) {
      yTo(e.pageY);
      xTo(e.pageX);
    }
  });
}

/* -------------------------------------------------------------------------- */
/*           Klasse 'active' dynamisch hinzuzufügen und zu entfernen          */
/* -------------------------------------------------------------------------- */

const hiddenLinks = document.querySelectorAll(".content");

hiddenLinks.forEach((link) => {
  link.addEventListener("mouseenter", () => {
    const hiddenContent = link.nextElementSibling;
    hiddenContent.classList.add("active");
  });

  link.addEventListener("mouseleave", () => {
    const hiddenContent = link.nextElementSibling;
    hiddenContent.classList.remove("active");
  });
});

Zu Beginn werden einige Variablen definiert, darunter die Position des Cursors (pos), eine Geschwindigkeitsvariable (speed) und Referenzen auf DOM-Elemente wie hiddenContent und content.

Es wird eine Timeline (tl) erstellt, die die Animation für das versteckte Element (hiddenContent) steuert. Abhängig von der Bildschirmbreite wird die Größe des Elements animiert, um entweder auf einer absoluten Position oder relativ zur aktuellen Position zu erscheinen.

Des Weiteren wird eine Liste von Elementen (hoveringContent) erstellt, die auf Mausinteraktionen reagieren. Wenn die Maus über eines dieser Elemente schwebt, wird die Animation gestartet bzw. rückgängig gemacht.

Schließlich gibt es eine Funktion (onFirstMove), die aufgerufen wird, wenn die Maus zum ersten Mal bewegt wird. Diese Funktion entfernt den Eventlistener für das erste Mausereignis und fügt einen neuen Eventlistener hinzu, der die Mausbewegungen überwacht. Dabei wird eine Maske sichtbar gemacht und an die Position der Maus angepasst. Wenn die Mausbewegung nicht animiert ist, wird die Position der Maske aktualisiert, um der Maus zu folgen.

Insgesamt ermöglicht dieser Code eine ansprechende visuelle Erfahrung, indem er auf subtile Weise auf Mausbewegungen reagiert und verschiedene Animationen auslöst, um die Benutzerinteraktion auf der Webseite zu verbessern.

31.png 3.38 MB

Kreis folgt der Maus

Der kreis folgt der Maus bei jeder Bewegung, allerdings folgt er der Maus nicht wenn wir die Seite scrollen, dieses ändern wir jetzt.
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                             scrollt mit                                    */
/* -------------------------------------------------------------------------- */

window.addEventListener("scroll", () => {
  const mouseX = mouse.x + window.scrollX;
  const mouseY = mouse.y + window.scrollY;
  if (!linkAnimated) {
    ySet(mouseY);
    xSet(mouseX);
  }
});

window.addEventListener("mousemove", (e) => {
  const dt = 1.0 - Math.pow(1.0 - speed, gsap.ticker.deltaRatio());
  mouse.x = e.clientX;
  mouse.y = e.clientY;
  if (!linkAnimated) {
    ySet(mouse.y + window.scrollY * dt);
    xSet(mouse.x + window.scrollX * dt);
  }
});

Bei jedem Scroll- oder Mausereignis wird die Position des Cursors aktualisiert, wobei berücksichtigt wird, ob die Seite gescrollt wurde. Dies geschieht, indem die aktuellen Mauskoordinaten (mouseX und mouseY) mit den Scrollpositionen (window.scrollX und window.scrollY) addiert werden. Wenn das Mausereignis nicht bereits animiert ist, wird die Position des Cursors entsprechend aktualisiert.

Die Aktualisierung der Cursorposition wird mit Hilfe der ySet- und xSet-Funktionen von GreenSock Animation Platform (GSAP) durchgeführt. Diese Funktionen sorgen dafür, dass die Änderungen der Cursorposition flüssig und animiert erfolgen.

Insgesamt ermöglicht dieser Code eine reibungslose und ansprechende Verfolgung des Cursors durch den Benutzer, auch wenn die Seite gescrollt wird. Dies trägt zu einer verbesserten Benutzererfahrung bei und macht die Interaktion mit der Webseite intuitiver.

Versteckter Text, der sichtbar wird

Nun geht es darum, den aufregenden Teil zu gestalten: den versteckten Text, der erst sichtbar wird, wenn wir mit der Maus über einen anderen Text fahren. 
// index.html

<div class="hidden-content" id="hiddenContents">
  <!-- -------------------------------- hero --------------------------------- -->
  <div class="row justify-content-center align-items-center min-vh-100">
    <div class="display">
      <p class="about_content_label text-align-center">b4um</p>
      <div class="text-center text-black">Hiding</div>
      <div class="text-center text-black"><strong>bad</strong></div>
      <div class="text-center text-black"><strong>shit</strong></div>
      <div class="text-center text-black">since</div>
      <div class="text-center text-black">2023</div>
    </div>
  </div>
  <!-- ------------------------------ hero ende ------------------------------ -->
</div>
Das HTML-Markup definiert einen versteckten Inhalt innerhalb eines Container-Divs mit der Klasse "hidden-content" und der ID "hiddenContents". Innerhalb dieses Containers befindet sich ein weiteres Div mit den Klassen "row", "justify-content-center" und "align-items-center", das den versteckten Inhalt zentriert und vertikal ausrichtet. In diesem Div befindet sich ein weiteres Div mit der Klasse "display", das den tatsächlichen Inhalt enthält.

Der Inhalt besteht aus mehreren Absätzen mit verschiedenen Texten, die zentriert und in schwarzer Farbe formatiert sind. Der erste Absatz enthält den Text "b4um", gefolgt von mehreren Absätzen mit den Wörtern "Hiding", "bad", "shit", "since" und "2023", wobei einige Wörter fett formatiert sind. Dieser versteckte Inhalt wird sichtbar gemacht, wenn bestimmte Aktionen ausgelöst werden, wie beispielsweise das Bewegen der Maus über den Text.
// assets/styles.css

.hidden-content strong {
  color: #0d0d0d;
  font-weight: 900;
}

33.mp4 12.8 MB


Und weiter im Programm:
// index.html

<!-- ------------------------------ About me ------------------------------- -->
<div class="row justify-content-center align-items-center min-vh-100">
  <div class="display width-100">
    <p class="about_content_label">About me</p>
    <div class="display-hidden">
      Ein visueller Designer - mit Fähigkeiten
    </div>
    <div class="display-hidden">
      die noch nicht von KI ersetzt wurden - der nur gute Arbeit macht,
    </div>
    <div class="display-hidden">wenn das Gehalt ebenso gut ist.</div>
  </div>
</div>
<!-- ---------------------------- About me ende ---------------------------- -->
  • <div class="row justify-content-center align-items-center min-vh-100">: Dieses <div>-Element verwendet Bootstrap-Klassen, um eine Reihe von Inhalten zu erstellen, die vertikal und horizontal zentriert sind und mindestens die volle Höhe des Bildschirms einnehmen.
  • <div class="display width-100">: Dieses <div>-Element enthält den eigentlichen Inhalt des Abschnitts "Über mich". Die Klasse width-100 weist darauf hin, dass der Inhalt die volle Breite des Elternelements einnehmen soll.
  • <p class="about_content_label">Über mich</p>: Dies ist eine Überschrift für den Abschnitt "Über mich", die mit der Klasse about_content_label gestylt wird.
  • <div class="display-hidden">: Diese <div>-Elemente enthalten den versteckten Text, der schrittweise sichtbar wird, wenn der Benutzer die Seite scrollt. Der Text beschreibt den Designer und seine Arbeit.
// assets/styles.css

.display-hidden {
  font-size: 2rem;
  font-weight: 600;
  line-height: 100%;
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: start;
  justify-content: start;
  position: relative;
  max-width: 1248px;
  margin: auto;
  text-align: left;
  padding-left: 1rem;
  padding-right: 1rem;
}
@media (min-width: 1248px) {
  .display-hidden {
    font-size: 4vw;
    padding-left: 0rem;
    padding-right: 0rem;
  }
}
Dieser CSS-Code definiert die Stile für Elemente mit der Klasse `.display-hidden`. Hier ist eine Erklärung für die einzelnen Eigenschaften:

- `font-size`: Legt die Schriftgröße auf 2 Rem fest, was 2 mal die Standardgröße der Schriftart ist.
- `font-weight`: Setzt die Schrift auf fett (Font Weight 600).
- `line-height`: Legt die Höhe der Zeilen auf 100% fest, was bedeutet, dass die Zeilenhöhe der gleichen Höhe wie die Schriftgröße entspricht.
- `width`: Der Text nimmt die volle Breite des verfügbaren Platzes ein.
- `display`: Stellt die Anzeige der Elemente als Flexbox ein, um sie in einer Reihe anzuordnen.
- `flex-direction`: Legt die Richtung der Flexbox auf "row" (Reihe) fest, was bedeutet, dass die Elemente horizontal angeordnet werden.
- `align-items`: Bestimmt die vertikale Ausrichtung der Elemente, in diesem Fall oben.
- `justify-content`: Bestimmt die horizontale Ausrichtung der Elemente, in diesem Fall am Anfang der Zeile.
- `position`: Setzt die Positionierung auf relativ, damit die Positionierung von Kinderelementen relativ zum Element erfolgt.
- `max-width`: Begrenzt die maximale Breite des Elements auf 1248 Pixel.
- `margin`: Zentriert das Element horizontal mit Auto-Margen.
- `text-align`: Legt den Textausrichtung auf links fest.
- `padding-left`, `padding-right`: Fügt links und rechts jeweils einen Abstand von 1 Rem hinzu.

Die Medienabfrage `@media (min-width: 1248px)` wird verwendet, um die Stile für Bildschirmbreiten von mindestens 1248 Pixeln zu überschreiben. In diesem Fall wird die Schriftgröße auf 4 vw (Viewport Width) festgelegt und der seitliche Abstand auf 0 Rem gesetzt, um den Text besser auf größeren Bildschirmen darzustellen.

Leeres Element

Als nächstes benötigen wir ein leeres Element für den Bereich, den wir bereits mit CSS-Code sichtbar machen.
// index.html

<!-- ----------------------------- what i do ------------------------------- -->
<div
  class="row justify-content-center align-items-center min-vh-100"
></div>
<!-- ----------------------------- ende what i do -------------------------- -->
Wir können direkt weiter machen:
// index.html

<!-- ----------------------------- experience ------------------------------ -->
<div class="row justify-content-center align-items-center min-vh-100">
  <div class="display">
    <p class="about_content_label">Experience</p>
    <div class="display-hidden">
      Nur sieben Jahre lang habe ich aktiv
    </div>
    <div class="display-hidden">
      coole Sachen produziert. Die anderen Jahre
    </div>
    <div class="display-hidden">waren eher ein Herumprobieren und</div>
    <div class="display-hidden">Durchlaufen meiner Karriere.</div>
  </div>
</div>
<!-- --------------------------- experience ende --------------------------- -->

// index.html

<!-- ------------------------------- history ------------------------------- -->
<div
  class="row justify-content-center align-items-center min-vh-100"
></div>
<!-- ---------------------------- history ende ----------------------------- -->

// index.html

<!-- ------------------------------- Clients ------------------------------- -->
<div class="row justify-content-center align-items-center min-vh-100">
  <div class="display">
    <p class="about_content_label">Clients</p>
    <div class="display-hidden">
      Ich war nur ein kleiner Teil eines großen
    </div>
    <div class="display-hidden">
      Teams. Sie haben wahrscheinlich keine
    </div>
    <div class="display-hidden">Ahnung, dass ich existiere.</div>
  </div>
</div>
<!-- ---------------------------- Clients ende ----------------------------- -->

// index.html

<!-- ------------------------- clients aufzählung -------------------------- -->
<div
  class="row justify-content-center align-items-center min-vh-100"
></div>
<!-- --------------------------- aufzählung ende --------------------------- -->

// index.html

<!-- ------------------------------- Motto ------------------------------- -->
<div class="row justify-content-center align-items-center min-vh-100">
  <div class="display">
    <p class="about_content_label text-align-center">Mein Motto</p>
    <div class="text-center text-black">Nicht alle</div>
    <div class="text-center text-black">ehrlichen Designs</div>
    <div class="text-center text-black">sind gut</div>
    <p class="about_content_label text-align-center">b4um</p>
  </div>
</div>
<!-- ---------------------------- Motto ende ----------------------------- -->

34.mp4 43.4 MB

Kreis hidden

Das nächste worum wir uns kümmern ist, das der Kreis unter bestimmten Umständen nicht angezeigt werden soll.
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                          verschwinden des kreises                          */
/* -------------------------------------------------------------------------- */

document.querySelectorAll(".hidden-link").forEach((link) => {
  link.addEventListener("mouseenter", (e) => {
    linkAnimated = true;
    gsap.set(hiddenContent, {
      autoAlpha: 0,
      "--x": e.pageX,
      "--y": e.pageY,
    });
  });
  link.addEventListener("mouseleave", (e) => {
    linkAnimated = false;
    gsap.set(hiddenContent, { xPercent: 0, yPercent: 0 });
    gsap.set(hiddenContent, {
      autoAlpha: 1,
      "--x": e.pageX,
      "--y": e.pageY,
    });
  });
});
Dieser JavaScript-Code überwacht alle Elemente mit der Klasse "hidden-link". Wenn der Mauszeiger über ein solches Element bewegt wird (mouseenter), wird das Ereignis ausgelöst. Das `linkAnimated` Flag wird auf true gesetzt, und die Position des versteckten Inhalts (`hiddenContent`) wird auf die aktuelle Position des Mauszeigers gesetzt, wobei die Sichtbarkeit auf 0 gesetzt wird.

Wenn der Mauszeiger das Element verlässt (mouseleave), wird das `linkAnimated` Flag auf false gesetzt und die Position des versteckten Inhalts wird auf die aktuelle Position des Mauszeigers zurückgesetzt, wobei die Sichtbarkeit auf 1 gesetzt wird.

Wechsel von scrollen auf bewegen

Jetzt haben wir noch das unschöne Problem, dass der Kreis von ausserhalb des Sichtbereiches kommt, wenn wir den wechseln von scrollen zu Mausbewegung haben. 
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                      wechsel von scrollen auf bewegen                      */
/* -------------------------------------------------------------------------- */

function onFirstMove(e) {
  window.removeEventListener("mousemove", onFirstMove);

  // Bestimme die X- und Y-Position der Maus
  const mouseX = e.pageX;
  const mouseY = e.pageY;

  // Bestimme die Breite und Höhe des sichtbaren Bereichs
  const viewportWidth = window.innerWidth;
  const viewportHeight = window.innerHeight;

  // Stelle sicher, dass die X-Position innerhalb des sichtbaren Bereichs liegt
  const xPosition = Math.min(Math.max(mouseX, 0), viewportWidth);

  // Stelle sicher, dass die Y-Position innerhalb des sichtbaren Bereichs liegt
  const yPosition = Math.min(Math.max(mouseY, 0), viewportHeight);

  // Setze die Position des Kreises auf die angepassten Werte
  gsap.set(hiddenContent, { autoAlpha: 1, "--x": xPosition, "--y": yPosition });

  // Füge ein Event-Listener für weitere Mausbewegungen hinzu
  window.addEventListener("mousemove", moveCircle);
}

function moveCircle(e) {
  // Bestimme die X- und Y-Position der Maus
  const mouseX = e.pageX;
  const mouseY = e.pageY;

  // Setze die Position des Kreises auf die aktuelle Mausposition
  gsap.set(hiddenContent, { "--x": mouseX, "--y": mouseY });
}
Die Funktion onFirstMove wird ausgeführt, wenn die Maus zum ersten Mal bewegt wird. Sie entfernt zunächst den Event-Listener für die Mausbewegung, um sicherzustellen, dass sie nur einmal ausgeführt wird. Dann bestimmt sie die X- und Y-Position der Maus relativ zum Seitenrand. Anschließend wird überprüft, ob sich die Mausposition innerhalb des sichtbaren Bereichs des Viewports befindet, und die Positionen werden entsprechend angepasst, falls sie außerhalb liegen. Schließlich wird die Position des Kreises auf die angepassten Werte gesetzt, und ein Event-Listener für weitere Mausbewegungen wird hinzugefügt.

Die Funktion moveCircle wird ausgeführt, wenn die Maus bewegt wird, nachdem onFirstMove aufgerufen wurde. Sie bestimmt einfach die aktuellen X- und Y-Positionen der Maus und setzt die Position des Kreises entsprechend auf diese Werte.

35.mp4 50.6 MB

Mobile Ansicht

Kümmern wir uns nun um die mobile Ansicht. Wir wollen nicht, das der Hintergrund orange wird wenn wir auf ein Mobile Display klicken. Als erstes erstellen wir und eine kleine Funktion die überprüft ob wir ein kleines Display haben, die Weite unter einen bestimmten Wert liegt.
// assets/scripts.js

/* -------------------------------------------------------------------------- */
/*                                   mobile                                   */
/* -------------------------------------------------------------------------- */

function isMobileDevice() {
  return window.innerWidth <= 1248;
}
Die Funktion können wir verwenden um eine if Abfrage zu starten. Suche window.addEventListener("mousemove", onFirstMove); und umschliesse es mit einer if Anweisung.
// assets/scripts.js

if (!isMobileDevice()) {
  window.addEventListener("mousemove", onFirstMove);
}
Jetzt haben wir das Problem behoben mit dem klicken auf das mobile Display, aber wir können unseren versteckten text nicht mehr lesen. Um dieses aufzuheben erstellen wir einen Button den man gedrückt halten muss um den text sichtbar zu machen. Fangen wir mit der html Struktur an und setzen den Button unter den footer:
// index.html
...

<button id="btn_clipPath" class="btn_clipPath">
  <span class="btn_inner"
    ><div class="btn_image btn-ring">
      <img src="assets/images/text-ring.svg" alt="text-ring" />
    </div>
    <div class="btn_touch">
      <img src="assets/images/touch.svg" alt="touch" /></div
  ></span>
</button>
Ich nutze zwei images, eine Hand und einen press Button. Beides bringen wir jetzt zusammen und der button soll animiert sein, dieses können wir am einfachsten mit entsprechendem css code realisieren. Erst erstellen wir die animation:
// assets/styles.css

@keyframes loop {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-webkit-keyframes loop {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
Diese CSS @keyframes und @-webkit-keyframes definieren eine Animation namens "loop", die eine Rotation von 0 Grad auf 360 Grad durchführt. Diese Animation kann dann auf ein Element angewendet werden, um es kontinuierlich zu drehen.
// assets/styles.css

.btn_clipPath {
  background: none;
  border: none;
  bottom: 2.1875rem;
  left: calc(50% - 39px);
  padding: 0 !important;
  position: fixed;
  z-index: 4;
}
.btn_inner {
  display: block;
  position: relative;
}
.btn-ring {
  -webkit-animation: loop 10s infinite forwards linear;
  animation: loop 10s infinite forwards linear;
  height: 78px;
  width: 78px;
}
.btn_touch {
  -webkit-box-align: center;
  -ms-flex-align: center;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  align-items: center;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  height: 100%;
  justify-content: center;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}
Die bereitgestellten CSS-Klassen definieren die Stile für einen Button mit einer animierten Umrandung (btn-ring). Der Button (btn_clipPath) wird fixiert positioniert, während seine inneren Inhalte (btn_inner) relativ positioniert sind, um die Umrandung korrekt zu platzieren. Die Klasse .btn_touch definiert Stile für den Bereich innerhalb des Buttons, der auf Berührungen reagiert.

  1. .btn_clipPath: Definiert die allgemeinen Stile für den Button, wie die Positionierung (fest), den Abstand vom unteren Bildschirmrand, den Abstand von der linken Seite des Bildschirms und den Z-Index. Außerdem werden hier der Hintergrund und der Rahmen auf "none" gesetzt und das Padding auf "0" gesetzt.
  2. .btn_inner: Definiert Stile für den inneren Bereich des Buttons, der die Umrandung enthält. Hier wird die relative Positionierung festgelegt und der Blockdisplay verwendet.
  3. .btn-ring: Definiert die Stile für die animierte Umrandung des Buttons, einschließlich ihrer Größe (Höhe und Breite) und der Animation, die auf sie angewendet wird. Die Animation "loop" wird hier mit einer Dauer von 10 Sekunden und einer linearen Interpolation für eine unendliche Wiederholung definiert.
  4. .btn_touch: Definiert Stile für den Bereich innerhalb des Buttons, der auf Berührungen reagiert. Dieser Bereich wird zentriert und nimmt den gesamten verfügbaren Platz innerhalb des Buttons ein.

Wir müssen noch dafür sorgen das der Button nur auf den mobilen Geräten angezeigt wird.
// assets/styles.css

@media (min-width: 1248px) {
  .btn_clipPath {
    display: none;
  }
}
Zu guter letzt, schreiben wir noch ein Javascript code der dafür sorgt, dass der versteckte Text angezeigt wird.
// assets/scripts.js

const circleButton = document.getElementById("btn_clipPath");
circleButton.addEventListener("touchstart", (e) => {
  e.preventDefault();
  if (isMobileDevice()) {
    gsap.set(hiddenContent, { autoAlpha: 1, "--x": e.pageX, "--y": e.pageY });
  }
});
circleButton.addEventListener("touchend", () => {
  if (isMobileDevice()) {
    gsap.set(hiddenContent, { autoAlpha: 0, "--x": 0, "--y": 0 });
    gsap.to(hiddenContent, {
      "--size": 0,
      duration: 0.75,
      ease: Expo.ease,
    });
  }
});
Dieser JavaScript-Code behandelt Touch-Ereignisse auf einem Element mit der ID "btn_clipPath". Ziel ist es, das Erscheinen und Verschwinden eines anderen Elements zu steuern, wenn auf das "circleButton" Element getippt wird.

1. `const circleButton = document.getElementById("btn_clipPath");`: Hier wird das Element mit der ID "btn_clipPath" aus dem DOM (Document Object Model) abgerufen und in der Variablen `circleButton` gespeichert. Dieses Element wird als der Button behandelt, auf den der Benutzer tippt.

2. `circleButton.addEventListener("touchstart", (e) => { ... });`: Ein Event-Listener wird dem "circleButton" Element hinzugefügt, der auf das `touchstart`-Ereignis reagiert. Das bedeutet, dass diese Funktion ausgeführt wird, wenn der Benutzer mit seinem Finger auf das Element tippt, um eine Berührung zu initiieren.
   - `e.preventDefault();`: Dieser Code verhindert das Standardverhalten des Browsers für das `touchstart`-Ereignis, was normalerweise das Auslösen von Klicks oder Scrollen sein kann. Es stellt sicher, dass das Standardverhalten des Browsers nicht ausgeführt wird.
   - `if (isMobileDevice()) { ... }`: Diese Bedingung überprüft, ob das Gerät ein mobiles Gerät ist, indem die Funktion `isMobileDevice()` aufgerufen wird. Wenn dies der Fall ist, wird der folgende Code ausgeführt.
   - `gsap.set(hiddenContent, { autoAlpha: 1, "--x": e.pageX, "--y": e.pageY });`: Hier wird die `set`-Methode der GSAP-Bibliothek verwendet, um die CSS-Eigenschaften des "hiddenContent" Elements zu ändern. Das Element wird auf sichtbar (opacity = 1) gesetzt, und seine Position wird auf die Position des Touch-Ereignisses (`e.pageX` und `e.pageY`) gesetzt.

3. `circleButton.addEventListener("touchend", () => { ... });`: Ein weiterer Event-Listener wird dem "circleButton" Element hinzugefügt, der auf das `touchend`-Ereignis reagiert. Das bedeutet, dass diese Funktion ausgeführt wird, wenn der Benutzer seinen Finger vom Element entfernt, um die Berührung zu beenden.
   - `if (isMobileDevice()) { ... }`: Diese Bedingung überprüft erneut, ob das Gerät ein mobiles Gerät ist.
   - `gsap.set(hiddenContent, { autoAlpha: 0, "--x": 0, "--y": 0 });`: Hier wird die `set`-Methode der GSAP-Bibliothek verwendet, um die CSS-Eigenschaften des "hiddenContent" Elements zu ändern. Das Element wird unsichtbar (opacity = 0) gemacht, und seine Position wird auf (0, 0) zurückgesetzt.
   - `gsap.to(hiddenContent, { "--size": 0, duration: 0.75, ease: Expo.ease });`: Hier wird die `to`-Methode der GSAP-Bibliothek verwendet, um eine Animation auf dem "hiddenContent" Element auszuführen. Die Größe des Elements wird auf 0 animiert, wobei eine Dauer von 0,75 Sekunden und eine Easing-Funktion namens "Expo.ease" verwendet werden.

36.mp4 30 MB

Meld dich an und schreibe ein Kommentar