Hacking CSS Animation State και χρόνος αναπαραγωγής PlatoBlockchain Data Intelligence. Κάθετη αναζήτηση. Ολα συμπεριλαμβάνονται.

Hacking CSS Animation State and Playback Time

Wolfenstein μόνο για CSS είναι ένα μικρό έργο που έφτιαξα πριν από μερικές εβδομάδες. Ήταν ένα πείραμα με τρισδιάστατους μετασχηματισμούς και κινούμενα σχέδια CSS.

Εμπνευσμένο από το Επίδειξη FPS και ένας άλλος Wolfenstein CodePen, αποφάσισα να φτιάξω τη δική μου έκδοση. Βασίζεται χαλαρά στο Επεισόδιο 1 – Όροφος 9 του αρχικού παιχνιδιού Wolfenstein 3D.

Επεξεργαστής: Αυτό το παιχνίδι απαιτεί σκόπιμα κάποια γρήγορη αντίδραση για να αποφευχθεί μια οθόνη Game Over.

Ακολουθεί ένα playthrough βίντεο:

[Ενσωματωμένο περιεχόμενο]

Με λίγα λόγια, το έργο μου δεν είναι παρά μια προσεκτικά γραμμένη μεγάλη κινούμενη εικόνα CSS. Συν μερικές περιπτώσεις του παραβίαση πλαισίου ελέγχου.

:checked ~ div { animation-name: spin; }

Το περιβάλλον αποτελείται από τρισδιάστατες όψεις πλέγματος και τα κινούμενα σχέδια είναι ως επί το πλείστον απλές τρισδιάστατες μεταφράσεις και περιστροφές. Τίποτα πραγματικά φανταχτερό.

Ωστόσο, δύο προβλήματα ήταν ιδιαίτερα δύσκολο να λυθούν:

  • Παίξτε το κινούμενο σχέδιο «όπλο πυροδότησης» κάθε φορά που ο παίκτης κάνει κλικ σε έναν εχθρό.
  • Όταν το αφεντικό που κινείται γρήγορα πέτυχε το τελευταίο χτύπημα, μπείτε σε μια δραματική αργή κίνηση.

Σε τεχνικό επίπεδο, αυτό σήμαινε:

  • Επανάληψη μιας κινούμενης εικόνας όταν είναι επιλεγμένο το επόμενο πλαίσιο ελέγχου.
  • Επιβραδύνετε μια κινούμενη εικόνα, όταν είναι επιλεγμένο ένα πλαίσιο ελέγχου.

Στην πραγματικότητα, κανένα από τα δύο δεν λύθηκε σωστά στο έργο μου! Ή κατέληξα να χρησιμοποιώ λύσεις ή απλώς τα παράτησα.

Από την άλλη, μετά από λίγο σκάψιμο, τελικά βρήκα το κλειδί και για τα δύο προβλήματα: την αλλαγή των ιδιοτήτων της εκτέλεσης κινούμενων εικόνων CSS. Σε αυτό το άρθρο, θα διερευνήσουμε περαιτέρω αυτό το θέμα:

  • Πολλά διαδραστικά παραδείγματα.
  • Ανατομές: πώς λειτουργεί (ή δεν λειτουργεί) κάθε παράδειγμα;
  • Πίσω από τη σκηνή: πώς χειρίζονται τα προγράμματα περιήγησης τις καταστάσεις κινούμενων εικόνων;

Ασε με «Πέτα τα τούβλα μου».

Πρόβλημα 1: Επανάληψη κινούμενων εικόνων

Το πρώτο παράδειγμα: "άλλο ένα πλαίσιο ελέγχου"

Η πρώτη μου διαίσθηση ήταν "απλώς προσθέστε ένα άλλο πλαίσιο ελέγχου", το οποίο δεν λειτουργεί:

Κάθε πλαίσιο ελέγχου λειτουργεί μεμονωμένα, αλλά όχι και τα δύο μαζί. Εάν ένα πλαίσιο ελέγχου είναι ήδη επιλεγμένο, το άλλο δεν λειτουργεί πλέον.

Δείτε πώς λειτουργεί (ή "δεν λειτουργεί"):

  1. Η animation-name of <div> is none από προεπιλογή.
  2. Ο χρήστης κάνει κλικ σε ένα πλαίσιο ελέγχου, animation-name γίνεται spin, και το animation ξεκινά από την αρχή.
  3. Μετά από λίγο, ο χρήστης κάνει κλικ στο άλλο πλαίσιο ελέγχου. Ένας νέος κανόνας CSS τίθεται σε ισχύ, αλλά animation-name is ακόμη spin, που σημαίνει ότι δεν προστίθεται ούτε αφαιρείται κινούμενη εικόνα. Το animation απλά συνεχίζει να παίζει σαν να μην συνέβη τίποτα.

