这里的动物是怎么变化的,其原理是什么?这样的效果用到了哪些前端技术?

看到一个神奇的动画效果,使用clip-path来绘制图形,请问这里面的clip-path对应的值是怎么计算的,是通过脚本计算呢?还是通过AI这样的工具绘制而成,另外从一个动物过渡到另一个动物,又是怎么实现的?其中的原理是什么?又用到哪些前端技术?In Pieces - 30 Endangered Species, 30 Pieces.
关注者
32
被浏览
1,491

1 个回答

昨天看到这个,今天有人问所以就研究一下:
Ctrl-U 看到 dom 元素的结构是这样的:
<div class="level-one hidden-startup">
    <div class="level-two">
        <div class="animal-mover">
            <div class="wrap right-to-left">
                <div class="shard-wrap">
                    <div class="shard"></div>
                </div>
                <div class="shard-wrap">
                    <div class="shard"></div>
                </div>
                <div class="shard-wrap">
                    <div class="shard"></div>
                </div>
<!-- 一共 30 个 shard ,略 -->

样式表在 //species-in-pieces.com/c 中,随手摘一点(人肉格式化及注释):
/* preloader 的动画,这个简单很多 */
body.preloader.start-up-seq .level-one .shard-wrap:nth-child(16) .shard{
    -webkit-transition:all 1.84s -.2s cubic-bezier(0.62,.02,.34,1),background-color .4s -.2s;-moz-transition:all 1.84s -.2s cubic-bezier(0.62,.02,.34,1),background-color .4s -.2s;
    transition:all 1.84s -.2s cubic-bezier(0.62,.02,.34,1),background-color .4s -.2s
}
body.preloader.start-up-seq .level-one .shard-wrap:nth-child(17) .shard{
    -webkit-transition:all 1.88s -.15s cubic-bezier(0.62,.02,.34,1),background-color .4s -.15s;-moz-transition:all 1.88s -.15s cubic-bezier(0.62,.02,.34,1),background-color .4s -.15s;
    transition:all 1.88s -.15s cubic-bezier(0.62,.02,.34,1),background-color .4s -.15s
}
各个动物的:
.shard-wrap {
    -webkit-transition:.3s;
    -moz-transition:.3s;
    transition:.3s;
    width:100%;
    height:100%;
    position:absolute;
    z-index:2;
}

.shard-wrap .shard {
    position:absolute;
    width:100%;
    height:100%;
    -webkit-transition:1s cubic-bezier(0.7,.3,0,1);
    -moz-transition:1s cubic-bezier(0.7,.3,0,1);
    transition:1s cubic-bezier(0.7,.3,0,1);
    -webkit-clip-path:polygon(50%50%,50%50%,50%50%);
    background-image:url(../img/transparent.png);
    background-position:center center;
    background-repeat:repeat;
    background-color:#1a1a1d;
}

/* level-one 和 preloader 的 */
.all-animals .level-one .shard-wrap:nth-child(1) .shard,
.preloader.start-up-seq .level-one .shard-wrap:nth-child(1) .shard {
    -webkit-clip-path:polygon(12.762% 61.464%,17.986% 76.893%,21.367% 69.321%);
}

.all-animals .level-one .shard-wrap:nth-child(2) .shard,
.preloader.start-up-seq .level-one .shard-wrap:nth-child(2) .shard {
    -webkit-clip-path:polygon(78.188% 35.179%,83.275% 54.179%,85.792% 43.179%);
}
具体每个动物的,可见微调不少
/* penguin */
#animalchanger.penguin .wrap .shard-wrap:nth-child(26) .shard{
    -webkit-clip-path:polygon(55.45% 44.857%,63.75% 51.143%,57.05% 74.429%);
    background-color:#bfc2c1
}
#animalchanger.penguin .wrap .shard-wrap:nth-child(27) .shard{
    -webkit-clip-path:polygon(59.55% 65.714%,63.05% 53.571%,65.45% 73.429%);
    background-color:#000
}

