响应式排版是一个棘手的问题。下面这段代码是我一开始写响应式网站时所能想出来的最好的方法:
p { font-size: 16px; } @media (min-width: 800px) { p { font-size: 18px; } } /* Repeat for h1 - h6 and other type groups */
在那之后,我学习了更多的有关排版的问题,而且收集了一些非常棒的例子,比如使用相对单位,vertical rhythms和恰当的文本缩放排版。
这些新的例子都是非常棒的,它们让我的网站更加美观,更加赏心悦目。但是,实现这些功能的过程却是非常糟糕的。
我必须去写很复杂的代码,而且我发现在巨大的时间压力下,我挣扎于编写响应式网站中。
在几个月的辛苦工作之后,现在我终于找到了一个可以和各位分享的一个解决方法——Typi。
Typi是非常棒的,因为在三个简单的步骤之后,它不仅允许我去使用我曾经学过的例子,同时它还解决了大部分我所遇到的问题。现在,就让我通过我研究响应式排版时用过的例子,来向你具体解释一下这三个步骤。
移动端浏览网页和在PC端浏览网页是完全不同的体验。当你在一部屏幕比较小的移动端上浏览网页时,毫无疑问你会将设备靠近你自己。
和移动端相比,你的PC的屏幕会离你更远。因此,相同大小的字因为更远的距离的缘故在PC上显得略微小一点。
为了增加可读性,弥补由距离带来的字的大小上的视觉损失,我们增加了字体的大小。
我第一次接触这个例子是通过 ia.net 上的一篇文章———— Responsive Typography: The Basics 。如果你对我说的不是很了解,我强烈建议你去看看这篇文章。
下面贴出的代码是用Sass对这个例子的实现:
html { font-size: 16px; @media (min-width: 800px) { font-size: 18px; } @media (min-width: 1200px) { font-size: 20px; } }
注:当我们增加字体的大小时,我们也可能需要去增加行高以满足每行文字间的空白。用Sass我们可以这么写:
html { font-size: 16px; line-height: 1.3; @media (min-width: 800px) { font-size: 18px; } @media (min-width: 1200px) { font-size: 20px; line-height: 1.4; } }
为你的排版元素选择字体大小是很难的(从 <h1>
到 <h6>
),尤其是如果你想让它们更加的美观。一个模块化的文本缩放,或者说文本缩放排版是一个很好的工具,你可以用它来帮助你选择能够和空白部分完美契合的排版字体。
它们是一序列通过比例关联在一起的数字。它可以是你的文本字体大小乘上或除以一个比例来得到的。得到的数字之后再次乘上或者除以那个比例。
一个上图中模块化文本缩放的代码可以如下:
html { font-size: 16px } h1 { font-size: 50px } h2 { font-size: 37px } h3 { font-size: 28px } // ...
当然,事情没有这么简单。如果你记得之前我们讨论到的第一个例子,你可能会意识到正文的字体大小应该随着你的屏幕大小改变而改变。
当你必须为了保证缩放的一致性,从而去改变每个断点处你的所有元素的排版大小时,这个问题就会发生了,看下面的代码:
html { font-size: 16px; line-height: 1.3; @media (min-width: 800px) { font-size: 18px; } @media (min-width: 1200px) { font-size: 20px; line-height: 1.4; } } h1 { font-size: 50px; @media (min-width: 800px) { font-size: 56px; } @media (min-width: 1200px) { font-size: 63px; } } h2 { font-size: 37px; @media (min-width: 800px) { font-size: 42px; } @media (min-width: 1200px) { font-size: 47px; } } h2 { font-size: 28px; @media (min-width: 800px) { font-size: 32px; } @media (min-width: 1200px) { font-size: 35px; } } // ...
想知道这个问题的答案的话可以看下一个例子。
注:如果你需要为你的模块化缩放选择开始的字体大小和缩放比例,我建议你读Tim Brown的一篇文章———— More Meaningful Typography 。
在CSS中的相对单位有百分号( %
),视窗单位( vh
, vm
, vmin
, vmax
), em
单位( em
)和 rem
单位( rem
)。最常用的排版单位是 em
和 rem
。
你可以同时在同一个行为中用 em
和 rem
来解决我们在第二个例子中遇到的问题。为了将像素 px
转换成 em
,我们将 font-size
的值除以浏览器默认的基本字体大小(base-font size)。
看下面贴出来的代码:
html { font-size: 16px; @media (min-width: 800px) { font-size: 18px; } @media (min-width: 1200px) { font-size: 20px; } } h1 { font-size: 3.125em; } // 50 ÷ 16 = 3.125 h2 { font-size: 2.3125em;} // 37 ÷ 16 = 2.3125 h3 { font-size: 1.75em; } // 28 ÷ 16 = 1.75 // ... // Note: These are approximate values. // The actual values derived from modularscale.com are 3.129em, 2.3353em and 1.769em respectively.
现在就好很多了!
这儿有一些问题需要我们注意。当屏幕宽度增加到 1200px
时, <h1>
的值变成大约 63px
。
63px
太大了。阅读标签 <h1>
内的文本已经不是很舒服了。一个更好的决定是将它的值调到 47px
(也就是 <h2>
的大小)。
当这个情况发生的时候,你可能会想去降低标签 <h2>
的大小,因为标签 <h1>
可以很好的强调。有时候,你也可能需要去改变 line-height
的值。
所以代码现在就变成了这样:
html { font-size: 16px; @media (min-width: 800px) { font-size: 18px; } @media (min-width: 1200px) { font-size: 20px; } } h1 { font-size: 3.129em; line-height: 1.2; @media (min-width: 1200px) { font-size: 2.3353em; line-height: 1.3; } } h2 { font-size: 2.3353em; @media (min-width: 1200px) { font-size: 1.769em; } } h3 { font-size: 1.769em; @media (min-width: 1200px) { font-size: 1.33em; } } // ...
额。。。现在我们回到出发点 :(
是时候来聊一聊Typi了,让我们先不管这些例子来看看Typi是怎么帮助你的吧。
Typi是一个Sass库,它可以允许你建立在分开的Sass map上所有排版元素的 font-size
和 line-height
属性。这些map可以被用来输出我们下面解决方案中的代码。下面让我说说它是怎么工作的。
首先,你需要建立一个 $typi
map,如下:
$typi: ( null: 16px, small: 18px, large: 20px );
null
, small
和 large
是断点。
Typi自动的寻找一个 $breakpoints
图来建立你的媒体查询(意思就是将作者写的一个库 mappy-breakpoints 完美的整合在一起。)
$breakpoints: ( small: 800px, large: 1200px );
一旦 $typi
map被建立,我们在 html
选择器中调用 typi-base()
掺合模式。
html { @include typi-base(); }
这个 typi-base()
掺合模式创建了和我们在例2中给 <html>
标签写的一样的样式。唯一的不同是 font-size
是用百分号表示。
html { font-size: 100%; /* This means 16px */ } @media all and (min-width: 800px) { html { font-size: 112.5%; /* This means 18px */ } } @media all and (min-width: 1200px) { html { font-size: 125%; /* This means 20px */ } }
我们也提到当 font-size
的值改变时有可能需要改变 line-height
的值。你可以提前在Typi上通过给每个需要它的断点上提供一个第二 line-height
值来改变 line-height
的值。
$typi: ( null: (16px, 1.3), // Sets line-height to 1.3 small: 18px, large: (20px, 1.4) // Sets line-height to 1.4 );
从我们更新的 $typi
图中我们可以得到CSS如下:
html { font-size: 100%; /* This means 16px */ line-height: 1.3; } @media all and (min-width: 800px) { html { font-size: 112.5%; /* This means 18px */ } } @media all and (min-width: 1200px) { html { font-size: 125%; /* This means 20px */ line-height: 1.4; } }
在创建 $typi
图后,我们可以用同样的格式来创建别的 font-maps
,下面是例子:
$h1-map: ( null: (3.129em, 1.2), large: (2.3353em, 1.3) ); $h2-map: ( null: 2.3353em, large: 1.769em ); $h3-map: ( null: 1.769em, large: 1.333em ); // ...
之后,我们可以通过 typi
掺合模式来调用每一个font-maps
h1 { @include typi($h1-map) } h2 { @include typi($h2-map) } h3 { @include typi($h3-map) } // ...
最后得到的CSS如下:
h1 { font-size: 3.129em; line-height: 1.2; } @media (min-width: 1200px) { h1 { font-size: 2.3353em; line-height: 1.3; } } h2 { font-size: 2.3353em; } @media (min-width: 1200px) { h2 { font-size: 1.769em; } } h3 { font-size: 1.769em; } @media (min-width: 1200px) { h3 { font-size: 1.333em; } }
非常的整齐是吧,你必须先去 下载Typi 来使用它(Sassmeister和Codepen上面还不能支持Typi)。
如果你不想在每个不同的字体map上写准确的 em
值(例如 1.769em
),你可以使用Sass mixin的模块化文本缩放。
如果你想这么做的话,你需要 下载库 并且把它导入到你的Sass文件中,之后你就可以用 ms()
函数来改变字体maps了。
$h1-map: ( null: (ms(4) 1.2), large: (ms(3), 1.3) ); $h2-map: ( null: ms(3), large: ms(2) ); $h3-map: ( null: ms(2), large: ms(1) ); // ...
所以简而言之,Typi通过帮助你在不同断点上写 font-size
和 line-height
属性来让响应式排版更容易。
现在我已经向你介绍了Typi,让我们回到之前的剩下的最后两个例子(一些问题我已经找到了解决方法)。
Vertical Rhythms在我看来是一个来自印刷设计的概念。在印刷设计中,我们需要保证一个页面中的元素的垂直距离与其他页面的一致性。这个想法与应用文本缩放的排版很类似————允许你的页面中的元素很好的浮动。
在实例中,我们经常用到 line-height
属性作为vertical rhythms一致性的基础。让我们把你的页面设置为 line-height = 25px
,你需要做下面的两件事情:
25px
的倍数。 line-height
设置为 25px
的倍数。 这是它看起来像CSS的地方(这儿还没有用到上面我们提到的三个实例)
html { font-size: 18px; line-height: 25px; } // Resets margins body, h1, p { margin: 0; } h1 { font-size: 63px; line-height: 75px; margin: 25px 0; } p + p { margin-top: 25px; }
这看起来非常的棒!让我们更进一步:将代码改成相对单位。当进行这一步时,你会遇到 em
和 rem
的冲突。
让我们首先把代码转换成ems为单位,然后再转换成rems。顺便提一句, line-height
的值最好应该是没有单位的 。
html { font-size: 1.125em; line-height: 1.4; // This is 25.2px to be accurate } // Resets margins body, h1, p { margin: 0; } h1 { // font size is 63.147px to be more precise font-size: 3.5082em; // 63.147 ÷ 18 = 3.5082em line-height: 1.1972; // 75.6 ÷ 63.147 = 1.1972 margin: 0.3991em 0; // 25.2 ÷ 63.147 = 0.3991 } p + p { margin-top: 1.4em; }
特别要注意的是我们应该怎么把 <h1>
标签中的 margin
属性转换成ems。
要注意的是我们怎么用 63.147px
作为除数?这必须被解决因为以ems为单位的大小的计算需要依据当前的字体大小。它总会导致混乱并包含很多复杂的数学问题。
现在,这儿出现了一个问题。尽管我们尝试去做到更加的精确,但是浏览器似乎不和我们合作。你需要注意我们的vertical rhythms开始变得古怪。
两个问题导致了这个古怪的现象。
第一,我们没有百分之百的精确我们的数学计算。我们可以更加精确(比如精确到十位小数),但是这会让我们的代码像地狱一样丑陋。
第二,不同的浏览器处理子像素的舍入问题是不同的。这意味着不管我们怎么努力的去尝试,我们都不能获得最好的像素规律。
好了,我不想纠结于子像素的舍入问题,因为我们真的没有什么可以做的。现在,让我们转而看看 rem
是如何解决这个复杂的数学问题的,好吗?
html { font-size: 1.125rem; line-height: 1.4; // This is 25.2px to be accurate } // Resets margins body, h1, p { margin: 0; } h1 { font-size: 3.5082rem; // 63.147 ÷ 18 = 3.5082 line-height: 1.1972; // 75.6 ÷ 63.147 = 1.1972 margin: 1.4rem 0; // 25.2 ÷ 18 = 1.4 } p + p { margin-top: 1.4rem; }
请注意我们是如何用margin属性中的 1.4rem
来替代 1.3991em
的?Rem作为单位来进行vertical rhythms的计算会更佳简单。
这并不是说你必须不假思索的就将单位转换成 rem
单位。Rems和em都是很有用的,他们可以被用作不同的目的。我会在之后的某一天讨论这个话题。现在,让我们回到vertical rhythms。
现在,我们将vertical rhythms转换成相对单位,让我们看一看当我们将它与实例一结合起来的时候它是怎么运行的。( font-sizes
和 line-heights
应该随着屏幕大小的改变而改变)。
我们可以用一个 media-query
来让这个例子尽可能的简单。我们也可以用 rem
单位。
html { font-size: 1.125em; line-height: 1.4; @media (min-width: 1200px) { font-size: 1.25em; // this is 20px // Slight change in line heights at 1200px line-height: 1.45 // this is 29px } } // Resets margins body, h1, p { margin: 0; } h1 { font-size: 3.5082em; line-height: 1.1972; margin: 1.45rem 0; @media (min-width: 1200px) { // font-size is now 70.164px line-height: 1.24; // 29px * 3 ÷ 70.164 = 1.24 margin: 1.45rem 0; } } p + p { margin-top: 1.4em; @media (min-width: 1200px) { margin-top: 1.45em } }
额。。。我们也许必须加 20000
个media queries来改变所有元素的 margin
和 line-height
仅仅因为我们改变了 <html>
中 line-height
的一个值。而且我们还没有讲 padding
属性和 border
属性呢!
所以,在这儿我明白了。在不同的浏览器之间实现完美的响应式vertical rhythms是不可能的。至少以现在的技术是不可能的。
那么,我们可以做那些事情来替代它呢?
line-height
属性。 body
中的 line-height
属性。当 CSS的变量 最终支持所有的主流浏览器后,事情将会变的简单。 当然,这个实例很简单。只需要记住:一个字符大约是 0.5em
。一个文本计量意思是你的文本的宽度必须在 22.5em
和 37.5em
之间。
举个例子,在实际情况中,我主要会担心文本超出了 75
个字符。而如果你的文本没有到 45
个字符大小,那么你可能需要改变你的字体大小了。
article { max-width: 30em; /* Anywhere between 22.5em to 37.5em. Use your discretion */ }
响应式排版很难。虽然现在还是没有完美的解决办法,但是我们可以尽我们最大的努力来解决它。
本文根据 @Zell 的《 Everything I know about Responsive Web Typography 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: http://zellwk.com/blog/responsive-typography/
常用昵称“飞鱼”,目前是武汉大学的学生,专业是软件工程。对HTML5,CSS,JavaScript等前端技术有浓厚的兴趣,希望在这儿能和大家分享自己的兴趣与爱好。