写这篇文章的目的是向设计师们介绍一些基本的代码知识,帮助大家从实现的角度理解设计工作。

早在10年前我刚刚入行的那段时间,我们这群人当初叫“网页设计师”,那个时候不仅要画图,还要做一些编码工作。一般程度也要会点HTML+CSS知识,硬核一点的还要会Javascript脚本和使用Bootstrap和JQuery等前端框架。跟代码打了十几年的交道,我感觉有代码的知识打底,对做设计有很大帮助,不仅可以更清晰的搭建视觉语言系统,而且可以对项目落地有十足的把握。在这里,我以WEB端为例,分享几点对设计师帮助最大的代码知识;Native端有很多地方也是相似的,很多知识可以直接平移过去。

阅读之前,有几点需要说明:

  1. 通过阅读本文,你并不能学会写代码!但是你可以建立基本的感性认识和结构逻辑

  2. 文中涉及的代码知识,为便于理解只是列举了基本特性,现实生产中它们基本上都有”截然相反“的高阶用法,没错这就是代码的世界

1. 代码的基本结构

一个比较简单的理解是“内容+外观+脚本”就可以构成静态的网页,内容部分可能是在前台事先写就,也可能是来自服务器动态生成;来自前台的部分也可能是被脚本控制的动态显示的内容。

网页的构成元素主要是下面三类:

  1. HTML – 网页标签,用来呈现内容,如文字、图片、视频等

  2. CSS – 视觉样式表,用来定义内容的外观,如大小、位置、颜色等

  3. Javascript – 脚本语言,可以控制内容和外观,以及实现更多的动态能力

扩展阅读:HTML 简介

2. 容器的妙用

用代码搭建界面的过程,就是从建立框架到细化内部元素,是逐层递进的过程。这个过程与设计过程十分相似。

首先介绍两个概念:块元素和行(háng)元素。一般块元素可以包含行元素,当然也可以包含其他块元素。

块元素和行元素有一些区别:

  1. 块元素默认占100%父级宽度,独自一行;行元素默认内容有多宽就占据多宽,后面其它行元素可以逐次相连

  2. 块元素可以定义大小,行元素无法定义大小

在做设计的时候,也可以先给行元素一个“衬底”,以此撑出的空间作为“容器”,比较类似“块元素”的用法,如下:

这样做有哪些好处?

  1. 父级元素的大小更整齐,便于通过对齐控制布局,简化设计框架

  2. 避免因为调整内容而改变相关元素的定位,充分发挥框架的作用

  3. 增加了内、外边距两个属性,使设计表达与前端实现更一致,代码更简洁高效

一个小问题:为什么说“行元素是没有大小的”?

在设计环境里,每个文字块看起来都有大小的属性,但是代码环境里因为行元素的大小取决于内容,因此无需定义,以文字举例,有字号、行高、字间距、段落间距这些属性后自然就决定了其大小,为了避免“双重定义”,因此放弃了文字块整体的大小的声明。

扩展阅读:CSS的盒模型

3. 元素的定位

布局框架的两个基本要素:位置和大小,这里先讲“位置”。CSS中描述位置的属性是position,它有这几种属性值:

  1. static – 默认属性

  2. relative – 相互关联,当前元素的定位取决于同级在它之前的元素

  3. absolute – 忽视同级元素,相对父级元素“绝对定位”在某个坐标

  4. fixed – 忽视其它元素,相对视窗元素“绝对定位”在某个坐标

定义位置的方式是首先声明position属性,也就是“参照物的模式”,有了参照物以后通过定义偏移量来达到最终精确定位的目的。定义偏移量有两个方式,常见方式是描述自元素相对父级元素的位移,一般是topbottomleftright其中一个或几个属性。另外一个方式是改变盒模型的大小,通过定义父级元素相对子元素的内边距padding,或者子元素自身的外边距margin来实现。两种定位方式有各自适用的场景,有时也混合使用。

我们先来看两个典型的关于模块间距的设计:

 

其中B方法也是依靠在设计时建立虚拟的衬底完成。

那么,在设计过程中应该应用哪种定位方式?

  1. 距离的表达一定涉及两个元素,而内边距的表达是描述自身,从这个角度讲用内边距表达更简洁,更重要的是不会影响到相连元素

  2. 从局部的代码量看,描述距离的方法在短时间内代码量更少,但是随着项目的扩大,抽象程度的不断提升,描述自身的表达一定会更有优势,逻辑也会更清晰

  3. 这点在布局Sketch文件中的Symbol时同样适用

扩展阅读:CSS的定位

4. 元素的大小

这里讲布局框架的第二个要素:大小。CSS中描述大小一般是高度height和宽度width,它有这两种属性值:

  1. Auto – 自动,有多大就多大

  2. 百分比和像素值 – 相对或绝对数值,可能需要进一步考虑内容超出后的问题