/* butterfly */
#animalchanger.butterfly .wrap .shard-wrap:nth-child(13) .shard{
    -webkit-clip-path:polygon(48.85% 48.071%,48.25% 52.214%,47.15% 51.643%);
    background-color:#DCB050
}
#animalchanger.butterfly .wrap .shard-wrap:nth-child(14) .shard{
    -webkit-clip-path:polygon(48.25% 46.214%,48.25% 44.786%,50.15% 44.071%);
    background-color:#62564D
}

当然了你会问为啥 -webkit-clip-path 在其他浏览器里面怎么办,其实还有 fallback:
.nowebkitbrowser .shard-wrap:nth-child(1) {
    background-image: url("../img/fallbacks/fallback_crow.png");
}

另外就是所有元素的数量是一致的(30 pieces 当然是 30 个),不存在一个动物多一个动物少的情况,只是元素的位置和颜色等等不一样,所以只有 transition 没有 dom 的新增和删除。
另外还要求所有元素的形状是一致的,比如这里都是三角形,这样便于编写(比如直接替换就可以了,不需要处理这里多一个逗号那里少一个逗号啥的)

要说原理么其实就是 clip-path 加 transition ,不过这个应该不是题主问的重点吧,重点应该是那些数值怎么写出来的吧。

我觉得大概是这样写出来的:
  1. 首先用随便什么工具画图(为了 fallback 的 png 也得画一遍吧),要求是元素数一样,并且每个元素都是三角形。这一步得到了基本的图并且顺便得到了 fallback.png。
  2. 搞清楚他们的位置,根据不同的工具可能方法不一样,大不了开了网格线一个一个数(其实肯定有更方便的方法吧,比如直接上个 SVG 画板啥的……)。这一步得到了每个元素的三个坐标和颜色。
  3. 格式化成 css 语句,用 less 之类的封装个函数应该不复杂吧。我常用的方法是正则表达式替换。
  4. 微调,仔细观察了一下微调不少,这个可能要手动了!
仔细观察以后发现有些动物还有动作,这个是通过 js 加的:
js:
/* 一共是 state-2, state-3, state-4 几个 state,调用的时候 参数是 $('body') */
function animalStates(t) {
    setInterval(function() {
        t.removeClass("state-four"), setTimeout(function() {
            t.addClass("state-two")
        }, 1e3), setTimeout(function() {
            t.removeClass("state-two"), t.addClass("state-three")
        }, 2e3), setTimeout(function() {
            t.removeClass("state-three"), t.addClass("state-four")
        }, 3e3)
    }, 4e3)
}

/* 另外还有一层 2-state-2,调用的时候 参数也是 $('body') */
function animalStatesSecondLevel(t) {
    setInterval(function() {
        setTimeout(function() {
            t.addClass("two-state-two")
        }, 1e3), setTimeout(function() {
            t.removeClass("two-state-two")
        }, 1100), setTimeout(function() {
            t.addClass("two-state-two")
        }, 1400), setTimeout(function() {
            t.removeClass("two-state-two")
        }, 1500)
    }, 3e3)
}
css:
.animal-animations-on.two-state-two #animalchanger.peccary .wrap .shard-wrap:nth-child(1) .shard {
    -webkit-clip-path:polygon(15.95% 78.214%,14.95% 79.929%,22.25% 79.929%);
}

.animal-animations-on.two-state-two #animalchanger.peccary .wrap .shard-wrap:nth-child(2) .shard {
    -webkit-clip-path:polygon(17.85% 58.786%,22.05% 58.5%,16.05% 78.214%);
}

.animal-animations-on.two-state-two #animalchanger.peccary .wrap .shard-wrap:nth-child(3) .shard {
    -webkit-clip-path:polygon(15.95% 78.214%,21.95% 58.214%,22% 79.929%);
}
这里估计大部分要手写了……因为每个都不一样啊

效率的话只要能开起来 GPU 加速应该都没问题(而且全是三角形啊),虽然选择器是有点慢不过实际效果还是流畅的(iPhone 5s,iOS 8.2)。

这个项目你说 Google 没给钱我也不信。