Verbergen von Elementen

Manchmal notwendig auf interaktiven Webseiten: Elemente kurzzeitig verbergen
Für statische Webseiten ohne Benutzerinteraktion sinnlos
Interaktionsmöglichkeiten über …
  • Mausereignisse mit der :hover Pseudoklasse
  • Navigationsereignisse mit der :target Pseudoklasse
  • Formulare
  • Allgemein clientseitiges JavaScript

Das HTML-Attribut hidden

Zugedachter Einsatzzweck: Unfertige Elemente oder technische Details ausblenden
  • Zur Überbrückung von Ladevorgängen bei AJAX-Anfragen
  • In der Computergrafik: Für einen nicht darzustellendes Renderziel (RTT, render to texture)
  • animate/hiding-attr-hidden.html | Validieren
    <label>
      <input type="checkbox"> Unsichtbares Entdecken?
    </label>
    <div hidden>
      Man sieht mich nicht
    </div>
    
  • animate/hiding-attr-hidden.js
    const checkElem = document.querySelector('[type="checkbox"]');
    const hiddenElem = document.querySelector('[hidden]');
    
    const updateHidden = _ => {
      if (checkElem.checked)
        hiddenElem.removeAttribute("hidden");
      else
        hiddenElem.setAttribute("hidden", "");
    };
    
    checkElem.addEventListener('change', updateHidden);
    updateHidden();
    

Die CSS-Eigenschaft visibility

Drei mögliche Werte um die Art der Sichtbarkeit zu beeinflussen
  • visible ist der Standardwert, das Element wird dargestellt
  • Mit hidden nimmt das Element weiterhin Platz im Layout ein, wird aber nicht dargestellt
  • In Tabellen und Flex-Layouts: Mit collapse nimmt das Element weder Platz im Layout ein, noch wird es dargestellt
Ursprünglich zugedachter Einsatzzweck: Tabellenelemente mit collapse vollständig ausblenden
Funktioniert für Tabellen nur absolut unzuverlässig, lieber nicht verwenden
Für hidden: Elemente werden ausgeblendet, ohne dabei zwingend Kindelemente zu beinflussen
  • Praktisch für komplexe hover-Effekte, erlaubt auch Animationen
  • Allerdings: Versteckte Elemente lösen keine hover-Ereignisse aus
  • animate/hiding-visibility-hover.html | Validieren
    {% for image in page.images %}
      <div class="item">
        <div class="decoration">
          <img src="{{ image.url }}">
          <a href="{{ image.cite }}" rel="author">{{ image.name }}</a>
        </div>
      </div>
    {% endfor %}
    
  • animate/hiding-visibility-hover.css
    .item {
        float: left;
    }
    
    .item .decoration {
        visibility: hidden;
        width: 100px;
        margin: 5px;
        border: 5px solid red;
        text-align: center;
    }
    
    .item .decoration img,
    .item:hover .decoration {
        visibility: visible;
    }
    
    

visibility: collapse und display: flex

collapse ist für Flexboxen wohldefiniert (und gut implementiert)
Im Gegensatz zu Tabellen: Mit Flexboxen ist collapse sinnvoll nutzbar
  • animate/hiding-visibility-flex.html | Validieren
    <ul>
      <li id="escort">
        <a href="#escort">Escort</a>
        <ul>
          <li>Dorado</li>
          <li>Route 66</li>
          <li>Watchpoint: Gibraltar</li>
        </ul>
      </li>
      <li id="control">
        <a href="#control">Control</a>
        <ul>
          <li>Ilios</li>
          <li>Lijang Tower</li>
          <li>Nepal</li>
          <li>Oasis</li>
        </ul>
      </li>
    </ul>
    
  • animate/hiding-visibility-flex.css
    ul > li {
      display: flex;
      flex-flow: column;
    }
    
    ul > li:not(:target):not(:hover) > ul {
      visibility: collapse;
    }
    

Die CSS-Eigenschaft display

Zugedachter Einsatzzweck: Art der Box spezifizieren
Erlaubt Werte wie inline, block, inline-block, flex, …
Ebenfalls erlaubter Wert: none
  • Element wird unsichtbar und hat keinerlei Auswirkungen auf den Elementfluss
  • Solcheart versteckte Elemente lösen keine Ereignisse aus und werden von Assistenzsystemen ignoriert
Problem bei “Wiederherstellung”: Steht in Konflikt mit anderen display-Eigenschaften
Der Wert none muss irgendwie wieder den ursprünglichen Wert erhalten
Implementierung einer allgemeinen .hidden-Klasse mit display daher nicht möglich
Abhängig vom Kontext lassen sich immer “kaputte” Szenarien erzeugen

Die CSS-Eigenschaft opacity

Zugedachter Einsatzzweck: Elemente teiltransparent darstellen
Aber ein vollständig transparentes Element ist selbstverständlich auch unsichtbar

