Web技巧(10)

发布于 大漠

自从响应式设计的概念的提出至今也有近10年的时间了,虽然不乏看到响应式设计的身影,但还是有很多同学不太了解什么是响应式设计或响应式设计中常会碰到的问题以及如何解决。特别是流式(自适应)排版和响应式设计难以分清楚,但这两种排版都为我们提供了很多机会来更好的设计Web页面,而且更能完善阅读体验,但与此同时,也带来一些潜在的问题,比如字体大小无法控制,图片等比缩放难处理,甚至还有一些潜在的问题,比如可访问性问题。在这一期中,我们就来聊聊排版中的一些技巧,希望大家能喜欢。

想想排版会遇到的问题

先来想想排版本会遇到哪些问题?不管是哪种布局,排版本都会有一些棘手的问题,只不过流式布局和响应式布局显得多一些,据我个人经验,在排版的时候常会碰到类似下面这样的问题:

  • 字号的使用
  • 图片的缩放

有的时候还会碰到文字断行,文本行间距等细节问题。

或许大家会说,像vwvh这些视窗单位得到支持之后,这些问题都将不再是问题。事实上,自2013年以来,大多数浏览器完全支持它们?那么为什么还看不到流式排版呢?为什么这种Web排版功能还没有得到更广泛的应用呢?我想涉及的问题并不是单一的:

  • 好的响应式设计和开发仍然具有一定的困难,复杂程度较高
  • Web排版在许多设计师或开发人员中并没有得到较高的重视(认为并不重要)
  • 可访问性具有潜在的问题
  • 流式Web排版可能非常棘手

接下来,我们仔细看看这些问题。

响应式设计和开发有困难,较复杂

对于响应式设计在社区中有一个较大的误差,认为能较好的适配容器就是响应式设计,其实这并不是真正的响应式设计。能较好的适配容器(比如社区中常说的Flexible适配方案vw适配方案)仅仅对Web中的各个元素做了一个等比缩放,只是缩放。事实上,响应式设计是能根据不同的容器空间提供最佳的布局,让用户用在有限的空间阅读到最多的内容,而且阅读体验也不会受限于容器空间。

简单地说,在不同的终端上能看不到不一样的设计风格。

如此一来,要设计响应式Web和开发响应式Web,需要投入大量的精力和人力。虽然有一些优秀的工具能帮助我们创建响应式网站,减少对响应式网站建设的成本,但仍然需要付出相当大的精力。在Web设计过程中,挑选工具,测试它们,然后采用它们将花费大量时间。我们还没有真正达到这样的地步 —— 简单地设计一个网站就能自动满足在大多数设备上能运行良好

不管是设计还是开发,仍然使用数字设计工具来设计(绘制设计图)我们的网站,这与由代码构成的最终Web还是具有较大的差距。目前在市面上看到的这些工具几乎不支持基本的吶应式Web设计,基于这样的环境,我们要是讨论流式的排版就更难了。

Web排版并不重要

在Web的设计和开发中,很多人都仍然局限于给网站选好字体,设置好字号就能自然而然得到较高质量的排版。事实上是否如此,我想大家都有体会!

流式排版对可访问性有潜在问题

在实际中,很多设计师和开发人员都不太会考虑可访问性(特别是在我们天朝这样的环境之下),主要原因还是认识问题,觉得可访问性没必要,觉得可访问性投入和收入不成正比。事实上,在国外的社区有很多人都一直在致力于可访问性的建设,为设计和开发Web页面(或Web应用程序)提供很多提高可访问性的建议与规则。而在流式的Web排版中有关于可访问性的问题,并没有人真正的谈论过。

只是有人提到过,流式排版对可访问性是不是存有一定的问题?

流式排版非常棘手

使用视窗单位设置font-size是件棘手的事情。虽然社区中有很多同学在探讨怎么在font-size上运用视窗单位,但在实际生产中使用的还是较少。对于流式排版而言,要的不是技巧,而更需要的是让它变得容易实现和有更好的方法。在以前的博文中或多或少有提到过类似的讨论:

但相比于@Matej Latin在《THE STATE OF FLUID WEB TYPOGRAPHY》一文中的讨论,还是相差甚远。@Matej Latin在这篇教程中提到了多种运用于流式排版的字号设置方案。

接下来,我们来看看这些方案运用于流式排版中效果更好,以及哪种方法可以让流式排版变得不那么复杂,易于控制。当我们这样做的时候,让我们看看在使用这种方法时是否存在任何可访问性问题。

流式排版字号设置的几种方案

@Matej Latin在《THE STATE OF FLUID WEB TYPOGRAPHY》一文提出了四种给流式排版设置font-size的方案:

  • 响应式排版
  • 完全流式排版
  • 不同的媒体查询中提供不同的字号
  • 使用CSS锁定流式排版

响应式排版

探索流式Web排版的起点实际上是响应式Web排版。当今天最常见的Web设计方法(响应式Web设计),通常以移动端布局(Mobile First)为先,会设置一个基本的font-size,并且在该基础上设置其他元素的字号。常见的方式可能像下面这样:

html {
    font-size: 100%; // 通常设置16px
}

h1 {
    font-size: 3rem; // 3 × 16px = 48px
}

上面代码设置的font-size的基础值是浏览器的默认字号(通常为16px),这是创建可访问性网站的一个重要步骤(后面我们可能会聊到)。接下来我们要考虑的是其他设备下重新处理网站的排版(布局),就需要相应的调整font-size。最简单,最常见的方式可以使用媒体查询在不同的断点下处理这些布局和字号。

html {
    font-size: 100%;

    @media (min-width: 768px) {
        font-size: 112.5%;
    }
}

h1 {
    font-size: 3rem;

    @media (min-width: 768px) {
        font-size: 3.5rem;
    }
}

上面的代码使用@media在平板电脑上重新设置了基础字号。平板电脑相对于手机设备屏幕更大,可用空间更大,所以字号设置得更大。

你可以在你的浏览器打开上面的示例,尝试改变浏览器视窗大小,你可以将看到下图这样的效果:

采用这种方案,重点还是在于开发者更过于关注自己的观点,并没把重点放在用户层面上。因为只有断点变化时font-size才会有相应的变化,但很多同学忽略了用户可以通过修改设备的浏览器默认font-size。也就是说,如果用户是PC端访问该网站,18px这样的字号并不会过大,用户也可以很容易地调整它的大小(如果开发者不使用非相对单位(比如px)来覆盖默认字号来取消这个控制)。

这种方式的优点是:

  • 用户仍然控制字号大小,没有可访问性问题
  • 媒体查询可以覆盖不同屏幕宽度

其缺点是:

  • 字号大小是静态的,更改与预定义的断点相关联
  • 在大屏幕上会有很多空白

完全流式排版

从上面的示例来看,响应式排版并不是最理想的。相对而言有一定的效果,但我们能做理更好点 —— 希望我们的字号大小在每个屏幕上都是理想的,而不仅仅是在特定的移动端屏幕、平板电脑和PC端等。

首先可能会想到的是vwvh这样的视窗单位来定义CSS中任何东西的大小。包括font-size。在我看来,视窗单位的引入更多是作为一种扩展特定的、主要是固定宽度的Web布局。正如@Sebastian Eberlein的文章中所描述的

尽管如此,视窗单位长期以来一直被用作一种灵活缩放font-size的方法。@Chris Coyier早在2012年就写过相关的教程,因为我们知道每行中最理想宽宽大约是80个字符,而且“这些单位可以让你感觉完美,然后体验任何大小的屏幕”。

效果完美,但实践并不简单。假设我们这样做:

html {
    font-size: 1.3vw;
}

h1 {
    font-size: 3vw;
}

