用 HTML5 实现星战的开篇字幕

the-force-awake

去年慕名去电影院看了星战的最新作《原力觉醒》。故事简单,不过里面的场景和人物(非常喜欢汉·索洛,可惜了)特别有趣。光剑的吱吱声,武士的服饰,海岛上的拜师(卢克终于出现了)……和中土世界(You walk a lonely road, Oh! How far you are from home…)不同,星战世界处处展现出了一种神秘的东方哲学。

看完了电影后,我就把星战的整个系列看了一遍。星战,在每部电影的开头都会有一段经典的字幕动画,黄色的文字呈梯形向前方流动,渐渐消失,背景则是漆黑的宇宙星空。简单,但令人印象深刻。

昨天下午在查找资料的时候,无意中看到了一篇CSS3 3D 转换的介绍,胡乱看到了这张图:

css3_3dtransform

等等,这不是星战的字幕吗?于是抱着好玩的心态,写出了这个 H5 动画

准备工作

  • 文本编辑器
  • 支持 H5 的浏览器
  • JQuery
  • 乐事薯片

首先,我们来构建一个跟浏览器窗口大小一样的黑色画布 div.paper

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
    <div class="paper">
    </div>
</body>
</html>

充满整个窗口……

.paper {
    height: 100%;
    width: 100%;
    background-color: black;
}

查看一下效果,整个界面惨白一片……

惨白的界面

AreYouKiddingMe

查看界面元素可以发现,此时 div.paper 的 hight 为 0,并没有像我们写的 height: 100% 那样等于窗口的高度。为什么呢?

我们知道这里的 100% 指的是相对父级元素高度的 100%,div.paper 的父级是 body,而此时 body 的高度也为 0,于是我们加上

body {
    height: 100%;
}

查看一下效果,整个界面依旧惨白一片……

fuuuuuuuu

查看界面元素可以发现,此时 body 的高度依然为 0,再来看上面的 HTML 代码,原来 body 上面还有 html 元素,于是我们加上:

html {
   height: 100%;
}

啧啧,大功造成。然后去除掉 body 的内边距(padding),再来看一下效果。

完美的画布

PERFECT

完美

类容文字元素

我们加上一个 div#content 元素作为文字层。

<body>
    <div class="paper">
        <div id="content">
            <p>A long time ago, in a galaxy far, far away...</p>
            <br><br>
            <p>Episode IV</p>
            <p>A NEW HOPE</p>
            <p>It is a period of civil war. Rebel spaceships, striking from a hidden base, have won their first victory against the evil Galactic Empire.</p>
            <p>During the battle, Rebel spies managed to steal secret plans to the Empire's ultimate weapon,the DEATH STAR,an armored space station with enough power to destroy an entire planet.</p>
            <p>Pursued by the Empire's sinister agents,Princess Leia races home aboard her starship,custodian of the stolen plans that can save her people and restore freedom galaxy...</p>
        </div>
    </div>
</body>

设置字体、字号、颜色和文字居中。

body {
    height: 100%;
    padding: 0;
    margin: 0;
    font-family: "lucida grande", "lucida sans unicode", lucida, helvetica, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
    color: #ffda00;
    font-size: 4em;
    text-align: center;
}

来看看效果。

带白框的文字

噗……怎么上面出现了一个白框啊。

我需要冷静

冷静下来,查看元素,原来上面之所以会出现一个白框,是因为“A long time ago”这一个段落 p 的外边距(margin)穿过了 div.paper,到了 div.paper 的上方, 这种规则称为外边距叠加,由于外边距是透明的,因此它呈现出了父元素 body 的白色。

解决方法很简单。

  1. 设置 div.paper 内边框,使得子元素的外边距(margin)无法穿透。

  2. 设置 body 的背景色。

这里,我使用方法二。

添加滚动条

设置 content 的样式、高度、宽度、居中当然还有滚动条。

#content {
    box-sizing: border-box;
    margin: 0 auto;
    width: 80%;
    height: 100%;
    overflow: scroll;
}

看看效果。

平面初步效果

哎哟,不错哦。

good

CSS3的3D转换

最关键的部分到了,根据 w3school 的这个示例,实现星战那样的 3D 字幕涉及到 perspective 和 rotateX 属性。

照葫芦画瓢, 我们给 bodydiv.paper 添加 3D 变换:

body {
    /*省略*/
    perspective: 500;
    -webkit-perspective: 500;
}
.paper {
    /*省略*/
    transform: rotateX(60deg);
    -webkit-transform: rotateX(60deg);
}

看看效果。

3D变换1

good。

jQuery动画

下面我们来一起加上动画,让字幕从开始滚动到结尾。

虽然 CSS3 有动画的功能,但是我还是选择用 jQuery 来做动画。(懒……)

jQuery 动画是用 animate 函数来完成的。只需要给出动画结束后某属性的值和动画时间(非必需)等参数,即可创建针对该参数的动画,参考w3school 关于 JQuery 动画的介绍

这里涉及到两个属性,scrollTopscrollHeight

scrollTop 可以控制滚动条的滚动高度,scrollHeight 可以得到滚动内容的实际高度。具体可以参考上面的链接,讲的很详细。

知道了 animate 函数和必要时属性后,很快的写下了代码。scrollTop 属性从开始的 0,经过 scrollHeight * 20 毫秒,匀速的变为了 scrollHeight

$(function(){
    var scrollHeight = $("#content")[0].scrollHeight;
    var scrollTop = $("#content")[0].scrollTop;
    $("#content").animate({scrollTop: scrollHeight}, scrollHeight * 20, "linear");
};

最后,隐藏滚动条。

#content {
    /*省略*/
    overflow: hidden;
}

3D变换2

嗯,大功告成。不过还是有些问题,一开始应该是没有文字的。我们可以在 div#content 开头加上一个空白区。

<div class="content">
    <div class="empty-content top"></div>
    <p>A long time ago, in a galaxy far, far away...</p>
    ...
.empty-content {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
}

这样就差不多了。当然我们还可以加图片背景,加背景音乐。这里就不做了……

动画演示 | 源码

Yoda

上篇我的软件清单
下篇新的一年,新的博客