Zeitabhängige Animation mit CSS

Ziel: Graduelle Veränderung von numerischen Werten ohne JavaScript
Technik dahinter ist allerdings noch nicht vollständig standarisiert
Nicht alle Eigenschaften lassen sich animieren, numerische Werte aber meistens schon
Genaue Auflistung zum Beispiel im MDN

Transitionen

Funktionsweise: Neue CSS-Eigenschaften werden nicht unmittelbar angewendet, sondern zeitabhängig verändert
Angegeben wird immer der gewünschte Zielzustand, die Zwischenwerte berechnet der Browser
Zwischenwerte werden über eine mathematische Funktion berechnet
Standardwert ist eine “Ease”-Funktion, andere Berechnungen ebenfalls möglich
Syntax: Liste von animierten Eigenschaften mit Dauer und Funktion
  • Animation aller Eigenschaften mit all möglich
  • Explizite Angabe der Animationsfunktion mit transition-timing-function

Beispiel: Veränderung einer Eigenschaft

Beispiel: Veränderung zweier Eigenschaften

Beispiel: Veränderung aller Eigenschaften

  • animate/transition-all.html | Validieren
    {% for i in (1..5) %}
      <div class="bar">
        Bar {{ i }}
      </div>
    {% endfor %}
    
  • animate/transition-all.css
    .bar {
        width: 20%;
        background-color: red;
        border: 2px solid red;
        text-align: right;
        transition: all 2s;
    }
    
    .bar:hover {
        width: 90%;
        background-color: green;
        margin-left: 10%;
        border: 2px solid yellow;
    }
    

Stetige Übergangsfunktionen

Intern: Verarbeitung von kubischen Bézier-Kurven
Irrelevantes Implementierungsdetail für nicht MInf und nicht CGT
linear
linear
ease
ease
ease-in
ease-in
ease-in-out
ease-in-out
ease-out
ease-out

Unstetige Übergangsfunktionen

Angabe von Schritten mit steps(number, direction)
  • number Ganzzahl für die Anzahl der Schritte
  • direction ist start oder end und bestimmt ob am Anfang oder am Ende keine Zeit vergehen soll
Bald: Angabe von Schritten mit frames(number)
steps(1, start)
steps(1, start)
steps(1, end)
steps(1, end)
steps(2,start)
steps(2,start)
steps(4,end)
steps(4,end)
frames(2)
frames(2)
frames(4)
frames(4)

Beispiele für Übergangsfunktionen

  • animate/transition-func.html | Validieren
    <div class="parent">
      {% for func in page.transitions %}
        <div class="bar"
             style="transition-timing-function: {{ func }};">
          <code>{{ func }}</code>
        </div>
      {% endfor %}
    </div>
    
  • animate/transition-func.css
    .bar {
        width: 25%;
        background-color: rgba(255, 0, 0, 0.2);
        border: 1px solid black;
        margin: 2px;
        text-align: right;
        transition: width 3s;
    }
    
    .parent:hover .bar {
        width: 100%;
    }
    

Animationen mit Keyframes

Funktionsweise: Neue CSS-Eigenschaften durchlaufen eine Liste von Zuständen (“Keyframe”)
Letzter Keyframe steht für den endgültigen Zustand
Umfangreiche Spezifikation aus acht Werten
  • animation-name für die zu verwendende Keyframe-Liste
  • animation-duration für die Dauer der Animation
  • animation-iteration-count für die Anzahl der Wiederholungen

Beispiel für endlos laufende Animation

  • animate/animate-color.html | Validieren
    <div class="rainbow">
      Rainbow
    </div>
    
  • animate/animate-color.css
    @keyframes colorRotate {
        from  { color: rgb(255,   0,   0); }
        16.6% { color: rgb(255,   0, 255); }
        33.3% { color: rgb(  0,   0, 255); }
        50%   { color: rgb(  0, 255, 255); }
        66.6% { color: rgb(  0, 255,   0); }
        83.3% { color: rgb(255, 255,   0); }
        to    { color: rgb(255,   0,   0); }
    }
    
    .rainbow {
        font-size: 15vw;
        font-family: monospace;
        text-align: center;
        animation: colorRotate 3s linear 0s infinite;
    }
    
    

Eigene Animationen mit requestAnimationFrame

Funktionsweise: Zum rendern aufgerufene Callback-Funktion
  • Ähnlich wie z.B. ein draw-Callback in OpenGL
  • Erster Parameter des Callbacks ist die vergangene Zeit
  • Angefordert wird exakt ein Frame, für wiederholte Verarbeitung muss ein neuer Aufruf angefordert werden
Exakte Aufruffrequenz wird vom Browser festgelegt
  • Typischerweise entsprechend der Bildwiederholfrequenz
  • Wird nicht aufgerufen wenn z.B. der Tab im Hintergrund ist
