3D-Spielemenükomponente erstellen

Ein grundlegender Überblick über die Erstellung eines responsiven, adaptiven und barrierefreien 3D-Spielmenüs.

In diesem Beitrag möchte ich Ihnen zeigen, wie Sie eine 3D-Spielmenükomponente erstellen können. Testen Sie die Demo ansehen.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> Demo

Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:

Übersicht

Videospiele bieten Nutzern oft ein kreatives und ungewöhnliches Menü, und im 3D-Raum. Es ist beliebt, dass das Menü in neuen AR-/VR-Spielen und schwebt im Weltraum. Heute wiederholen wir die Grundlagen dieses Effekts, aber mit adaptivem Farbschema und Anpassungsmöglichkeiten für Nutzende die eingeschränkte Bewegung bevorzugen.

HTML

Ein Spielmenü besteht aus einer Liste von Schaltflächen. Um dies in HTML darzustellen, folgt:

<ul class="threeD-button-set">
  <li><button>New Game</button></li>
  <li><button>Continue</button></li>
  <li><button>Online</button></li>
  <li><button>Settings</button></li>
  <li><button>Quit</button></li>
</ul>

Eine Liste von Schaltflächen kommt gut für Screenreader-Technologien und funktioniert auch ohne JavaScript oder CSS.

eine
Aufzählungsliste mit normalen Schaltflächen als Elemente.

CSS

Der Stil der Schaltflächenliste ist in folgende übergeordnete Schritte unterteilt:

  1. Benutzerdefinierte Eigenschaften einrichten
  2. Ein Flexbox-Layout.
  3. Eine benutzerdefinierte Schaltfläche mit dekorativen Pseudoelementen.
  4. Elemente im 3D-Raum platzieren

Übersicht über benutzerdefinierte Eigenschaften

Mit benutzerdefinierten Eigenschaften lassen sich Werte unterscheiden, auf ansonsten zufällig aussehende Werte und vermeidet wiederholten Code und die Weitergabe von Daten an andere. Werte unter untergeordneten Elementen.

Unten finden Sie Medienabfragen, die als CSS-Variablen gespeichert sind. Diese werden auch als benutzerdefinierte Medien. Das sind globale und wird in verschiedenen Selektoren verwendet, um den Code prägnant und lesbar zu halten. Die Komponente des Spielemenüs verwendet Bewegungen Einstellungen, System-Farbe und Farbbereich Funktionen des Display.

@custom-media --motionOK (prefers-reduced-motion: no-preference);
@custom-media --dark (prefers-color-scheme: dark);
@custom-media --HDcolor (dynamic-range: high);

Mit den folgenden benutzerdefinierten Eigenschaften wird das Farbschema verwaltet und bei gedrückter Maustaste Positionswerte, mit denen das Spielmenü interaktiv gestaltet werden kann, wenn der Mauszeiger darauf bewegt wird Benennen: benutzerdefiniert Eigenschaften verbessern die Lesbarkeit des Codes, da der Anwendungsfall für den Wert oder einen Anzeigename für das Ergebnis des Werts.

.threeD-button-set {
  --y:;
  --x:;
  --distance: 1px;
  --theme: hsl(180 100% 50%);
  --theme-bg: hsl(180 100% 50% / 25%);
  --theme-bg-hover: hsl(180 100% 50% / 40%);
  --theme-text: white;
  --theme-shadow: hsl(180 100% 10% / 25%);

  --_max-rotateY: 10deg;
  --_max-rotateX: 15deg;
  --_btn-bg: var(--theme-bg);
  --_btn-bg-hover: var(--theme-bg-hover);
  --_btn-text: var(--theme-text);
  --_btn-text-shadow: var(--theme-shadow);
  --_bounce-ease: cubic-bezier(.5, 1.75, .75, 1.25);

  @media (--dark) {
    --theme: hsl(255 53% 50%);
    --theme-bg: hsl(255 53% 71% / 25%);
    --theme-bg-hover: hsl(255 53% 50% / 40%);
    --theme-shadow: hsl(255 53% 10% / 25%);
  }

  @media (--HDcolor) {
    @supports (color: color(display-p3 0 0 0)) {
      --theme: color(display-p3 .4 0 .9);
    }
  }
}

Kegelförmiger Hintergrund in hellem und dunklem Design

Das helle Design hat einen lebendigen Farbton von cyan bis deeppink Farbverlauf und das dunkle Design hat einen subtilen, kegelförmigen Farbverlauf. Um mehr darüber zu erfahren, ist mit konischen Farbverläufen möglich, siehe conic.style.

