Műhely · vissza a rovathoz

Miért ugrik az animáció első képkockája?

A mozgás-kód hibátlan volt, a doboz mégis ugrott egy nagyot az induláskor, és utána mozgott csak szépen. Az ok két lépéssel arrébb állt.

A keresőpanel alján egy lábsor mondja meg, hány találat van, és azt is, ha nincs egy sem. Ez a sor nulla magasságról nyílik ki, JavaScriptből: egy követő minden képkockán ráír egy magasságot, és a szám végig azon az íven halad, amin haladnia kell.

A képernyőn viszont ugrott. Az első képkockán majdnem teljes magasságra állt, és onnantól mozgott finoman — ez rosszabb, mint ha végig ugrálna, mert a mozgás második fele tökéletesen sima, tehát a mozgás-kód jónak látszik.

Mit mutat a mérés, ha a kód jónak látszik?

A mozgás-kód olvasása itt nem visz előre, mert nincs benne hiba. Ami előrevisz: képkockánként kiírni két számot egymás mellé — amit a szkript beállít, és amit a doboz valójában felvesz.

Képkockánkénti nyom a lábsor nyílásáról — a beállított és a felvett magasság
$ ~/.kk-venv/bin/python tipp-nyom.py
  116,0ms   h=  20,19   lepes= +19,19   style.height=      1px
  184,0ms   h=  20,30   lepes=  +0,11   style.height=   20,3px
  201,0ms   h=  20,50   lepes=  +0,20   style.height=   20,5px
  217,0ms   h=  20,69   lepes=  +0,19   style.height=   20,7px
  234,0ms   h=  21,00   lepes=  +0,31   style.height=     21px

A két szám nem egyezett. A szkript egy képpontra állította a magasságot, a doboz mégis 20,19 képpontot foglalt. Innentől a kérdés az, mi nem engedi a dobozt egy képpontnál kisebbre.

Mi tesz padlót a doboz alá?

A 20,19 kijön papíron: 9,6 meg 9,6 meg 1. Padding fent, padding lent, egy képpont keret. A box-sizing: border-box azt jelenti, hogy a megadott magasság a keretet és a paddingot is magában foglalja — a padding viszont nem nyomható össze. A padding padlót tesz a doboz alá, és a magasság-animáció addig nem látszik, amíg a padló fölé nem ér.

A padló a doboz alatt A rövidítéssel a padló azonnal a végértéken áll: a szkript magassága alulról indul, de amíg a padló alatt van, a doboz meg sem mozdul, ezért az első képkockán odaugrik. A két longhanddal a padló a magassággal együtt emelkedik, végig alatta marad, és a doboz követi a mozgást. a rövidítéssel ugrás amit a szkript ráír padló — padding és keret a két longhanddal a doboz végig követi a padló együtt emelkedik
a rövidítéssela padló — padding és keret — azonnal a végértéken
a két longhanddala padló együtt emelkedik
a rövidítésselamit a szkript ráír, az a padló alatt marad — ugrás
a két longhanddala doboz végig követi

a szkript mindkét esetben ugyanazt a magasságot írja rá

Miért állt a padding már a végértéken?

Mert a paddingnak is animálódnia kellett volna, csak nem tette. A stíluslapban egyetlen átmenet-lista állt, három tulajdonsággal: az opacity mozgott, a border-color mozgott, a padding-block pedig egyetlen képkockán a végértékre ugrott. Ez az a pont, ahol a padló azonnal a helyére állt, miközben a magasság még alulról jött.

Az ok motorfüggő. A WebKit a padding-block rövidítésre nem indít átmenetet, a padding-block-start és a padding-block-end longhandra viszont igen. Chromiumban a rövidítés is megy — vagyis az előnézeti böngészőben az egész hibátlanul nézett ki.

Melyik tulajdonságra indul valódi átmenet — WebKitben mérve, két képkockával a változtatás után
$ ~/.kk-venv/bin/python pad-teszt.py
  transition: padding-block          → 20px      UGROTT
  transition: padding-block-start    → 1px       animál
  transition: padding-top            → 1.1px     animál
  transition: opacity                → 0.056667  animál

