Webdesign - CSS3-Keyframe-Animation mit verschiedenen Objekten

  1. Zum Inhalt springen

webdesign
klamonfra
Klaus Franz


Wie setzt man CSS3-Keyframe-Animationen optimal um?

23Aug2014

CSS3-Keyframe-Animation mit verschiedenen Objekten


Bei diesem Beitrag werde ich einen animierten Gruß zu Ostern erstellen und möchte aufzeigen, wie man mit einfachen Mitteln eine lebendige und abwechslungsreiche Animation erstellt.
Und wie schon bei der Wolkenanimation, werde ich die einzelnen Schritte aufzeigen und jeweils mit kleinen Beispielen visuell darstellen. Ich animiere dabei verschiedene Objekte vor einem Bild aus Südtirol. Das Bild zeigt die Santner Spitze und ist auf der Seiser Alm aufgenommen worden.

Zuerst fange ich mit dem statischen Teil des Bildes an. Das Bild der Santner Spitze dient bei dieser Animation als Kulisse und ist in mehreren Ebenen aufgeteilt. Die erste Ebene wird als Hintergrund der Animation verwendet und besteht lediglich aus dem Himmel. Davor liegt in einer Ebene die Santner Spitze mit den Häusern und Bäumen damit eine Wolke hinter dem Berg vorbei fliegen kann. Die Wiese besteht aus drei weiteren Ebenen die jeweils nur einen Teil der Wiese darstellen und diese sind ebenfalls als png-Dateien abgespeichert. Somit können Blumen aus der Wiese wachsen und ein Osterei versinkt ein wenig in der Wiese.

Der Aufbau im HTML (HyperText Markup Language) sieht wie folgt aus.

<div id="hg">
    <div id="santner"> </div>
    <div id="wiese1"> </div>
    <div id="wiese2"> </div>
    <div id="wiese3"> </div>
    ...
</div>

Da ich einzelne Objekte, zum Beispiel die zweite Wolke, zeitweise außerhalb des Bildes positionieren muss, erhält der übergeordnete "div-Container" die Eigenschaft "overflow: hidden" und die Santner Spitze sowie die drei Einzelteile der Wiese werden per "z-index" weiter vorne positioniert.

Das zugehörige CSS3 (Cascading Style Sheet).

#hg {
    position: relative;
    overflow: hidden;
    background: url(/bilder/Seis.JPG) no-repeat;
    height: 35.2em;
    width: 46.9em;
    font-family: 'Comic Sans MS';
    text-align: center;
    color: #fff;
    text-transform: uppercase;
    border-radius: 20px;
    border: 5px solid #eee;
    box-shadow: 1px 1px 5px 2px #777;
    margin: 2em;
    z-index: 1;
}

#santner,
#wiese1,
#wiese2,
#wiese3 {
    position: absolute;
    height: 35.2em;
    width: 46.9em;
}

#santner {
    background: url(/bilder/santnerspitze.png) no-repeat;
    z-index: 10;
}

#wiese1 {
    background: url(/bilder/wiese1.png) no-repeat;
    z-index: 20;
}

#wiese2 {
    background: url(/bilder/wiese2.png) no-repeat;
    z-index: 30;
}

#wiese3 {
    background: url(/bilder/wiese3.png) no-repeat;
    z-index: 40;
}

Damit ist das Grundgerüst fertig und ich kann mit der Animation der einzelnen Objekte beginnen.


Animation der Wolken

Im Artikel der Wolkenanimation bin ich schon eingehend auf die Arbeitsweise der Keyframes eingegangen, deshalb wird hier nur die Einbindung in HTML5 (HyperText Markup Language) und CSS3 (Cascading Style Sheet) gezeigt. Der einzige Unterschied zu der reinen Wolkenanimation aus dem vorherigen Artikel besteht darin, dass ich die Bilder nicht im HTML5 (HyperText Markup Language), sondern direkt ins CSS3 (Cascading Style Sheet) eingebunden habe.
Ich habe in dieser Animation zwei Wolken eingebunden und per "z-index" hinter der Santner Spitze positioniert. Die zweite, kleinere Wolke wird dabei etwas versetzt nach oben gesetzt und bewegt sich zur ersten Wolke schneller. Und da die zweite Wolke erst nach 10 Sekunden im Bild erscheinen soll, wird sie mit "left: -135px" außerhalb des Bildes platziert.