html {
  background: conic-gradient(at -10% 50%, deeppink, cyan);

  @media (--dark) {
    background: conic-gradient(at -10% 50%, #212529, 50%, #495057, #212529);
  }
}
<ph type="x-smartling-placeholder">
</ph>
Demonstration des Wechsels zwischen hellen und dunklen Farbeinstellungen im Hintergrund.

3D-Perspektive aktivieren

Damit Elemente im 3D-Bereich einer Webseite vorhanden sind, kann ein Darstellungsbereich Perspektive muss initialisiert werden. Ich habe mich dafür entschieden, das Element body aus der Perspektive zu sehen und nutzte Darstellungsbereiche, um den Stil zu erstellen, der mir gefiel.

body {
  perspective: 40vw;
}

Dies ist die Art der Auswirkungsperspektive.

Stil der Schaltflächenliste für <ul> gestalten

Dieses Element ist verantwortlich für das gesamte Layout der Schaltflächenliste, eine interaktive und schwebende 3D-Karte. Das können Sie auf folgende Weise erreichen:

Layout der Schaltflächengruppe

Flexbox kann das Containerlayout verwalten. Standardrichtung von Flex ändern von Zeilen in Spalten mit flex-direction und stellen Sie sicher, dass jedes Element die Größe indem Sie für align-items von stretch in start ändern.

.threeD-button-set {
  /* remove <ul> margins */
  margin: 0;

  /* vertical rag-right layout */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2.5vh;
}

Richten Sie als Nächstes den Container als 3D-Space-Kontext ein und richten Sie die CSS-Datei clamp() ein um sicherzustellen, dass sich die Karte nicht über die lesbaren Drehungen hinaus dreht. Hinweis dass der mittlere Wert für die Einschränkung eine benutzerdefinierte Eigenschaft ist, werden diese --x und --y Werte werden mit der Maus aus JavaScript festgelegt Interaktion.

.threeD-button-set {
  

  /* create 3D space context */
  transform-style: preserve-3d;

  /* clamped menu rotation to not be too extreme */
  transform:
    rotateY(
      clamp(
        calc(var(--_max-rotateY) * -1),
        var(--y),
        var(--_max-rotateY)
      )
    )
    rotateX(
      clamp(
        calc(var(--_max-rotateX) * -1),
        var(--x),
        var(--_max-rotateX)
      )
    )
  ;
}

Wenn Bewegung für den Besucher kein Problem ist, fügen Sie dem Browser einen Hinweis hinzu, die Transformation dieses Elements ständig mit will-change Aktivieren Sie außerdem die Interpolation, indem Sie für Transformationen einen transition festlegen. Dieses erfolgt, wenn die Maus mit der Karte interagiert. Dadurch wird eine Rotationsänderungen. Die Animation läuft ständig der den 3D-Raum darstellt, in dem sich die Karte befindet, selbst wenn eine Maus nicht mit der Komponente interagiert.

@media (--motionOK) {
  .threeD-button-set {
    /* browser hint so it can be prepared and optimized */
    will-change: transform;

    /* transition transform style changes and run an infinite animation */
    transition: transform .1s ease;
    animation: rotate-y 5s ease-in-out infinite;
  }
}

Bei der rotate-y-Animation wird nur der mittlere Keyframe auf 50% festgelegt, da das verwendet der Browser standardmäßig den Standardstil des Elements für 0% und 100%. Dieses steht für abwechselnde Animationen, deren Anfang und Ende identisch sein müssen . Es ist eine großartige Möglichkeit, unendliche abwechselnde Animationen zu artikulieren.

@keyframes rotate-y {
  50% {
    transform: rotateY(15deg) rotateX(-6deg);
  }
}

Stil für <li>-Elemente festlegen

Jedes Listenelement (<li>) enthält die Schaltfläche und die dazugehörigen Rahmenelemente. Die Der Stil von display wurde geändert, sodass für das Element kein ::marker Der position-Stil ist auf relative gesetzt, sodass die Pseudoelemente der nächsten Schaltfläche innerhalb des gesamten Bereichs, den die Schaltfläche verbraucht.

.threeD-button-set > li {
  /* change display type from list-item */
  display: inline-flex;

  /* create context for button pseudos */
  position: relative;

  /* create 3D space context */
  transform-style: preserve-3d;
}

Screenshot der im 3D-Raum gedrehten Liste zur Darstellung der Perspektive und
hat jedes Listenelement keinen Aufzählungspunkt mehr.

Stil für <button>-Elemente festlegen

Die Gestaltung von Schaltflächen kann schwierig sein. Es gibt viele Status und Interaktionstypen die Sie berücksichtigen müssen. Diese Schaltflächen werden durch die Ausgewogenheit schnell komplex. Pseudo-Elemente, Animationen und Interaktionen.

Anfängliche <button>-Stile

Unten sind die grundlegenden Stile aufgeführt, die die anderen Stadien unterstützen.

.threeD-button-set button {
  /* strip out default button styles */
  appearance: none;
  outline: none;
  border: none;

  /* bring in brand styles via props */
  background-color: var(--_btn-bg);
  color: var(--_btn-text);
  text-shadow: 0 1px 1px var(--_btn-text-shadow);

  /* large text rounded corner and padded*/
  font-size: 5vmin;
  font-family: Audiowide;
  padding-block: .75ch;
  padding-inline: 2ch;
  border-radius: 5px 20px;
}

Screenshot der Schaltflächenliste in 3D, dieses Mal mit benutzerdefiniertem Stil
Schaltflächen.

Pseudoelemente der Schaltfläche

Die Ränder der Schaltfläche sind keine traditionellen Rahmen, sie befinden sich an einer absoluten Position. Pseudo-Elemente mit Rahmen enthalten.

Screenshot des Bereichs „Elemente“ in Chrome-Entwicklertools mit einer Schaltfläche, die das Symbol
::before- und ::after-Elemente.

Diese Elemente sind entscheidend für die Darstellung der bisher bekannten 3D-Perspektive. festgelegt ist. Eines dieser Pseudoelemente wird von der Schaltfläche weggeschoben, und eines wird näher am Nutzer gezogen. Am deutlichsten wirkt sich der Effekt in der Tasten oben und unten.

.threeD-button button {
  

  &::after,
  &::before {
    /* create empty element */
    content: '';
    opacity: .8;

    /* cover the parent (button) */
    position: absolute;
    inset: 0;

    /* style the element for border accents */
    border: 1px solid var(--theme);
    border-radius: 5px 20px;
  }

  /* exceptions for one of the pseudo elements */
  /* this will be pushed back (3x) and have a thicker border */
  &::before {
    border-width: 3px;

    /* in dark mode, it glows! */
    @media (--dark) {
      box-shadow:
        0 0 25px var(--theme),
        inset 0 0 25px var(--theme);
    }
  }
}

3D-Transformationsstile

Unter „transform-style“ ist preserve-3d festgelegt, damit die Kinder Platz haben sich selbst auf der z-Achse. transform ist auf --distance festgelegt benutzerdefinierte Eigenschaft, die durch Hover- und fokus.

.threeD-button-set button {
  

  transform: translateZ(var(--distance));
  transform-style: preserve-3d;

  &::after {
    /* pull forward in Z space with a 3x multiplier */
    transform: translateZ(calc(var(--distance) / 3));
  }

  &::before {
    /* push back in Z space with a 3x multiplier */
    transform: translateZ(calc(var(--distance) / 3 * -1));
  }
}

Bedingte Animationsstile

Wenn die Nutzenden mit Bewegung einverstanden sind, weist die Schaltfläche dem Browser darauf hin, Transformationseigenschaft sollte geändert werden können und ein Übergang für transform- und background-color-Properties. Beachten Sie den Unterschied in hatte ich das Gefühl, dass es eine schöne gestaffelte Wirkung erzeugt.

.threeD-button-set button {
  

  @media (--motionOK) {
    will-change: transform;
    transition:
      transform .2s ease,
      background-color .5s ease
    ;

    &::before,
    &::after {
      transition: transform .1s ease-out;
    }

    &::after    { transition-duration: .5s }
    &::before { transition-duration: .3s }
  }
}

Interaktionsstile für Mauszeiger und Fokus

Das Ziel der Interaktionsanimation besteht darin, die Schichten der Schaltfläche mit flachem Design. Legen Sie dazu die Variable --distance fest, anfänglich auf 1px. Mit dem Selektor im folgenden Codebeispiel wird geprüft, Sie können sehen, ob ein Gerät den Mauszeiger auf die Schaltfläche bewegt oder darauf fokussiert wird, wenn ein Gerät Fokusanzeige und nicht aktiviert ist. In diesem Fall übernimmt das CSS Folgendes:

  • Wenden Sie die Hintergrundfarbe an, über die der Mauszeiger darauf bewegt wird.
  • Strecke vergrößern
  • Füge einen Entspannungseffekt hinzu.
  • Verteilen Sie die Übergänge des Pseudoelements.
.threeD-button-set button {
  

  &:is(:hover, :focus-visible):not(:active) {
    /* subtle distance plus bg color change on hover/focus */
    --distance: 15px;
    background-color: var(--_btn-bg-hover);

    /* if motion is OK, setup transitions and increase distance */
    @media (--motionOK) {
      --distance: 3vmax;

      transition-timing-function: var(--_bounce-ease);
      transition-duration: .4s;

      &::after  { transition-duration: .5s }
      &::before { transition-duration: .3s }
    }
  }
}

Die 3D-Perspektive war für die Bewegungseinstellung reduced immer noch ansprechend. Die Elemente oben und unten stellen den Effekt auf subtile Weise zur Verfügung.

Kleine Verbesserungen mit JavaScript

Die Benutzeroberfläche kann über Tastaturen, Screenreader, Gamepads, Touchscreens mit der Maus. Wir können aber JavaScript-Elemente hinzufügen, von Szenarien.

Unterstützende Pfeiltasten

Mit der Tabulatortaste navigiere ich gut im Menü. oder Joysticks, um den Fokus auf einem Gamepad zu verschieben. Die roving-ux-Bibliothek, die häufig für GUI verwendet wird Challenge-Oberflächen übernehmen die Pfeiltasten für uns. Der Code unten teilt dem Bibliothek, um den Fokus innerhalb von .threeD-button-set abzufangen und ihn auf das Untergeordnete Elemente.

import {rovingIndex} from 'roving-ux'

rovingIndex({
  element: document.querySelector('.threeD-button-set'),
  target: 'button',
})

Interaktion mit Maus-Parallaxe

Die Bewegung der Maus und das Neigen des Menüs soll AR und VR imitieren. Videospiel-Oberflächen, bei denen Sie statt der Maus einen virtuellen Zeiger verwenden können. Es kann lustig sein, wenn die Elemente den Zeiger sehr bewusst sind.

Da dies eine kleine Zusatzfunktion ist, platzieren wir die Interaktion hinter einer Abfrage von die Bewegungspräferenz der Nutzenden. Speichern Sie bei der Einrichtung auch die Liste der Schaltflächen. Komponente mit querySelector in den Speicher ein und speichern die Begrenzungen des Elements menuRect. Legen Sie anhand dieser Grenzen den Rotationsversatz fest, der auf die Karte angewendet wird. basierend auf der Mausposition.

const menu = document.querySelector('.threeD-button-set')
const menuRect = menu.getBoundingClientRect()

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

Als Nächstes benötigen wir eine Funktion, die die x- und y-Mauspositionen akzeptiert und einen Wert, mit dem die Karte rotiert wird. Die folgende Funktion verwendet die Maus, um zu ermitteln, in welcher Seite der Box sie sich befindet. Die delta wird von der Funktion zurückgegeben.

const getAngles = (clientX, clientY) => {
  const { x, y, width, height } = menuRect

  const dx = clientX - (x + 0.5 * width)
  const dy = clientY - (y + 0.5 * height)

  return {dx,dy}
}

Beobachten Sie abschließend die Mausbewegung und übergeben Sie die Position an die Funktion getAngles(). und verwenden Sie die Deltawerte als benutzerdefinierte Eigenschaftsstile. Durch 20 geteilt, um die und es weniger verdreht, gibt es vielleicht eine bessere Methode. Wenn Sie Wir haben die Requisiten --x und --y in die Mitte einer clamp()-Funktion verhindert, dass die Mausposition zu stark gedreht wird. an einer unleserlichen Position.

if (motionOK) {
  window.addEventListener('mousemove', ({target, clientX, clientY}) => {
    const {dx,dy} = getAngles(clientX, clientY)

    menu.attributeStyleMap.set('--x', `${dy / 20}deg`)
    menu.attributeStyleMap.set('--y', `${dx / 20}deg`)
  })
}

Übersetzungen und Wegbeschreibungen

Beim Testen des Spielmenüs in anderen Schreibmodi Sprachen.

<button>-Elemente haben den Stil !important für writing-mode im Nutzer Agent-Stylesheet. Das bedeutete, dass der HTML-Code des Spielmenüs geändert werden musste, das gewünschte Design. Das Ändern der Schaltflächenliste in eine Liste von Links aktiviert logische Eigenschaften des Menüs, da <a>-Elemente keinen Browser haben bereitgestellten Stil !important.

Fazit

Jetzt, wo Sie wissen, wie ich das gemacht habe, wie würdest du... ‽ 🙂 Kannst du einen Beschleunigungsmesser hinzufügen? Interaktion mit dem Menü, sodass sich das Menü drehen soll, wenn Sie Ihr Telefon als Kachel verwenden? Können wir uns verbessern? keine Bewegungserkennung?

Lassen Sie uns unsere Herangehensweisen diversifizieren und alle Möglichkeiten kennenlernen, wie wir das Web entwickeln können. Erstelle eine Demo, twittere mir Links und ich füge sie hinzu im Abschnitt „Community-Remixe“ weiter unten.

Community-Remixe

Hier gibt es noch nichts zu sehen.