Το δεύτερο παράδειγμα: "κλωνοποίηση του κινούμενου σχεδίου"

Μια προσέγγιση εργασίας είναι η κλωνοποίηση της κινούμενης εικόνας:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }

Εδώ είναι πώς αυτό λειτουργεί:

  1. animation-name is none αρχικά.
  2. Ο χρήστης κάνει κλικ στο "Spin!", animation-name γίνεται spin1. Το κινούμενο σχέδιο spin1 ξεκινά από την αρχή γιατί μόλις προστέθηκε.
  3. Ο χρήστης κάνει κλικ στο "Περιστροφή ξανά!", animation-name γίνεται spin2. Το κινούμενο σχέδιο spin2 ξεκινά από την αρχή γιατί μόλις προστέθηκε.

Σημειώστε ότι στο Βήμα #3, spin1 καταργείται λόγω της σειράς των κανόνων CSS. Δεν θα λειτουργήσει εάν το "Spin again!" ελέγχεται πρώτα.

Το τρίτο παράδειγμα: "προσάρτηση της ίδιας κινούμενης εικόνας"

Μια άλλη προσέγγιση εργασίας είναι η "προσάρτηση της ίδιας κίνησης":

#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }

Αυτό είναι παρόμοιο με το προηγούμενο παράδειγμα. Μπορείτε πραγματικά να κατανοήσετε τη συμπεριφορά ως εξής:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }

Σημειώστε ότι όταν "Περιστροφή ξανά!" είναι επιλεγμένο, το παλιό κινούμενο σχέδιο γίνεται το δεύτερο κινούμενο σχέδιο στη νέα λίστα, το οποίο μπορεί να μην είναι διαισθητικό. Μια άμεση συνέπεια είναι: το κόλπο δεν θα λειτουργήσει αν animation-fill-mode is forwards. Εδώ είναι ένα demo:

Αν αναρωτιέστε γιατί συμβαίνει αυτό, δείτε μερικές ενδείξεις:

  • animation-fill-mode is none από προεπιλογή, που σημαίνει "Το κινούμενο σχέδιο δεν έχει κανένα αποτέλεσμα εάν δεν παίζει".
  • animation-fill-mode: forwards; σημαίνει "Μετά την ολοκλήρωση της αναπαραγωγής της κινούμενης εικόνας, πρέπει να παραμείνει για πάντα στο τελευταίο βασικό καρέ".
  • spin1η απόφαση του πάντα υπερισχύει spin2γιατί spin1 εμφανίζεται αργότερα στη λίστα.
  • Ας υποθέσουμε ότι ο χρήστης κάνει κλικ στο "Spin!", περιμένει για μια πλήρη περιστροφή και μετά κάνει κλικ στο "Spin again!". Αυτή τη στιγμή. spin1 έχει ήδη τελειώσει και spin2 μόλις ξεκινά.

Ερωτήσεις - Συζήτηση

Εμπειρικός κανόνας: δεν μπορείτε να "επανεκκινήσετε" ένα υπάρχον animation CSS. Αντίθετα, θέλετε να προσθέσετε και να παίξετε μια νέα κινούμενη εικόνα. Αυτό μπορεί να επιβεβαιωθεί από η προδιαγραφή W3C:

Μόλις ξεκινήσει μια κινούμενη εικόνα, συνεχίζει μέχρι να τελειώσει ή να αφαιρεθεί το όνομα της κινούμενης εικόνας.

Τώρα, συγκρίνοντας τα δύο τελευταία παραδείγματα, νομίζω ότι στην πράξη, η "κλωνοποίηση κινούμενων εικόνων" θα πρέπει συχνά να λειτουργεί καλύτερα, ειδικά όταν είναι διαθέσιμος ο προεπεξεργαστής CSS.

Πρόβλημα 2: Αργή κίνηση

Κάποιος μπορεί να σκεφτεί ότι η επιβράδυνση ενός κινούμενου σχεδίου είναι απλώς θέμα ρύθμισης μεγαλύτερου χρονικού διαστήματος animation-duration:

div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }

Πράγματι, αυτό λειτουργεί:

… ή το κάνει;

Με μερικές τροποποιήσεις, θα είναι πιο εύκολο να δείτε το πρόβλημα.

Ναι, το animation έχει επιβραδυνθεί. Και όχι, δεν φαίνεται καλά. Ο σκύλος (σχεδόν) πάντα «πηδά» όταν αλλάζετε το πλαίσιο ελέγχου. Επιπλέον, ο σκύλος φαίνεται να πηδά σε μια τυχαία θέση και όχι στην αρχική. Πώς κι έτσι?