<div id="hg">
    <div id="santner"> </div>
    <div id="wiese1"> </div>
    <div id="wiese2"> </div>
    <div id="wiese3"> </div>
    <div id="wolke1"> </div>
    <div id="wolke2"> </div>
    ...
</div>
#wolke1,
#wolke2 {
    position: absolute;
    height: 5em;
    width: 5em;
    background: url(/bilder/wolke_klein.png) no-repeat;
}

#wolke1 {
    z-index: 2;
    animation: wolke1 300s infinite linear;
}

@keyframes wolke1 {
    from{transform: scaleX(6) translate3d(-45px,40px,0)}
    to{transform: scaleX(5.7) translate3d(160px,40px,0)}
}

#wolke2 {
    z-index: 5;
    left: -135px;
    animation: wolke2 60s infinite linear 10s;
}

@keyframes wolke2 {
    from{transform: scaleX(2.3) translate3d(-60px,10px,0)}
    to{transform: scaleX(1.5) translate3d(600px,10px,0)}
}

Das Resultat bis hier:


Animation der Blumen

Damit verlasse ich die Welt der erstellten Fotos, und arbeite mit gezeichneten Bilder weiter.

Die Blumen werden etwas anders animiert als die Wolken.
Im Gegensatz zu den Wolken werden sie nicht als Endlosschleife mit dem Befehl "animation: infinite" eingebunden, sondern mit dem Befehl "animation: forwards". Damit behält das animierte Objekt nach Ablauf der Animationszeit den Style der letzten "@keyframes-Regel". Mit anderen Worten, die Blumen bleiben nach Ablauf der Zeit in der Wiese stehen und wachsen nicht wieder von Neuem.
Mit dem "z-index: 25" werden die Blumen zwischen zwei Ebenen der Wiese platziert und jede Sekunde wächst eine neue Blume aus der Wiese. Da beim Start der Animation alle Blumen ganz klein sind und gleichmäßig wachsen sollen, benötige ich nur die "@keyframes-Regel" für das Ende der Animation. Exemplarisch habe ich für die ersten drei Blumen die Einbindung in HTML (HyperText Markup Language) und CSS3 (Cascading Style Sheet) dokumentiert.

<div id="hg">
    ...
    <div id="wolke2"> </div>
    <div id="blume1"> </div>
    <div id="blume2"> </div>
    <div id="blume3"> </div>
    ...
</div>
#blume1,
#blume2,
#blume3 {
    position: absolute;
    top: 420px;
    left: 50px;
    transform: scale(.01);
    z-index: 25;
}

#blume1 {
    height: 2.8em;
    width: 1.9em;
    background: url(/bilder/blume2.png) no-repeat;
    animation: blume1 5s forwards linear;
}

@keyframes blume1 {
    to{transform: scale(1) translateY(-45px)}
}

#blume2 {
    height: 2.8em;
    width: 1.6em;
    background: url(/bilder/blume3.png) no-repeat;
    animation: blume2 6s forwards linear 1s;
}

@keyframes blume2 {
    to{transform: scale(1.2) translate3d(15px,-45px,0)}
}

#blume3 {
    height: 3.8em;
    width: 1.3em;
    background: url(/bilder/blume1.png) no-repeat;
    animation: blume3 7s forwards 2s;
}

@keyframes blume3 {
    to{transform: scale(1) translate3d(40px,-30px,0)}
}

Das Resultat, ohne Wolken aber dafür mit 8 Blumen.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.


Animation des Ostereis

