专栏首页前端小作坊中文排版二三事

中文排版二三事

中文排版二三事

前段时间一直在折腾中文排版相关的事情,自认为结果还算不错。故开源之,即是Entry.css。这是一个可配置的、更适合阅读的中文文章样式库,可以用来快速搭建中文博客主题或是用于项目文档的样式。在这篇博文中会介绍下在做这个库过程中学到的一些中文排版知识,以及它的特色。

垂直的韵律

Typography大师Robert Bringhurst (The Elements of Typographic Style一书的作者)曾经说:

“Space in typography is like time in music. It is infinitely divisible, but a few proportional intervals can be much more useful than a limitless choice of arbitrary quantities.” 排版中的空间就想音乐中的时间一样。他是无限整除的,但是按比例的间隔比起毫无限制的使用任意大小要有用很多。

在做web开发和设计中经常会用到网格。它即解决了统一性,也避免了我们在排版时纠结那一两个像素的位置摆放。可惜网格只能解决水平方向的排版布局,在垂直方向上一直没有这样的技术,全仰仗设计师大大的美感了。不过最近出现了baselinecss这样的css库,它类似于960 grid,提供了一个css库以及一些psd磨版。它是基于“vertical rhythm”原则设计的库,解决了垂直方向上的排版布局。

Vertical Rhythm可译成垂直的旋律。它的排版思路是垂直方向上各行文字的行高是一个基础数值的n倍,n是正整数。一般情况下,我们会把基础数值设置成基本文字的行高。但是有时这不一定能符合要求。这样的限制可以让文字的布局变的更美观,且易于阅读。特别是对于有很多文字的页面,减少视觉疲劳是很重要的。

上面那个样例采用了14px/28px和21px/28px这两种“字体大小/行高”样式。对于中文来说看起来挺合适。基线之道这篇文章中也提到了另外一种:16px/22px ,28px/33px,40px/44px。可以看到它的基础数值是11px,所以也并不需要拘泥于“基础数值是基本文字的行高”这条。实际上我们需要遵守的规则是:

按照一定比例的间隔,让阅读更加舒适。

这看起来这是一件挺简单的事情,但是实际操作起来还是会有很多问题的。于是涌现了很多相关工具,辅助你开发这样的拥有美妙旋律的网站。例如:

  1. baseliner.js是一个js库帮助你在页面上绘制固定间隔的横线
  2. basehold.it 是一个类似hold.it的服务,可以提供用于绘制横线的css或背景图片
  3. baseline.js是一个js库用于确保外部资源,例如图片的高度是基础数值的n倍。不过这个库还有不少bug

开发时你还会用到些复杂情况:

边距与边框(em与px)

当我们需要设置上下各一像素边框时,就会导致有两像素多余。旋律就会被打破。同样上下padding与margin都会有这个问题。我们可以设置上下padding/margin/border之和为基础数值的正整数倍。

对于基于px单位的情况,这样处理还算比较容易,只是加减法而已。如果你是用em这样的相对单位呢?你的border如果实际上只需要1px,字体大小为14px。那么你需要设置border为1/14em。如果你不想支持旧浏览器,那么你还可以用伪元素after/before来伪装上下border。less代码如下:

.fake-border-top-bottom (@color: #CCC, @width: 1px) {
    position: relative;
    &:before,
    &:after {
        position: absolute;
        z-index: 1;
        content: '';
        width: 100%;
        height: @width;
        background-color: @color;
    }
    &:before {
        top: 0;
        left: 0;
    }
    &:after {
        bottom: 0;
        left: 0;
    }
}

可惜这种方法对img这样没有after/before伪元素的标签不起作用,对于pre、table这样的标签也有些小bug。当然对于固定高度的元素还可以用box-sizing限制死高度。

最后你还会遇到浏览器对于em单位计算不精确导致1像素的偏差。我本来也打算基于em来写entry.css,结果总是遇到chrome浏览器在处理计算时的bug。后来干脆换成了px,当然也损失了对于缩放情况的优化。

外部资源

更多会遭遇的麻烦是外部资源的高度问题。比如你的文章中可以引入图片,恰巧你又不知道高度的确定值,那么很可能图片会打破旋律。对此没有什么特别好的办法,使用js是我能想到的唯一方法。于是基于baseline.js库来设置外部资源的高度,如下:

baseline.init('.entry img, .entry iframe', 28); // 这是standalone版本的baseline.js

其实在我写这篇文章的时候这个库有不少bug,用之前先看下github上别人的pull request。

缩放因子

最后还有个问题,真的仅仅凭借p {line-height: 28px;}一句就可以确保p的行高是28px吗?看这个例子:

p标签中有一个small标签,这时p标签的整体高度是57px,不是行高56px(28px*2)的。这是因为small继承得到行高为28px,然后small与匿名文本一起按照baseline摆放。行高最终是通过一行之上的最高边界与最低边界确定的。而small的文字比匿名文本小,于是计算就可以知道行高就会有可能超过28px。理论上可以计算:(28-14)/2 + 14 + (28-10)/2 = 30,但在safari上实际得到的结果确是29px。对此还没搞明白为什么。后来找到的解决方案是使用“缩放因子”而不是绝对数值,即line-height:2