A mérésnek van egy csapdája. A beállítás után rögtön olvasva a computed érték már a végértéket adja, mert az átmenet csak a következő stílusszámoláskor indul el. Ebből úgy tűnik, mintha semmilyen tulajdonság nem animálódna — két képkockával később kell olvasni.

Mi lett a javítás?

Egy sor helyett kettő, ugyanazzal a tempóval és lágyítással.

A lábsor átmenet-listájaCSS
transition: opacity var(--t-felulet) var(--ease-oda-vissza),
            padding-block-start var(--t-felulet) var(--ease-oda-vissza),
            padding-block-end var(--t-felulet) var(--ease-oda-vissza),
            border-color var(--t-felulet) var(--ease-oda-vissza);

Ezzel a padding a magassággal együtt nő. A padló is emelkedik, csak lassabban, mint amilyen gyorsan a magasság távolodik tőle: a teljes padding és keret 20,19 képpont, a teljes magasság 36,8 — a doboz így soha nem éri utol a saját padlóját. Mérve az első lépés 19,2 képpontról 1,5-re csökkent, a küszöb 3,5.

Mit lehet ebből általánosítani?

Az elsőt a tünet és az ok távolsága adja. Ha egy animált méret az elején ugrik, utána szép, akkor jellemzően nem a mozgással van baj: valami padlót tesz a doboz alá, és a mozgás első szakasza a padló alatt zajlik, láthatatlanul. Padlót tesz a padding, a keret, a min-height, a sor magassága, és flexben az elem tartalmi minimuma.

A második a rövidítés. Egy átmenet-listában a rövidítés-tulajdonság kockázat: ha a motor nem ismeri fel animálhatónak, akkor nem hibázik, hanem ugrik — és az ugrás nem ott jelentkezik, ahol a rövidítés áll. Ugyanez a gyanú áll a padding, a margin, az inset és a padding-inline esetére.

Ezen a szabályon egy korábbi kör már elcsúszott. Ugyanerre a 20,19 képpontra akkor min-height: 0 került a szabályba, és az a tünet egy másik megjelenését meg is oldotta — a számot viszont nem, mert a padló továbbra is ott volt, csak máshonnan.

Ezt a hibát egy ellenőrzés találta meg, ami számot adott — képkockánkénti csúcsot és küszöböt. Arról, hogy mit érdemes gépre bízni egy oldal átnézéséből, a gépi ellenőrzésről szóló darab szól.

Kérdések a témáról

Miért ugrik egy magasság-animáció az első képkockán?

Jellemzően nem a mozgás a hibás, hanem az, hogy valami padlót tesz a doboz alá: a megadott magasság egy darabig a padló alatt van, tehát a doboz nem mozdul, majd amint a magasság a padló fölé ér, a doboz egyszerre ugrik oda. A mozgás második fele ilyenkor tökéletesen sima, ezért látszik a mozgás-kód jónak.

Mi tesz padlót egy doboz alá?

A box-sizing: border-box mellett a megadott magasság a keretet és a paddingot is magában foglalja, a padding viszont nem nyomható össze. Fent és lent 9,6 képpont belső térköz plusz egy képpont keret azt jelenti, hogy a doboz 20,19 képpontnál alacsonyabb nem lehet, akármit ír rá a szkript. Ugyanígy padlót tesz a min-height, a sor magassága, és flexben az elem tartalmi minimuma.

Melyik átmenet-tulajdonságokra érdemes gyanakodni?

A rövidítésekre. A WebKit a padding-block rövidítésre nem indít átmenetet, a padding-block-start és a padding-block-end longhandra igen; Chromiumban a rövidítés is megy, tehát a különbség csak az egyik motoron látszik. Ugyanez a gyanú áll a padding, a margin, az inset és a padding-inline esetére.

Hogyan lehet megmérni, hogy egy átmenet tényleg fut-e?

Két képkockával a változtatás után kell olvasni a computed értéket, nem közvetlenül utána. Az átmenet a következő stílusszámoláskor indul el, tehát a szinkron olvasás még a végértéket adja vissza — abból pedig úgy tűnik, mintha semmilyen tulajdonság nem animálódna.

← Vissza a Műhelyhez