想法來(lái)源于codepen大神的一個(gè)神作狰晚,一群機(jī)械人以神一樣的步伐在進(jìn)行群魔亂舞,可是堂污,可是家肯,打開(kāi)一看,純js實(shí)現(xiàn)盟猖,js讨衣!也罷换棚,我偏要試一下用SVG+CSS3能不能搞出這個(gè)效果來(lái),o( ̄ヘ ̄o#)反镇。此為前提固蚤。
1.基礎(chǔ)圖形與基礎(chǔ)動(dòng)畫(huà)
先來(lái)個(gè)簡(jiǎn)易版的機(jī)械人吧,因?yàn)橹攸c(diǎn)是動(dòng)效歹茶,所以就簡(jiǎn)易到不能再簡(jiǎn)易夕玩,全部膠囊樣式的圓角矩形來(lái)搞,但為了方便以后替換個(gè)胳膊腿什么的惊豺,我還是乖乖的把每個(gè)準(zhǔn)備運(yùn)動(dòng)起來(lái)的零件都拆分到了不同的圖層燎孟,并且給關(guān)節(jié)部位打了一個(gè)螺絲釘。好吧好吧尸昧,簡(jiǎn)易螺絲釘揩页,打了個(gè)黑點(diǎn)行了吧,在AI里繪制完成后烹俗,這貨是下面這樣滴爆侣。(為了方便疊加,我給加了透明度幢妄,后來(lái)發(fā)現(xiàn)有透明度居然自帶設(shè)計(jì)感兔仰,那就這樣吧)
雖然沒(méi)有科技感,且遍布全身的詭異黑點(diǎn)導(dǎo)致它看上去像是十八銅人或者中醫(yī)針灸啊穴位啊的什么東西蕉鸳,但是這不妨礙我們的機(jī)械人運(yùn)動(dòng)乎赴,來(lái)吧,給大家打個(gè)招呼置吓,動(dòng)動(dòng)頭先无虚,走起來(lái)。
CSS部分略通一二的小伙伴都知道衍锚,再簡(jiǎn)單不過(guò)友题,transform:rotate
屬性,這里唯一要注意的是在定義animation時(shí)戴质,一定要定義transform-origin度宦,旋轉(zhuǎn)的原點(diǎn),這里就是我在關(guān)節(jié)處打了一堆黑點(diǎn)的意義了告匠。因?yàn)槲褹I導(dǎo)出的SVG中戈抄,每個(gè)關(guān)節(jié),也就是<circle>
的圓心cx
與cy
的值后专,就是各個(gè)部位旋轉(zhuǎn)的原點(diǎn)划鸽。
很好,很聽(tīng)話。既然動(dòng)起來(lái)有了生命裸诽,管它硅基還是碳基嫂用,給“他”起個(gè)帥氣的名字,叫起來(lái)也方便丈冬。大白(●—●)不能叫嘱函,那就叫小冰吧」∪铮“Hi~往弓,我是小冰”
小冰,現(xiàn)在命令你動(dòng)一下左腿蓄氧,擺幅大一些函似。
好的,接下來(lái)喉童,其他部位一并動(dòng)起來(lái)缴淋。
好了檢測(cè)完畢,一切正常泄朴。等等,似乎哪里不太對(duì)露氮,聰明如你一定發(fā)現(xiàn)了詭異之處祖灰,那就是——?jiǎng)有Ю锒际侵w的末節(jié)在動(dòng),小腿動(dòng)大腿不動(dòng)畔规,胳膊動(dòng)胳膊肘不動(dòng)局扶,咳咳,是的叁扫,這是一個(gè)被釘住只能掙扎的機(jī)械人三妈。釘住小冰的就是那一堆“螺絲”。為什么這么搞呢莫绣?理由很簡(jiǎn)單畴蒲,我讓大腿動(dòng)一下,看看發(fā)生了什么
這是对室?各甩各的模燥,誰(shuí)都不理誰(shuí)?拜托掩宜,你們可是一個(gè)整體哎∧杪睿現(xiàn)在的問(wèn)題來(lái)了,我們CSS動(dòng)畫(huà)屬性定義的時(shí)候牺汤,每個(gè)可活動(dòng)的形狀的旋轉(zhuǎn)原點(diǎn)都是給了固定值辽旋,那既然如此,怎么才能讓末肢的原點(diǎn)隨著上肢的擺動(dòng)而動(dòng)起來(lái)呢?
2.SIML路徑動(dòng)畫(huà)解決方案
凡事皆要慢慢來(lái)补胚,先進(jìn)行第一步拆解码耐,只讓上半部分肢節(jié)動(dòng)起來(lái)。
為了方便查看(現(xiàn)在眼花繚亂的不能直視)糖儡,小冰聽(tīng)令伐坏,先暫停擺動(dòng),右大腿帶著右小腿動(dòng)一個(gè)握联。(大腿和小腿用相同的旋轉(zhuǎn)動(dòng)畫(huà)定義桦沉,包括原點(diǎn),統(tǒng)一定義為大腿旋轉(zhuǎn)的原點(diǎn))
有沒(méi)有毛步鹈觥纯露?有!不符合物理規(guī)律的樣子代芜。我們先用圖來(lái)分析一下埠褪,然后來(lái)對(duì)癥下藥。
大腿從位置A甩到位置B挤庇,我希望得到小腿的效果是始終保持下垂钞速。相當(dāng)于小腿部分沒(méi)有擺幅度的運(yùn)動(dòng),也就是沿著圖中的虛線軌跡運(yùn)動(dòng)嫡秕。等等渴语,想起來(lái)了點(diǎn)什么沒(méi)?軌跡昆咽?我們?cè)诼窂絼?dòng)畫(huà)中提到過(guò)是可用控制擺動(dòng)的驾凶,
<animateMotion rotate="auto">
這是定義隨著路徑擺動(dòng),不定義的話默認(rèn)不擺動(dòng)掷酗,那既然圓形也可以是路徑调违,我們這里用路徑動(dòng)畫(huà)實(shí)現(xiàn)一下看看如何。關(guān)于路徑動(dòng)畫(huà)的詳解我以前寫(xiě)過(guò)詳解了泻轰,這里只看效果:
似乎解決了問(wèn)題的樣子技肩。但是,新的問(wèn)題已然出現(xiàn)糕殉,就是我要甩大腿的過(guò)程中小腿自然擺動(dòng)亩鬼,怎么搞?
3.拆解SVG阿蝶,利用獨(dú)立坐標(biāo)系解決方案
去他的路徑動(dòng)畫(huà)雳锋,正解在這里,因?yàn)橐粋€(gè)SVG是一個(gè)坐標(biāo)系羡洁,也就是說(shuō)我們定義旋轉(zhuǎn)原點(diǎn)的時(shí)候都要遵循同一個(gè)規(guī)則玷过,在立方體旋轉(zhuǎn)動(dòng)畫(huà)里,我們?cè)?jīng)搞過(guò),六個(gè)面辛蚊,六個(gè)SVG粤蝎,里面各自動(dòng)畫(huà)進(jìn)行,互不干擾袋马,這個(gè)思路放到我們這個(gè)動(dòng)畫(huà)中初澎,依舊可行。
簡(jiǎn)單來(lái)說(shuō)虑凛,我把需要擺動(dòng)的四個(gè)末肢放到四個(gè)SVG里碑宴,還是拿右腿為例∩5看圖延柠,看圖。小腿所在的獨(dú)立的SVG先與大腿保持相同的旋轉(zhuǎn)運(yùn)動(dòng)锣披,當(dāng)然贞间,用的也是大腿的旋轉(zhuǎn)原點(diǎn)O2,里面組成小腿的形狀按自己坐標(biāo)系的旋轉(zhuǎn)原點(diǎn)O1運(yùn)動(dòng)雹仿,因?yàn)镾VG運(yùn)動(dòng)的過(guò)程中增热,坐標(biāo)系也在運(yùn)動(dòng),所以雖然相對(duì)于原始坐標(biāo)系小腿的運(yùn)動(dòng)的原點(diǎn)一直在變化胧辽,但在它自己的坐標(biāo)系里钓葫,卻始終不變。有點(diǎn)拗口票顾,但理解了動(dòng)畫(huà)思路也就打通了。
貼上部分代碼順便解釋一下
首先帆调,最重要的是奠骄,放到html中,首先要把SVG的位置屬性定義成絕對(duì)番刊,這里不賣(mài)弄了含鳞,小伙伴都懂得,因?yàn)槲覀兊腟VG是互相重疊的芹务,所以
SVG{position:absolute}
運(yùn)動(dòng)的CSS代碼如下(只放了右腿的):
@keyframes rightLeg{ /*定義右腿大腿的擺動(dòng)(旋轉(zhuǎn)動(dòng)畫(huà))*/
0%{transform:rotate(0deg); }
100%{transform:rotate(-90deg); }
}
.rightLeg{
animation:rightLeg 1s ease alternate infinite;
transform-origin: /*旋轉(zhuǎn)原點(diǎn)O1*/
}
@keyframes rightLeg2{ /*定義右腿小腿的擺動(dòng)(旋轉(zhuǎn)動(dòng)畫(huà))*/
0%{transform:rotate(-50deg); }
100%{transform:rotate(50deg); }
}
.rightLeg path{
animation:rightLeg2 0.4s ease alternate infinite ;
transform-origin: /*旋轉(zhuǎn)原點(diǎn)O2*/
}
DOM部分蝉绷,大腿、胳膊肘兒枣抱、頭熔吗、身體是同一個(gè)SVG,組成小腿部分是單獨(dú)的SVG
<svg class="rightLeg">
<path d=""/> <!--這里可能是path佳晶,也可能是rect桅狠,總之AI導(dǎo)出什么就是什么啦。-->
</svg>
好了,小冰中跌,聽(tīng)口令咨堤,現(xiàn)在讓大家看一下正常的機(jī)械腿。
perfect!現(xiàn)在小腿和大腿可以無(wú)縫連接在一起漩符,想怎么動(dòng)就怎么動(dòng)一喘,運(yùn)動(dòng)速度啊,擺動(dòng)幅度啊嗜暴,任意定義凸克。
剩下的又是體力活了,現(xiàn)在把其余的部分按照上面的思路拆解就可以咯灼伤。我隨隨便便定義了一下(說(shuō)是隨便触徐,但每個(gè)都要定義一堆,也是頭昏腦漲昂摹)撞鹉,然后就得到了下面這段動(dòng)畫(huà)。
機(jī)械舞颖侄,夠不夠魔性鸟雏。
當(dāng)然了,如果你有足夠的創(chuàng)意的話览祖,可以隨便玩兒嘛孝鹊,反正小冰非我族類(lèi),怎么運(yùn)動(dòng)都可以展蒂。比如齊刷刷的左右擺動(dòng)(左臂右臂定義成相同的動(dòng)畫(huà)又活,左腿和右腿定義成相同的動(dòng)畫(huà))
總之,怎么定義都行锰悼,一切隨意柳骄。
還記不記得我們的跳幀動(dòng)畫(huà),見(jiàn)這篇文章https://juejin.im/post/597694e75188250d4d352cf9
里面做了一些效果箕般,比如“咔噠咔噠”的時(shí)鐘耐薯,我們的小冰也可以“咔吧咔吧”的動(dòng)起來(lái)。在定義動(dòng)畫(huà)animation時(shí)丝里,去掉ease啊曲初,linear啊,或者cubic-brazier這些定義速率的值杯聚,換成steps()
臼婆,就會(huì)得到缺少潤(rùn)滑油的小冰,關(guān)于steps(n)
里n值的定義幌绍,可以不要太過(guò)隨意目锭,根據(jù)旋轉(zhuǎn)動(dòng)畫(huà)的時(shí)間评汰,使咔吧的頻率保持一致,會(huì)更嚴(yán)謹(jǐn)一些痢虹。我做了效果可以看一下:
再比如我們來(lái)個(gè)炫酷的組裝過(guò)程被去。(動(dòng)畫(huà)第一部分為零件組裝,也就是以transform:translate位移動(dòng)畫(huà)為主)
就這樣吧奖唯,拆得再散實(shí)在招架不住了惨缆。
如果你覺(jué)得身體部分一動(dòng)不動(dòng),太過(guò)死板的話丰捷,no problem坯墨,先理清楚思路,首先病往,所有的零件一起移動(dòng)捣染,同時(shí),大腿在自己的坐標(biāo)系做旋轉(zhuǎn)運(yùn)動(dòng)停巷,小腿在自己的坐標(biāo)系做旋轉(zhuǎn)運(yùn)動(dòng)耍攘。這樣的話,要對(duì)原DOM結(jié)構(gòu)再加入一個(gè)容器<div>
畔勤。把所有的SVG放到這個(gè)<div>
中蕾各。
CSS部分原來(lái)的不變,增加一個(gè)身體移動(dòng)部分的定義如下:
@keyframes base{
0%{transform:translateX(-100px); }
100%{transform:translateX(100px); }
}
.base{
animation:base 1s ease alternate infinite;
}
或者再增加點(diǎn)擺動(dòng)庆揪,就得到了下面這個(gè)效果:
在基礎(chǔ)的動(dòng)效基礎(chǔ)上式曲,可以對(duì)機(jī)械人小冰進(jìn)行各種美化,去替換SVG的組成部分就可以缸榛,比如下面這種:
記得重新定義旋轉(zhuǎn)原點(diǎn)A咝摺!
關(guān)于動(dòng)效聯(lián)動(dòng)重點(diǎn)是相對(duì)坐標(biāo)系的使用内颗,也就是說(shuō)脆贵,如果一個(gè)元素需要“自動(dòng)”和“公動(dòng)”(源自自轉(zhuǎn)和公轉(zhuǎn),自己造詞)方法就是放到單獨(dú)的SVG中起暮,每個(gè)SVG擁有自己獨(dú)立的坐標(biāo)系,組成元素的“自動(dòng)”遵循自己的坐標(biāo)系会烙。
這個(gè)方法一旦掌握负懦,再做動(dòng)效時(shí)簡(jiǎn)直為所欲為,做機(jī)械臂很簡(jiǎn)單吧柏腻?做摩天輪很簡(jiǎn)單吧纸厉?感興趣的小伙伴可以自行嘗試。
另外五嫂,另外颗品,其實(shí)我知道最好的方法是用js肯尺,比如我們這種動(dòng)畫(huà),可以js去獲取關(guān)節(jié)部分的坐標(biāo)值躯枢,再賦值給旋轉(zhuǎn)原點(diǎn)则吟,可是,這不是不會(huì)嘛~~手動(dòng)(* ̄︶ ̄)