Innerhalb des Callbacks: Beliebige Operationen
  • DOM-Manipulation, <canvas>-Zeichenoperationen, WebGL-3D-Rendering, …
  • Nutzung zur Animationen von Eigenschaften, welche mit Keyframes nicht addressierbar sind

Beispiel für eine Animation der textContent-Eigenschaft

  • animate/animate-js-frames.html | Validieren
    <p>
      Es bleiben noch <span id="timeleft">0</span>
      Millisekunden bis <time>0</time> ms seit dem ersten
      Laden der Seite vergangen sind.
    </p>
    <button>Neuen Zähler starten</button>
    
  • animate/animate-js-frames.js
    const targetTimeElem = document.querySelector('time');
    const timeLeftElem = document.querySelector('#timeleft');
    const startTimerBtn = document.querySelector('button');
    
    const updateTargetTime = () => {
      targetTimeElem.textContent = performance.now() + 2000;
    };
    
    const animateTime = (timestamp) => {
      const endTime = +targetTimeElem.textContent;
      const remainingTime = endTime - timestamp;
    
      if (remainingTime > 0) {
        timeLeftElem.textContent = Math.round(remainingTime);
        window.requestAnimationFrame(animateTime);
      } else {
        timeLeftElem.textContent = 0;
      }
    };
    
    const startTimer = () => {
      updateTargetTime();
      window.requestAnimationFrame(animateTime);
    };
    
    startTimerBtn.addEventListener('click', startTimer);
    
    startTimer();
    
    

Dreidimensionale Transformationen

Seit CSS3: Setzen von beliebigen affinen Transformationen für alle Elemente
Auf Basis von Komfortfunktionen wie rotateX(angle) oder durch direkte Angabe von Matrizen
Im Rahmen dieser Veranstaltung: Oberflächliche Erwähnung
Tipp: Wundervolles Tutorial von David DeSandro
Vorraussetzung für 3D-Darstellung: Spezifikation der Perspektive
Näherungsweise: Distanz der Kamera zu den 3D-Objekten

Einfache Abbildungen

Vorsicht: Beispielcode ist sehr repetetiv und voller nebensächlicher Farbgebungen und Größen
Gezeigte Quelltexte sind lediglich Ausschnitte
Quintessenz: Beispiele für die Effekte unterschiedlicher Transformationsfunktionen
Setzen von perspektive auf dem Elternelement und transform auf dem Kind
  • animate/transform-functions.html | Validieren
    <div class="container">
      <div class="panel" id="translateNegZ">
        translateZ(-200px)
      </div>
    </div>
    
    <div class="container">
      <div class="panel" id="translatePosZ">
        translateZ(200px)
      </div>
    </div>
    
  • animate/transform-functions.css
    .container {
        perspective: 1000px;
    }
    
    #translateNegZ {
        transform: translateZ(-200px);
    }
    
    #translatePosZ {
        transform: translateZ(200px);
    }
    
    #rotateX {
        transform: rotateX(45deg);
    }
    
    #rotateY {
        transform: rotateY(45deg);
    }
    

Animierte Abbildungen

Numerische Parameter der transform-Eigenschaft lassen sich hervorragend animieren

Änderungen im Vergleich zum vorherigen Beispiel
  • Angabe von transition: transform 2000ms; für alle .panel-Elemente
  • Anwendung der bisherigen transform-Werte bei :hover
  • animate/transform-functions-transition.css
    .container {
        perspective: 1000px;
    }
    
    .panel {
        transition: transform 2000ms;
    }
    
    #translateNegZ:hover {
        transform: translateZ(-200px);
    }
    
    #translatePosZ:hover {
        transform: translateZ(200px);
    }
    
    #rotateX:hover {
        transform: rotateX(45deg);
    }
    
    #rotateY:hover {
        transform: rotateY(45deg);
    }
    

Beispiel: Drehen einer Spielkarte

  • animate/transform-cardflip.html | Validieren
    {% for card in page.cards %}
      <div class="card">
        <div class="front">
          <h1>{{ card.name }}</h1>
          <img src="{{ card.img }}">
          <p class="text">{{ card.text }}</p>
        </div>
        <div class="back">
          <img src="/assets/fhw.svg"
               alt="Cardback Art">
          <h1>The TCG</h1>
        </div>
      </div>
    {% endfor %}
    
  • animate/transform-cardflip.css
    .card {
        perspective: 600px;
        position: relative;
        width: 200px;
        height: 300px;
        margin: 20px;
    }
    
    .card > div {
        position: absolute;
        backface-visibility: hidden;
        transition: transform 1000ms;
        height: 100%;
        width: 100%;
    }
    
    .card .front {
        transform: rotateY(180deg);
    }
    
    .card:hover .back {
        transform: rotateY(180deg);
    }
    
    .card:hover .front {
        transform: rotateY(360deg);
    }