Jetzt komme ich zu dem etwas aufwendigeren Teil der Animation.
Ziel ist es, dass sich ein Osterei von unten rechts aus dem Tal langsam nach oben die Wiese hoch bewegt und zwischendurch immer mal wieder stoppt. Das Osterei soll während der Bewegung natürlich kontinuierlich größer werden und zum Schluss horizontale Bewegungen ausführen.
Hierfür werden verschiedene "@keyframes-Regeln" erstellt. Während der Bewegung wird jede zweite Regel wiederholt, um den Stopp-Vorgang zu erhalten.

Aber es gibt eine kleine Schwierigkeit beim Festlegen der vertikalen und horizontalen Ausrichtung. Um das zu Verdeutlichen habe ich unten ein Bild eingefügt. Beide Ostereier haben die gleichen Angaben der Positionierung, außer dass das rechte Ei mit "transform: scale(.5)" nur halb so groß dargestellt wird.
Erst mit der doppelten Größenangabe bei "translate3d(-540px,70px,0)" ist das kleinere Osterei über dem großen Osterei zu sehen.

Aber wenn man das berücksichtigt ist es kein Problem mehr und ich kann das Osterei animieren. Und damit das Osterei nicht wie ein Fremdkörper wirkt und sich die Wiese leicht darin spiegeln soll, habe ich die Deckkraft mit "opacity: .9" auf 90% reduziert. Bei 48 - 60% der Zeitdauer wird die Deckkraft wieder etwas erhöht, da sich dahinter der Osterhase versteckt und nicht zu sehen sein soll.
Und wie bei den vorherigen Beispielen zeige ich zuerst die Einbindung in HTML5 (HyperText Markup Language) und dann das zugehörige CSS3 (Cascading Style Sheet). Man muss übrigens in einer "@keyframes-Regeln" nur die Veränderungen von Zuständen aufführen. Das heißt die "opacity: .9" gilt wieder ab 63% der Zeitdauer bis zum Schluss und die "transform: scale(1)" ab 48% bis 74% der Zeitdauer. Diese Tatsache macht die Größe eines CSS3 (Cascading Style Sheet) dadurch um einiges kleiner!

<div id="hg">
    ...
    <div id="blume8"> </div>
    <div id="ei1"> </div>
    ...
</div>
#ei1 {
    position: absolute;
    top: 340px;
    left: 680px;
    height: 6.3em;
    width: 5.6em;
    background: url(/bilder/ei_ganz.png) no-repeat;
    opacity: .9;
    z-index: 22;
    transform: scale(0);
    animation: ei1 30s;
}

@keyframes ei1 {
     5%  {transform: scale(0)}
     9%  {transform: scale(.07)}
    12%  {transform: scale(.15) translateY(90px)}
    15%  {transform: scale(.15) translateY(90px)}
    18%  {transform: scale(.23) translate3d(-150px,100px,0)}
    21%  {transform: scale(.23) translate3d(-150px,100px,0)}
    24%  {transform: scale(.33) translate3d(-200px,100px,0)}
    27%  {transform: scale(.33) translate3d(-200px,100px,0)}
    30%  {transform: scale(.55) translate3d(-200px,70px,0)}
    33%  {transform: scale(.55) translate3d(-200px,70px,0)}
    39%  {transform: scale(.8) translate3d(-250px,60px,0)}
    42%  {opacity: .9;
          transform: scale(.8) translate3d(-250px,60px,0)}
    48%  {opacity: .98;
          transform: scale(1) translate3d(-270px,35px,0)}
    60%  {opacity: .98;
          transform: translate3d(-270px,35px,0)}
    63%  {opacity: .9;
          transform: scaleX(1.1) translate3d(-250px,35px,0)}
    64%  {transform: translate3d(-270px,35px,0)}
    65%  {transform: scaleX(1.05) translate3d(-260px,35px,0)}
    66%  {transform: translate3d(-270px,35px,0)}
    67%  {transform: scaleX(1.1) translate3d(-250px,35px,0)}
    68%  {transform: translate3d(-270px,35px,0)}
    69%  {transform: scaleX(1.05) translate3d(-260px,35px,0)}
    70%  {transform: translate3d(-270px,35px,0)}
    71%  {transform: scaleX(1.1) translate3d(-250px,35px,0)}
    72%  {transform: translate3d(-270px,35px,0)}
    73%  {transform: scaleX(1.05) translate3d(-260px,35px,0)}
    74%  {transform: scale(1) translate3d(-270px,35px,0)}
    74.1%{transform: scale(.001)}
    75.2%{transform: scale(0)}
    to   {transform: scale(0)}
}

