2013年新首页

由于之前跟其他人一起合租的一个虚拟主机空间很快就要到期了,而我的域名 upsuper.org 一直停靠在那上面,没有迁移到自己后来买的 VPS 上,于是今天决定把域名指过去。之前已经花了一番功夫把博客里面的大把文章转移到了这个 GitHub 上面的新博客里,剩下的主要就是首页了。

当年做的首页很久没有维护了,有一些链接甚至应该已经是死链了。而现在感觉能放上去的链接实在太少了,不好保留原来的样式,所以就新做了一个。既然重新做,这自然又是练手的好时机,一面看看自己(自我感觉良好)的设计,一面学习学习那些新的技术。

之前在做 white 这个应用的时候,就研究过 CSS3 里许多有趣的东西,其中不少就被我用在了这次做新首页上。

设计

参考了 Reeoo 网站里面的一些设计之后,脑中大概形成了新首页的设计:中间照旧地放上标志性的 Logo,旁边将链接围成一圈,然后绕着中心旋转;作为平衡,在链接圈外加一圈逆向旋转的虚线;鼠标放到链接上时停止旋转,并且呈现某种与所指链接有关的效果。

以最近所活跃的网站作为链接选择的标准,最后选择了这个博客Twitter 页面GitHub 页面Bangumi 页面和我的 Gmail 地址作为链接。一开始的想法是在鼠标悬停到链接上时将中间的 Logo 换成对应网站的 Logo,但是考察了一圈这几个网站的图片,感觉风格差异太大,放在一起好像很不好看。而且我也不会画画,没法把它们统一风格,于是就作罢了。

因为不怎么会使用那些画图软件,所以干脆就直接用纸笔来画效果图,在脑子里想象成品应该长的样子。当然我在纸上画画的功力也不怎么样,连一个圆都画不圆,也只是勉强能作为参考的水准。

实现

因为想到 CSS3 应该已经相当强力了,所以一开始是想完全使用 CSS3 来实现的,想着图形只要用 transform 变换一下都可以实现,圆形就用 border-radius 画,旋转动画只要用 animation 就可以了,这样除了中心的 Logo 以外,便一张图片都不需要了。当然,这种想法是美好的,可惜现实是残酷的:即使是 CSS3 也远没有到我曾经设想的想实现什么就能实现什么的水平,而且浏览器实现还有各种这样那样的问题……

扇形链接 问题一

第一个遇到的阻碍便是周围绕转的扇形链接,最初的想法如上面说,是希望使用 transform 这个属性的 matrix 函数来做任意变换。我总是想着,都能上矩阵了,应该是没什么做不到的吧。在这上面花了不少时间研究,想计算出一个矩阵。最后突然想到,矩阵变换根本不能做非线性运算,也就是说根本不可能把一个矩形变成扇形,遂放弃这种方法。

虽然放弃用纯 CSS 了,但是不想放弃这个设计,所以就考虑了别的方法。第一个想到的就是 SVG 了,因为 SVG 可以直接内嵌在 HTML 里面,想过去真是方便。但是潜在 HTML 里面的话,又会影响 HTML 的“文档性”,感觉不爽。因此就采用了现在的方法,使用独立的 SVG 图片在 CSS 里面引用其为背景。这种做法也算是一个折中,因为 SVG 也是代码编写的,所以某种意义上也算是没有增加图片的数量吧。

扇形链接 问题二

这个问题虽然用 SVG 在视觉效果上轻松解决了,但是随之也带来了另一个问题:如何让链接覆盖整个扇形区域呢?如果链接是一块区域的话自然比但只有文字部分更方便点击,但是如果使用普通的矩形块来覆盖的话,相邻的扇形就会有链接重叠的部分,点击的时候就可能进入到预期外的页面,无论如何这样都是非常糟糕的。这个时候又想到了 transform

这个 transform 虽然不能把矩形变成扇形,但变成梯形总是可以的吧?因为视觉形状已经由 SVG 图片代劳了,实际链接的有效区域只要保证覆盖必要的区域并且不会相互覆盖即可,多覆盖一些是无所谓的~于是变成梯形,让梯形斜边与扇形两边重合,梯形下底与扇形大弧相切,上底连接小弧两端点即可。

查了一番资料,一个坏消息和一个好消息。坏消息是,单纯的 2D 变换连梯形都做不出来,好消息是我们还有 3D 变换。结合了 perspectivetransform 两个属性,调了很久终于调成功了。5个连接的实际范围如右图红色部分所示。因为多出来的部分没有相互重合,所以关系不是很大,总之这样在绝大多数情况下对链接的预期和实际情况是相符的。