当然如果有行内元素的行内块高度超过基础数值也会打破旋律。对于这种情况我还没有比较好的解决方案。

样式的优化

Entry.css也考虑到了针对中文阅读做些特殊优化,比如下划线样式。众所周知,下划线有个很严重的问题是:使用某些字体时,下划线会和文字粘在一起。例如中文的“十”字和下划线粘连的时候就会造成“十”和“士”两字难以区分。Entry.css使用了border-bottom来模拟下划线样式。除此之外,对于相邻的两个下划线样式还会设置一些间隔,避免下划线粘连。

如果文字和下划线的颜色一样,人的视觉误差会造成错觉:让人感觉下划线的颜色更深一些。于是Entry.css使用了less css中的lighten方法,降低了下划线的颜色。

对于中文缩近,并没有采用text-indent来实现,因为其默认继承的特性并不是我所期望的。所以采用了如下方法:

.start-with2word () {
    // text-indent: 2em; 避免继承,故不用
    &:before {
        content: '  ';
        display: inline;
    }
}

使用了伪元素before实现了两个中文字的缩近。

Entry.css还提供了“书名号、缩写、着重符、旁注、上下标等等”这样的特殊样式。可以参考下Entry.css的文档

大小与适应性

以前我在写样式的时候觉得一行之上显示的文字应该尽量多,后来发现一行之上的文字太多反而会影响到自己阅读的耐心,让自己的眼睛变的很累。于是我开始思考一行放多少字才算合适。后来我通过纸质书籍找到了一个合适的数值:40。大概统计了身边十本书籍之后,发现一行之上的中文大概都在40字左右。

在写Entry.css之前就已经设计好了它要支持小屏幕,于是在限制宽度的时候都使用了max-width,而不是width。最大宽度设置成了@font-size * 42,在左右各留一个字大小的空间。

对于基础文字大小,我设置成了14px。主要是综合了各种默认字体在各个系统中的样子,觉得14px还算比较均衡的一个数值,再大的话可能会导致在使用特殊字体时变得特别难看。当然你也可以使用typekit、justfont、Typesquare这样的服务,使用在线字体。

自定义

对于这点不做过多说明了。因为Entry.css是基于less写的,所以使用了less提供的变量功能实现了自定义配置功能。Entry.css提供了基础的左、中、右三种布局方式。又因为对于配色这块不太了解,所以移除了最初默认提供的标题背景配色。期待大家可以提供很棒的配色~

最后如果你有什么喜欢的样式,或是觉得需要的功能,更或是发现了bug,请提交issue给我。Feel free to use it~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CSS动画的性能优化

    在Web页面中使用动画效果已经不是什么稀奇的事情了。但凡优秀的UI界面都会有一些点缀用的动画效果。举个例子,Stripe Checkout小组通过UI动画效果来...

    mmzhou
  • ECMAScript 6之WeakMap

    ECMAScript 6中加入了很多新的特性,其中有一个有用的API:WeakMap。Nicholas的博文做了详细的介绍。这也是一篇关于WeakMap的笔记。

    mmzhou
  • CSS硬件加速的好与坏

    每个人都痴迷于60桢每秒的顺滑动画。为了实现这个顺滑体验现在用的最流行的一个做法就是使用『CSS硬件加速』。在一些极端例子中,强制使用translate3d意味...

    mmzhou
  • [WebSocket入门]手把手搭建WebSocket多人在线聊天室(SpringBoot+WebSocket)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    后端技术漫谈
  • [WebSocket入门]手把手搭建WebSocket多人在线聊天室(SpringBoot+WebSocket)

    https://www.callicoder.com/spring-boot-websocket-chat-example/

    Rude3Knife的公众号
  • wordpress后台登录界面美化

    @font-face { font-family:fzz; src: url('https://img.zmki.cn/ttf/fzz.ttf'); } ...

    AlexTao
  • [Markdown]Sublime Text2配置成MarkdownPad2效果

    原文链接:http://blog.csdn.net/humanking7/article/details/43516903

    祥知道
  • WordPress美化-缩略图&整站添加圆角、边框、阴影

    我觉得自己的审美是在一直在变化的,总是感觉还会有更好的效果。那就要不断的更改尝试。

    AlexTao
  • 前端课程——盒子模型

    盒子模型又称为框模型,HTML页面所有的元素都具有盒子模型,该模型用于设计HTML页面和实现HTML页面布局。

    Dreamy.TZK
  • 使用iframe实现在pc端预览移动端页面的效果

    前段时间需要做一个在PC端预览移动端的功能,由于我是前端不太好,就在网上查找资料,花了半天的时间终于有所收获,在这里把我的实现代码分享给大家。想要在PC端实现模...

    AlbertYang

扫码关注云+社区

领取腾讯云代金券