Und noch eine Verkürzung der "@keyframes-Regel", in dem man die gleichen Angaben bei den Prozenten zusammenfassen kann, ergibt:

@keyframes ei1 {
     5%           {transform: scale(0)}
     9%           {transform: scale(.07)}
    12%, 15%      {transform: scale(.15) translateY(90px)}
    18%, 21%      {transform: scale(.23) translate3d(-150px,100px,0)}
    24%, 27%      {transform: scale(.33) translate3d(-200px,100px,0)}
    30%, 33%      {transform: scale(.55) translate3d(-200px,70px,0)}
    39%           {transform: scale(.8) translate3d(-250px,60px,0)}
    42%           {opacity: .9;
                   transform: scale(.8) translate3d(-250px,60px,0)}
    48%           {opacity: .98;
                   transform: scale(1) translate3d(-270px,35px,0)}
    60%           {opacity: .98;
                   transform: translate3d(-270px,35px,0)}
    63%           {opacity: .9;
                   transform: scaleX(1.1) translate3d(-250px,35px,0)}
    64%, 66%, 68%,
         70%, 72% {transform: translate3d(-270px,35px,0)}
    65%, 69%, 73% {transform: scaleX(1.05) translate3d(-260px,35px,0)}
    67%, 71%      {transform: scaleX(1.1) translate3d(-250px,35px,0)}
    74%           {transform: scale(1) translate3d(-270px,35px,0)}
    74.1%         {transform: scale(.001)}
    75.2%, 100%   {transform: scale(0)}
}

Das Resultat, ohne Wolken, ohne Blumen und einem bewegenden Osterei.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.

Uups, das Osterei ist verschwunden!
Ach ja, der zweite Teil der Animation fehlt ja noch.


Animation des Ostereis, 2. Teil

Das Osterei soll natürlich nach der Bewegung platzen und die Osterwünsche freigeben. Dafür arbeite ich mit einer unteren und einer oberen Schale des Ostereis weiter.
Die untere Schale soll natürlich bis zum Schluss der Animation in der Wiese liegen bleiben und die obere Schale fliegt weg und landet danach an einer anderen Stelle in der Wiese. Damit es natürlicher aussieht, wird während der Flugphase die Deckkraft auf 98% erhöht.

<div id="hg">
    ...
    <div id="blume8"> </div>
    <div id="ei1"> </div>
    <div id="ei2"> </div>
    <div id="ei3"> </div>
    ...
</div>
#ei2,
#ei3 {
    position: absolute;
    top: 375px;
    left: 410px;
    height: 6.3em;
    width: 5.6em;
    opacity: .9;
    transform: scale(0);
}

#ei2 {
    background: url(/bilder/ei_unten.png) no-repeat;
    z-index: 23;
    animation: ei2 30s forwards;
}

@keyframes ei2 {
    74%        {transform: scale(0)}
    74.1%, 100%{transform: scale(1)}
}

#ei3 {
    background: url(/bilder/ei_oben.png) no-repeat;
    z-index: 33;
    animation: ei3 30s forwards linear;
}

@keyframes ei3 {
    74%       {transform: scale(0)}
    74.1%, 75%{transform: scale(1)}
    78%, 78.1%{opacity: .98;
               transform: rotate(-50deg) translate3d(30px,-90px,0)}
    81%, 81.1%{opacity: .98;
               transform: rotate(-100deg) translate3d(150px,-130px,0)}
    84%,  100%{opacity: .95;
               transform: rotate(-140deg) translate3d(230px,-180px,0)}
}