上面的示例中,基本字号的设置中使用了视窗单位vw。这意味着font-size将随着浏览器屏幕的宽度的变化而调整,而不仅仅是像响应式排版那样预定义断点。但由于屏幕宽度的变化较大,所以font-size变化也较大。

同样的,打开上面的示例,调整浏览器宽度,你将看到的效果会如下:

该方法的优点:

  • 在实践中,如果不将这种方法与响应式排版相结合,该方法并没有任何的好处。从上面示例中你也可以看到,当屏幕足够小的时候,font-size就会过于太小

其缺点是:

  • 使用视窗单位来定义font-size在某些浏览器中是无法访问(在某些浏览器中,用户无法控制font-size
  • 使用视窗单位来定义font-size将会覆盖用户设置的默认字号,这将会直接影响可访问性
  • 另一个无法控制的是,font-size会迅速从一个极端到另一个极端

视窗单位和媒体查询的结合

从前面两个方案来看,完全流式的Web排版方法显然是行不通的。具有讽刺意味的是,让它工作的唯一方法是通过媒体查询来控制font-size的变化,但又和前面所说的响应式Web排版方法不同,这里需要大量的媒体查询条件和视窗单位相结合,从而达到限制font-size的大小。比如:

$breakpoint-1: 25em;
$breakpoint-2: 35em;
...

html {
    font-size: 1.3vw;
}

h1 {
    font-size: 3vw;
}

@media (min-width: $breakpoint-1) {
    html {
        font-size: 2vw;
    }
    
    h1 {
        font-size: 6vw;
    }
}

@media (min-width: $breakpoint-2) {
    ...
}

这个示例是将流式排版和响应式排版结合在一起。如果你在浏览器中打开上面的示例,并尝试调整浏览器视窗的大小。你将看到它比上面完全流式的方法更好(在这个示例中使用了七个断点):

该方案的font-size比响应式Web排版具有更好的伸缩性,但它也带来了其他问题。包括可访问性问题,如果对访问性要求高的话,这可以是一个禁忌呀。

该方法的优点:

  • font-size可以很好的缩放,并适应每个屏幕的宽度

其缺点是:

  • 使用视窗单位定义的font-size在某些浏览器中对可访问性不太友好
  • 因为使用了媒体查询来控制font-size的缩放,所以在调整浏览器视窗大小时仍然会出现闪跳的现象
  • 使用视窗单位的font-size还会覆盖用户的默认字体大小

使用CSS锁定流式排版

可能有人已经注意到,在流式的Web排版方法中最难控制的是font-size。我们也知道通过添加大量的媒体查询来控制其大小并不可取也不是最理想的。所以我们需要找一个更佳的替代方案。@Mike Riethmuller、@Tim Brown和@Geoff Graham都在致力于这方面的研究,而且找到了最终的解决方案,即 使用CSS锁(CSS Locks)定流式排版可能是最佳的方案

这是一个有趣的技术。它设置了最小的font-size和应该使用的屏幕宽度(Minimum Viewport),最大的font-size和应该使用的屏幕(Maximum Viewport),以及两者之间的所有可变font-size。它优雅地解决了font-size在不同屏幕宽度下缩放过快的问题。下面这图可以很好的描述这种技术方案:

font-size的大小不会在左右区域发生变化,它们只会在中间区域缩放。下栅极(Lower Gate)是最小的屏幕大小,我们对它应用固定的font-size,同样的,上栅极(Upper Gate)是最大的屏幕宽度,对应也采用固定的font-size

另外该技术方案好比在运河和河流航行中,船闸是一种在不同水位的水域之间升降船只的装置。

该方式设置font-size可以通过一个计算公式来完成,在CSS中借助calc()函数来实现,将会给这个函数传四个变量:最小字号最大字号最小视窗宽度最大视窗宽度

调整浏览器视窗大小看到的效果如下:

这个效果非常好。如果屏幕宽度介于最小值和最大值之间,font-size可以很好的缩放。如果屏幕小于最小值或大小最大值,则切换到固定的font-size。从理论上讲,这非常有效。但当我尝试着在Chrome上更改浏览器的默认font-size时,它对上面示例的代码没有任何影响。这是一个问题,因为这意味着这种方法仍然忽略用户设置的默认font-size,因此会导致可访问性问题。

该方法优点是:

  • 在调整浏览器视窗的大小时,font-size不会有跳跃的现象
  • font-size大小不能在最小或最大屏幕宽度上进行缩放

缺点是:

  • 使用视窗单位设置font-size会覆盖用户默认设置的font-size,对可访问性有一定的影响

不管采用上面哪种方案,流式排版(或者响应排版)都和font-size有极大的关系,在CSS中设置font-size大小主要是由CSS的单位来控制,所以说,了解CSS中单位相关的知识有助于我们更好的理解这方面的知识。个人建议您花点时间阅读下面几篇文章:

我们看到的大部分是基于font-size的变化,特别是最后一节,使用CSS Locks技巧。即 使用CSS的calc()vwvhfont-size来锁定font-size的变化

该技术还有另一个专业术语:线性插件。 线性插件可能在JavaScript能常听到。

其实这样的原理也可以运用于别的地方。比如@David Bachmann 提到的将该原理运用于其他的CSS属性中

@function between($from, $to, $fromWidth, $toWidth) {
    $slope: ($to - $from) / ($toWidth - $fromWidth);
    $base: $from - $slope * $fromWidth;

    @return calc(#{$base} + #{100vw * $slope});
}

$small: 400px; 
$large: 1000px;

.Container {
    padding: 20px;
    
    @media (min-width: $small) {
        padding: between(20px, 100px, $small, $large);
    }

    
    @media (min-width: $large) {
        padding: 100px;
    }
}

上面的代码演示了如何在容器的padding之间进行切换。从移动端的20px切换到PC端的100px。在这两者之间的任何大小都将得到计算出的padding,即范围在20px ~ 100px之间。为了防止padding超出最大值,我们可以借助媒体查询来将其覆盖。

你可以使用了vw的适配方案,发现在PC端会造成paddingmargin运用了vw的视窗单位元素太大了。那么你就可以考虑这样的线性插值的技术方案来处理。

@Carly Sylvester 使用该技术写了一个线框图的案例,感兴趣的可以查看一下相关源

Rhythm给排版中的运用

上面我们的重点是围绕着font-size的设置,特别是流式排版中怎样设置font-size是最佳的。正如上面所阐述的,实现方案有多种,但不同的方案都有其利弊。在实际使用的时候,应该根据自己的业务场景来决定。

但Web的排版涉及到的知识点以及细节是非常的多。比如在垂直方向,很多时候要处理元素之间的间距,比如paddingmarginline-height等。在排版中有一个专业的术语,即Rhythm。Rhythm是一个较为复杂的课题,这里不会做较详细的阐述,如果您感兴趣的话,可以自己去深入了解这方面的知识。接下来我们只会简单的了解一下该方面的知识。

在排版中,不管是水平方向还是垂直方向都有Rhythm的身影:

在水平方向可以借助CSS的letter-spacingfont-kerningtext-aligntext-indenthanging-punctuationlist-style-positionfont-varialbe等属性来控制。

对于垂直方向的Rhythm相比于水平方向的要更复杂的多,也正因为其复杂,很多开发同学难于掌握该方面的技巧,甚至选择性的忽略。和水平方向有点类似,控制垂直方向的Rhythm涉及到的CSS属性主要会有font-sizeline-heightmargin-top/bottompadding-top/bottomborder-top/bottom以及字体和字体方面的baseline

CSS中的baselinefont-sizeline-height是CSS中(也可以说是Web排版中的重中之重)较难的部分,建议大家花点时间阅读《深入了解CSS字体度量,行高和vertical-align》一文。

如果您对Rhythm方面的知识感兴趣的话,可以阅读下面这些参考资料:

如果你是位拿来主义,那可以考虑线上的Gridlover工具直接帮你计算出来:

这些都有一定的排版批例,比如说下面几篇就是关于黄金比例排版的计算:

越来越觉得,任何一个细节或方案都有深层的理论在支持。

顺便插一句,大家在完成视觉还原时,有文本元素的垂直间距总是难于控制。

有关于这方面的问题,@Ethan Wang提出了 4px基线网格 相关的理论,可以较好的帮助大家解决这个问题:

文本的断行

在Web排版中难免离不开长文本的运行,那么在排版的时候就会碰到长文本撑破容器,从而影响用户阅读的体验。比如下面这种现象:

我们可以像下面这样来解决:

.hyphenate {
    overflow-wrap: break-word;
    word-wrap: break-word;
    hyphens: auto;
}

而CSS中处理断行或处理文本的CSS属性还有word-breakoverflow-wraphyphenslink-breaktext-wrap。这些属性不同的运用会得到不同的效果:

有关于这方面更多的介绍,可以阅读:

其实早在第3期的时候,也提到了断行排版:连字符hyphens的相关知识。

图片纵宽比

Web中图片的运用是常见的场景之一,在固定布局下,图片的使用难度不会太麻烦。但在响应式布局或者说流式布局当中,图片的使用难度相对而言就要更难一些。比如说响应式Web到今天已有近十年了,对于图片的处理一直都没有找到较好的方案。

在Web技巧的第一期,我们就是围绕着响应式图片展开的。在该文中我们提到过图片宽高比的一些处理方案:

事实上平时使用图片时,为了做适配,更多采用的方案是使用background-sizeobject-fit来处理。事实上这样的处理并不是最佳的方案,他们都有同样的一个现象,采用一张图片硬性的将图片填充整个容器。在流式的排版中,我们的容器可能会随时跟着视窗的大小进行变化,那么我们就需要像上面所说的采用宽高比来做相关的处理。

虽然上面文章提到的技术都可以模拟出宽高比的效果,但可以说是一种hack手段。值得庆幸的是,我们可以直接使用一些原生的技术来实现。

首先,img标签会提供一个intrinsicsize

<img intrinsicsize="400x300" style="width: 100%" />

intrinsicsize属性会告诉浏览器用intrinsicsize属性中指定的width/height覆盖img的实际大小。具体的说,这些尺寸和图像上的naturalWidth/naturalHeight的图像栅格将返回此属性中指定的值。

对于video也将以这个大小光栅化,而视频上的videoWidth/videoHeight将返回intrinsicsize属性的值。

所有其他图像大小操作的行为都是相同的。比如:

  • 如果没有设置width/height,则图像尺寸由intrinsicsize指定
  • 如果在图像上设置了width,那么intrinsicsize将设置高度让图片保持正确的长宽比
  • 如果在图像上同时设置了widthheight,那么intrinsicsize属性的值只会影响naturalWidth/naturalHeight的值,而不影响图片的渲染大小

intrinsicsizeimg的属性,属于HTML属性的范畴,除此之外,CSS中还提供了一个原生的属性aspect-ratio可以直接用来设置图片的长宽比:

img {
    aspect-ration: 3 / 2
}

另外还可以借助CSS的attr()函数配合元素的widthheight来处理长宽比:

<img src="image.jpg" width="800" height="600" />

img, video {
    aspect-ratio: attr(width) / attr(height);
}

有关于这方面更多的介绍可以阅读下面相关的文章:

小结

在这一期中,主要围绕着流式排版展开的。主要介绍了如何调整font-size,让流式排版的在阅读上有一个较好的用户体验。当然,不管是哪种排版还有很多细节是值得大家去思考的,比如说文字的相关属性,图片、视频等相关属性的设置,另外就是间距等使用。

上面的内容虽然涉及到了一些排版相关的知识,但不一定完全全面,如果你有这方面的经验,欢迎在下面的评论中与我们一起分享。