扇形链接 更多问题

但是这么做了之后,再次引出一个新的问题 (orz 就这个东西问题真多):因为链接被变形了,链接里面的文字也扭曲得没法看了。本来试图用 CSS 变换回来,可试来试去效果都不好,最后决定用 JavaScript 将文字提取出来放到链接外面,单独对其设置样式。这样就既保证了 HTML 的文档性,又方便了实现。

在测试 Chrome 下的情况的时候,出现了一个新的问题是在扇形区域的一些部分,链接是无法点击的。经过研究发现是链接的形状仍为矩形的父元素遮蔽了一部分其他链接的区域。这个解决起来就轻车熟路了,直接将父元素的 pointer-events 设置为 none,并将链接的这个属性设置为 auto 就可以了。这种做法带来的唯一的麻烦是你就通不过 W3C 的 CSS 验证了,不过无所谓啦这个。

虚线外框

另一个问题就是外圈反向旋转的虚线,本以为直接使用 borderdashed 做虚线边框,然后 border-radius 把它弄成圆的就可以了。这种方法在 Chrome 上是可行的,但是到了 Firefox 上就行不通了:整个圆竟然变成了实线。我在 Mozilla 的 Bugzilla 上面还找到了这个问题相关的 Bug 两枚:Bug 382721Bug 652650,看起来也是老问题了,至今没有解决呢。最后无奈,虚线边框也使用 SVG 解决了。

旋转与悬浮效果

至于旋转并没有花什么力气倒是顺利解决了,毕竟这个就是 CSS3 的主打功能之一。CSS3 的动画用起来还是很方便的,唯一的问题是 WebKit 内核的浏览器还必须使用 -webkit- 前缀的东西才行。在悬停的时候,使用 animation-play-state: paused 就可以暂停,一行 JavaScript 都不需要。

因为放弃了在中间显示图标的设计,最后决定改变背景色。在鼠标悬浮在某个连接时,使用这个网站的印象色作为页面背景色,并且使用 trasition 来做渐变。为了方便编写,我直接把每个链接对应的色彩写在 dataset 里。这也算是很轻松地实现了,只是选色选了一会儿。直接截取网站的主要印象色太过于鲜亮了,完全不适合作为背景色,最后还是到维基百科的 Web colors 这个条目里挑选了几个淡一些的颜色。

关于兼容性

因为知道这次用了很多很新的东西,所以彻底放弃对 IE 的支持了,甚至于连要求升级的页面都懒得做了。不过即使是 Firefox 和 Chrome 对我所用的这些特性也仍然达不到完美的程度。属性需要前缀这种事情都已经没什么好说的了。

Chrome 里面最让我不满意的一个地方:有问题的 border-radius 实现。说实话这个东西的问题还真是不少,Firefox 下有虚线变实线的问题,Chrome 下也有 Chrome 的问题,这个问题就是 border-radius 的边缘不符合预期。为了限制链接不泄露到圆外,同时使得鼠标不在圆内时不会导致旋转暂停,我在整个圆的容器上加上了 border-radius 把它变成圆形,并且使用 overflow: hidden 防止任何内部元素泄漏到圆外。这种想法想必是很有意义的,不过能不能实现嘛……

如右图,左边的是 Firefox 中经过上面处理后的5个链接的有效区域,右边是 Chrome 的。Firefox 在这里很完美地达成了我们的愿望,可是 Chrome 呢……看过去似乎也很努力地想要去实现了,只可惜看起来跟狗啃的一样,和我们的期待相去甚远……本来还想使用中心的 Logo 来屏蔽泄漏到中间部分的链接区域,也因为同样的原因在 Chrome 下无法使用而作罢了。

总结

总体来说,这真是一篇又臭又长的文章,不过里面用到的一些技巧自认为还蛮有意思的。写出来一方面作为一个记录,另一方面也找点东西填充一下久不更新的博客,毕竟不能每次都开一个新博客然后就没下文了嘛。

把首页搞定之后,接下来也就是好好琢磨一下怎么整一整这个博客的主题了。之前在 GitHub 上看 Pelican 官方收集的主题,觉得能看的都没几个,更别说满意的了,果然技术宅们都不怎么擅长设计呢。相比起来,我大概还算不错的了吧?

参考资料

Comments !

social