Das Resultat, ohne Wolken, ohne Blumen, einem bewegenden und dann platzenden Osterei.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.


Animation des Osterhasen

Jetzt fragt sich natürlich jeder:
Wie ist das Osterei nach oben auf die Wiese gekommen?

Nun, dafür ist natürlich der Osterhase zuständig. Er schiebt das Osterei den Berg hinauf und muss zwischendurch immer wieder eine kleine Pause zum Erholen einlegen, daher kommt es auch zu den Stopps des Ostereis. Nachdem das Osterei endlich den Berg erreicht hat, schaut der Hase hervor und hüpft aus Angst vor dem bewegenden Osterei davon.
Für diese Animation benötige ich wieder die "@keyframes-Regel" und die "3D-Transformationen". Und mit "transform: scaleX(-1)" wird der Hase bei einer "@keyframes-Regel" sogar gespiegelt.
Zum Ende der Animation schaut der Osterhase noch einmal um die Ecke. Das ist mit dem "div-Container" mit dem Namen "hase2" realisiert.

<div id="hg">
    ...
    <div id="ei3"> </div>
    <div id="hase1"> </div>
    <div id="hase2"> </div>
    ...
</div>
#hase1 {
    position: absolute;
    top: 405px;
    left: 420px;
    height: 5.6em;
    width: 3.8em;
    background: url(/bilder/hase1.png) no-repeat;
    z-index: 21;
    transform: scale(0);
    animation: hase1 30s;
}

@keyframes hase1 {
    51%       {transform: scale(0)}
    51.1%     {transform: scale(.7)}
    52%, 54.8%{transform: scale(1) translate3d(5px,-60px,0)}
    55%, 57.8%{transform: scale(.7)}
    58%, 61.8%{transform: scale(1) translate3d(-100px,-40px,0)}
    62%, 64.8%{transform: scale(.83) scaleX(-1) translate3d(80px,-50px,0)}
    65%, 67.8%{transform: scale(1) translate3d(-150px,-40px,0)}
    68%, 70.8%{transform: scale(.83) translate3d(-250px,-80px,0)}
    71%, 73.8%{transform: scale(.7) translate3d(-400px,-120px,0)}
    74%, 76.8%{transform: scale(.5) translate3d(-700px,-220px,0)}
    77%, 79.8%{transform: scale(.4) translate3d(-1000px,-300px,0)}
    80%,  100%{transform: scale(.3) translate3d(-1600px,-400px,0)}
}

#hase2 {
    position: absolute;
    top: 555px;
    left: -150px;
    height: 12.4em;
    width: 9.3em;
    background: url(/bilder/hase2.png) no-repeat;
    z-index: 50;
    animation: hase2 30s forwards 25s;
}

@keyframes hase2 {
    10%, 100%{transform: translate3d(100px,-100px,0)}
}

Das Resultat, ohne Wolken, ohne Blumen, einem bewegenden und dann platzenden Osterei sowie einem Osterhasen, der zum Schluss um die Ecke schaut.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.

Da fehlt aber noch etwas, der Osterhase bewegt ja seine Augen gar nicht.
Das wird sofort geändert!


Animation des Osterhasen, 2. Teil

Also wird für den Hasen, der um die Ecke schaut, noch eine zusätzliche Bewegung eingefügt. Dafür wird ein neuer "div-Container" mit der Identität id="hase3" eingefügt und wie folgt animiert:

<div id="hg">
    ...
    <div id="hase2"> </div>
    <div id="hase3"> </div>
    ...
</div>
#hase3 {
    position: absolute;
    top: 555px;
    left: -150px;
    height: 12.4em;
    width: 9.3em;
    opacity: 0;
    background: url(/bilder/hase_auge_zu.png) no-repeat;
    z-index: 50;
    animation: hase3 30s forwards 25s;
}