衍生标签还有min-heightmax-heightmin-widthmax-width,分别用来描述最小、最大的高度和宽度,需要跟heightwidth组合使用,意为“最小不能小于某个定义的值,或最大不大于某个定义的值”。

如果子元素的内容比较多,超过了max-height定义的高度怎么办?

这时候还有需要定义一个描述“超出之后如何显示”的属性,叫做overflow,大体上它有“隐藏、覆盖显示、局部滚动“这几种方式。

扩展阅读:CSS的尺寸

5. 标注的窍门

在工程制图中,始终强调“误差”的概念,因为误差是无所不在,并且会累积的,因此在设计的过程中也需要考虑误差的因素,并在设计稿标注的过程中合理规避可能的风险。

举个例子,早期的网页浏览器中,对于字号和行高的解析逻辑不一致,导致14px的字行高可能“看起来”有16px,如果直接把容器写14px高度,那字体的底部好像被裁掉了一样。因此留有余地就显得尤为重要了。结合上面谈到的容器的概念,有几点建议:

  1. 在处理文字块的时候,尽量依靠“相对父级元素对齐”的方式,减少具体标注以减少误差

  2. 标注需考虑设备分辨率的不确定性,通常都有一个元素不标注,以表达“自适应宽度”的逻辑

  3. 除非有特殊需求,标注尽量相对父级元素,不要相对同级元素,这样可以保持框架的稳定

6. 正则表达式

正则表达式(常写作Regex)是非常强大的处理字符串的工具,它有以下功能:

  1. 测试字符串内的模式。 例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。

  2. 替换文本。 可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。

  3. 基于模式匹配从字符串中提取子字符串。 可以查找文档内或输入域内特定的文本。

因此,前端表单校验,判断用户输入的“电子邮件地址”是不是符合要求,就是由正则表达式判断完成的。

了解正则表达式对于设计有什么帮助呢?举个例子,当我们在处理优惠券列表的设计时,券名称“10元优惠券”一般是取自一个叫做 “券名称”的接口,开发的同学一般会告诉你:“这意味着他只能用一个标签承载这个字段的输出,换句话说你整行字只能用一个外观,你不能把10这个数字单独拿出来标红加粗”。真的做不到吗?事实上你只要能把你的逻辑描述出来,通过正则表达式就有办法把它过滤出来。在这里就是“整个字符串中的数字部分”,通过正则表达式可以把整个字符串切割成多个字符串,然后单独对数字部分的字符串标签定义外观。

扩展阅读:JavaScript RegExp 对象

7. 触发器和侦听器

先讲几个概念:

  1. 事件 – 一个可以被感知和描述的结果,比如用户点击,比如页面加载完毕

  2. 触发器 – 对标签/节点定义一个事件以及事件发生的处理方式,比如onclick=javascript:alert(‘OK’),定义了如果被点击,就弹窗显示OK

  3. 侦听器大体上与触发器功能相似,一个是主动,另一个是被动,这里不再详述

举个例子:

<input type="text" id="fname" onchange="formComfirm()">

“onchange”意为“如果用户输入变化”,就执行后面的表单验证的程序。

8. 动画绑定和动画队列

关于“触发器”的部分已经介绍过,大部分的事件是用来响应用户的操作,动画当然是其中非常重要的一部分。举例:当我们把用户对按钮的点击绑定另一个组件进行耗时1秒的位移动画,那么常发生的事情是用户在1秒内快速对按钮进行5次点击,接下来会发生什么?可能会是下面几种情况:

  1. 组件用5秒钟时间依次播放动画

  2. 用户每次点击,都打断正在播放的动画,使组件的动画从头播放,所以用户最后一次点击后,组件花了1秒完成动画播放

事实上对于动画队列的描述至少有三种,这里以JQuery为例:

  1. 清空队列,立即播放新触发动画

  2. 除正在播放的动画以外,清空剩余队列,将新触发动画排在其后

  3. 仅将新触发动画排在动画队列的末尾

对于动画队列的设计一般要注意以下几点:

  1. 对于动画队列的控制需要综合考虑用户感受和容错性,很多时候没有完美方案。

  2. 任何由用户触发的动画,都存在短时间重复触发的可能,请注意控制或清空动画队列

  3. 为使动画更平顺,也可以通过锁定事件的响应,使动画播放中不可重复触发动画,达到限制动画队列长度的目的。

9. 为什么是SVG

在诸多图片格式中,SVG有一些独特的优势

  1. 矢量描述,无损,无需处理分辨率适配问题,节省图片资源

  2. 基于XML描述,可以被CSS控制外观,被JS制作动画

由于以上特点,SVG非常适合处理色彩简单的Icon图形,比起IconFont,SVG可以有多个颜色,甚至是局部渐变。

另外,IconFont需要把所有图压缩在一个文件里,还要维护一个字典,从文件个数上看起来是少了,但是想想早期有将多张图合并在一张图片文件里的操作,用以节省文件请求数,非要做的话SVG同样做得到。

感谢阅读!