Θα ήταν ευκολότερο να το καταλάβουμε αν εισάγαμε δύο «σκιώδη στοιχεία»:

Και τα δύο σκιώδη στοιχεία εκτελούν τα ίδια κινούμενα σχέδια με διαφορετικά animation-duration. Και δεν επηρεάζονται από το πλαίσιο ελέγχου.

Όταν κάνετε εναλλαγή του πλαισίου ελέγχου, το στοιχείο απλώς αλλάζει αμέσως μεταξύ των καταστάσεων δύο σκιωδών στοιχείων.

Αναφορά η προδιαγραφή W3C:

Οι αλλαγές στις τιμές των ιδιοτήτων κινούμενων εικόνων ενώ εκτελείται η κινούμενη εικόνα ισχύουν σαν να είχε αυτές τις τιμές από την αρχή.

Αυτό ακολουθεί το ανιθαγενείς σχεδιασμός, ο οποίος επιτρέπει στα προγράμματα περιήγησης να προσδιορίζουν εύκολα την τιμή κινουμένων σχεδίων. Περιγράφεται ο πραγματικός υπολογισμός εδώ και εδώ.

Άλλη μια προσπάθεια

Μια ιδέα είναι να θέσετε σε παύση την τρέχουσα κινούμενη εικόνα και, στη συνέχεια, να προσθέσετε μια πιο αργή κινούμενη εικόνα που αναλαμβάνει από εκεί:

div {
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

Λειτουργεί λοιπόν:

… ή το κάνει;

Επιβραδύνει όταν κάνετε κλικ στο "Slowmo!". Αλλά αν περιμένετε για έναν πλήρη κύκλο, θα δείτε ένα "άλμα". Στην πραγματικότητα, πηδά πάντα στη θέση όταν "Slowmo!" γίνεται κλικ.

Ο λόγος είναι ότι δεν έχουμε α from καθορισμένο βασικό καρέ – και δεν θα έπρεπε. Όταν ο χρήστης κάνει κλικ στο "Slowmo!", spin1 είναι σε παύση σε κάποια θέση και spin2 ξεκινά ακριβώς από την ίδια θέση. Απλώς δεν μπορούμε να προβλέψουμε αυτή τη θέση εκ των προτέρων… ή μπορούμε;

Μια λειτουργική λύση

Μπορούμε! Χρησιμοποιώντας μια προσαρμοσμένη ιδιότητα, μπορούμε να καταγράψουμε τη γωνία στην πρώτη κίνηση και, στη συνέχεια, να τη μεταφέρουμε στη δεύτερη κίνηση:

div {
  transform: rotate(var(--angle1));
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  transform: rotate(var(--angle2));
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

@keyframes spin1 {
  to {
    --angle1: 360deg;
  }
}

@keyframes spin2 {
  from {
    --angle2: var(--angle1);
  }
  to {
    --angle2: calc(var(--angle1) + 360deg);
  }
}

Σημείωση: @property χρησιμοποιείται σε αυτό το παράδειγμα, το οποίο είναι δεν υποστηρίζεται από όλα τα προγράμματα περιήγησης.

Η «Τέλεια» Λύση

Υπάρχει μια προειδοποίηση για την προηγούμενη λύση: η "έξοδος από το slowmo" δεν λειτουργεί καλά.

Εδώ είναι μια καλύτερη λύση:

Σε αυτήν την έκδοση, η αργή κίνηση μπορεί να εισαχθεί ή να βγει απρόσκοπτα. Δεν χρησιμοποιείται επίσης κανένα πειραματικό χαρακτηριστικό. Είναι λοιπόν η τέλεια λύση; Ναι και ΟΧΙ.

Αυτή η λύση λειτουργεί όπως η «αλλαγή» «γρανάζι»:

  • Γρανάζια: υπάρχουν δύο <div>μικρό. Ο ένας είναι γονιός του άλλου. Και τα δύο έχουν το spin κινούμενα σχέδια αλλά με διαφορετικά animation-duration. Η τελική κατάσταση του στοιχείου είναι η συσσώρευση και των δύο κινούμενων εικόνων.
  • Μετατόπιση: Στην αρχή, μόνο ένα <div> τρέχει το animation του. Το άλλο είναι σε παύση. Όταν γίνεται εναλλαγή του πλαισίου ελέγχου, και οι δύο κινούμενες εικόνες αλλάζουν τις καταστάσεις τους.

Αν και μου αρέσει πολύ το αποτέλεσμα, υπάρχει ένα πρόβλημα: είναι μια ωραία εκμετάλλευση του spin animation, το οποίο δεν λειτουργεί για άλλους τύπους κινούμενων εικόνων γενικά.

Μια πρακτική λύση (με JS)

Για γενικά κινούμενα σχέδια, είναι δυνατό να επιτευχθεί η λειτουργία αργής κίνησης με λίγο JavaScript:

Μια γρήγορη εξήγηση:

  • Μια προσαρμοσμένη ιδιότητα χρησιμοποιείται για την παρακολούθηση της προόδου της κινούμενης εικόνας.
  • Το κινούμενο σχέδιο "ξανεκκινείται" όταν το πλαίσιο ελέγχου είναι εναλλαγή.
  • Ο κώδικας JS υπολογίζει το σωστό animation-delay για να εξασφαλίσει μια απρόσκοπτη μετάβαση. προτείνω αυτό το άρθρο εάν δεν είστε εξοικειωμένοι με τις αρνητικές τιμές του animation-delay.

Μπορείτε να δείτε αυτήν τη λύση ως ένα υβρίδιο της «επανεκκίνησης κινούμενων σχεδίων» και της προσέγγισης «αλλαγής ταχύτητας».

Εδώ είναι σημαντικό να παρακολουθείτε σωστά την πρόοδο του animation. Είναι δυνατές λύσεις εάν @property δεν είναι διαθέσιμο. Για παράδειγμα, αυτή η έκδοση χρησιμοποιεί z-index για να παρακολουθείτε την πρόοδο:

Πλευρική σημείωση: αρχικά, προσπάθησα επίσης να δημιουργήσω μια έκδοση μόνο για CSS αλλά δεν τα κατάφερα. Αν και δεν είναι 100% σίγουρο, νομίζω ότι είναι επειδή animation-delay is μη ζωντανή.

Εδώ είναι μια έκδοση με ελάχιστη JavaScript. Μόνο το «είσοδος σε slowmo» λειτουργεί.

Ενημερώστε με εάν καταφέρετε να δημιουργήσετε μια λειτουργική έκδοση μόνο για CSS!

Slow-mo Any Animation (με JS)

Τέλος, θα ήθελα να μοιραστώ μια λύση που λειτουργεί για (σχεδόν) οποιοδήποτε κινούμενο σχέδιο, ακόμη και με πολλά περίπλοκα @keyframes:

Βασικά, πρέπει να προσθέσετε έναν ανιχνευτή προόδου κινουμένων σχεδίων και, στη συνέχεια, να υπολογίσετε προσεκτικά animation-delay για το νέο κινούμενο σχέδιο. Ωστόσο, μερικές φορές μπορεί να είναι δύσκολο (αλλά πιθανό) να λάβετε τις σωστές τιμές.

Για παράδειγμα:

  • animation-timing-function δεν είναι linear.
  • animation-direction δεν είναι normal.
  • πολλαπλές τιμές σε animation-name με διαφορετικές animation-durationκαι του animation-delay's.

Περιγράφεται επίσης αυτή η μέθοδος εδώ των Web Animations API.

Ευχαριστίες

Ξεκίνησα σε αυτό το μονοπάτι αφού συνάντησα έργα μόνο για CSS. Καπου λεπτό έργο τέχνης, και μερικά ήταν σύνθετες κατασκευές. Τα αγαπημένα μου είναι αυτά που περιλαμβάνουν τρισδιάστατα αντικείμενα, για παράδειγμα, αυτό αναπήδηση μπάλα και αυτό συσκευασία κύβο.

Στην αρχή, δεν είχα ιδέα πώς φτιάχτηκαν. Αργότερα διάβασα και έμαθα πολλά αυτό το ωραίο σεμινάριο από την Ana Tudor.

Όπως αποδείχθηκε, η κατασκευή και η κίνηση τρισδιάστατων αντικειμένων με CSS δεν διαφέρει πολύ από το να το κάνεις με Μίξερ, απλά με λίγο διαφορετική γεύση.

Συμπέρασμα

Σε αυτό το άρθρο εξετάσαμε τη συμπεριφορά των κινούμενων εικόνων CSS όταν ένα animate-* η ιδιοκτησία μεταβάλλεται. Ειδικά επεξεργαστήκαμε λύσεις για την "επανάληψη ενός κινούμενου σχεδίου" και "κινούμενη εικόνα αργής κίνησης".

Ελπίζω να βρείτε αυτό το άρθρο ενδιαφέρον. Σε παρακαλώ πες μου τις σκέψεις σου!

Σφραγίδα ώρας:

Περισσότερα από Κόλπα CSS