@keyframes hase3 {
    10%, 100%{opacity: 0;transform: translate3d(100px,-100px,0)}
    13%, 20%, 23%, 30%, 33%, 40%, 43%, 50%,
    53%, 60%, 63%, 70%, 73%, 80%, 83%, 90% {opacity: 0}
    15%, 25%, 35%, 45%, 55%, 65%, 75%, 85% {opacity: 1}
}

Das Resultat ist ein blinzelnder, um die Ecke schauender Osterhase.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.

Das könnte man natürlich auch mit einem gif-Bild erreichen, und wie das funktioniert steht im nächsten Abschnitt.


Animation der fliegenden Vögel

Die Besonderheit bei den Vögeln ist die Bewegung der Flügel und diese ist mit einer gif-Animation erstellt worden. Um die Bewegung realistischer darzustellen, muss der Vogelflug zeitlich auf den Flügelschlag abgestimmt sein. Und wie bereits bei dem Osterei, habe ich die Deckkraft auf 90% reduziert.

<div id="hg">
    ...
    <div id="hase2"> </div>
    <div id="hase3"> </div>
    <div id="adler"> </div>
    <div id="vogel"> </div>
    ...
</div>
#adler {
    position: absolute;
    left: -125px;
    height: 13.9em;
    width: 15.6em;
    background: url(/bilder/adler.gif) no-repeat;
    opacity: .9;
    z-index: 12;
    animation: adler 30s infinite linear;
}

@keyframes adler {
    from{transform: scale(.15) translate3d(-125px,40px,0)}
    to{transform: scale(.3) translate3d(2700px,450px,0)}
}

#vogel {
    position: absolute;
    left: 585px;
    height: 1.7em;
    width: 1.9em;
    background: url(/bilder/vogel.gif) no-repeat;
    opacity: .9;
    z-index: 12;
    animation: vogel 40s infinite linear;
}

@keyframes vogel {
    from{transform: scale(.5) translate3d(380px,150px,0)}
    to{transform: scale(.5) translate3d(-1300px,80px,0)}
}

Das Resultat sind zwei Vögel am Himmel.
Um die Animation noch mal von vorne zu sehen, drücken Sie bitte die -Taste.


Animation der Osterwünsche

Jetzt fehlt nur noch der Ostergruß.
Aus dem offenen Osterei sollen nun die Wünsche zum Osterfest herausfliegen. Nach bewährtem Schema ist das, wie unten aufgeführt, realisiert.

<div id="hg">
    ...
    <div id="vogel"> </div>
    <div class="text1">Monika und Klaus</div>
    <div class="text2">wünschen</div>
    <div class="text3">Frohe Ostern</div>
</div>
#text1,
#text2,
#text3 {
    position: absolute;
    opacity: 0;
    z-index: 21;
    transform: scale(.3);
}

#text1 {
    top: 360px;
    left: 360px;
    animation: text 29s forwards linear 20s;
}

#text2 {
    top: 390px;
    left: 400px;
    animation: text 29s forwards linear 23s;
}

#text3 {
    top: 420px;
    left: 390px;
    animation: text 29s forwards linear 26s;
}

@keyframes text {
     1%  {opacity: 0;}
     1.1%{opacity: 1;
          transform: scale(.3) rotate(90deg) translate3d(750px,250px,0)}
    20%  {transform: scale(.6) rotate(40deg) translate3d(-150px,-25px,0)}
    30%  {transform: scale(1) rotate(20deg) translate3d(-300px,-100px,0)}
    40%  {transform: scale(1) rotate(-10deg) translate3d(-100px,-360px,0)}
    to   {opacity: 1;
          transform: scale(1) rotate(-10deg) translate3d(-100px,-360px,0)}
}

Damit ist die Animation für die Wünsche zum Osterfest fertig!
Und hier ist sie endlich komplett zu sehen: Die besten Wünsche zu Ostern

Zum Seitenanfang springen Λ