在本篇开始之前,我们稍作回顾。目前已经完成的两个系列包括:「iOS 13 设计新特性」,涉及深色模式、SF Symbols、卡片面板及情境菜单等话题,错过的朋友不妨回看,毕竟新系统将会在近两日正式推送。在「基础设计原理」当中,演讲人通过一场夏威夷之旅带领我们了解了一系列重要的设计原理,包括一致性、可供性、心智模型、渐进呈现等等,深入浅出,老少咸宜,强烈推荐。
△ Mike Stern 老师的「基础设计原理」
而本期开始的新话题则聚焦于如何面向 Apple 生态体系中的多种设备进行设计,包括如何选择平台,如何针对不同的平台权衡功能与外观风格,如何构建生态体验等等;演讲者是 Apple 的设计师 Cas Lemmens。
在 Apple,我们非常自豪于我们所创造的一系列设备平台。在创造和升级这些平台的过程中,我们都会以提升人们的日常生活品质为目标,并力图在人与设备之间构建富有意义的关联。这关联未必仅存在于单一平台当中;你所使用的 Apple 设备越多,便越发能体会到整个生态带来的依存关系。
你可能会戴着 Apple Watch 晨跑,可能会在 MacBook 或是 iMac 上完成一天的工作;下班后,你可能会借助 iPhone 的一系列功能来使用公共交通,或是在你的车里使用 CarPlay;回到家,你可能会通过 Apple TV 看剧或电影;睡前,你可能还会在 iPad 上读书。
无论你正在使用何种设备,Apple 的平台生态都可以识别你、理解你,并帮助到你。
面向这样的生态体系进行设计,你必须对其中的每一个平台都有着深刻的理解。对于 Apple 的设计师而言,这样的挑战已经变得司空见惯。我们必须谨慎思考每一个 app 可能适合的平台类型,以及如何使其针对不同的平台进行相应的调整。
Apple 开发的 app 当中,有些是面向全平台的,例如「照片」或「音乐」。
而有些则仅存在于特定的平台当中,例如「备忘录」、「邮件」等等。
有些服务可以在你拥有多种设备的情况下带来最优体验,例如 ApplePay;另外一些则必须基于多台设备同时运行,例如 FaceTime。
今天,我要与各位分享的,便是 Apple 的设计师在进行跨平台设计时所采用的典型流程。希望这些经验可以帮助各位更加且目标明确地将你的产品和服务推向 Apple 生态圈当中的更多平台。
我们首先会从「平台选择」开始,即了解每一个平台的情境特质与能力特征,并以此为基础选择最恰当的目标平台。
然后是「平台适配」,即基于目标平台的设备特性,对我们希望实现的功能进行权衡与管理。
接下来是「风格协调」,即在品牌风格与平台规范之间寻求平衡,对 app 的视觉外观及操作体验进行定义。
然后是「平台连接」,即探索如何在不同的设备平台之间实现功能的连续性,打造轻松、无缝的使用体验。
最后,我们还会尝试「平台扩展」,即探索如何同时基于多平台实现最优的综合生态体验。
以上便是跨平台设计的主要流程。接下来,我们将对这五个步骤逐一进行了解。
所谓「平台选择」,即回答「我要面向哪个平台进行设计」这个问题。
或许你还没有上线过任何 app,目前正在考虑以哪个平台作为首发;或许你已经在一两个平台上发布过 app,正在考虑接下来应该进行怎样的扩展。
在选择平台时,有两个最为关键的概念需要我们重点思考:
对于「情境」的理解至关重要,因为当情境发生变化时,人们通常会切换他们所使用的设备,以不同的方式完成不同的任务。
举个例子。譬如你正在办公室里工作,或是在学校上着课;这些都是高度聚焦和稳定的情境。当你离开这些场所,乘上了公交车或地铁,你便进入了高度动态和移动化的情境。这两类情境之间的差异非常明显,我们通常会从 Mac 切换至 iPhone 或 Watch,因为后两者本就是面向移动化情境进行设计的。
而对于「能力」的理解则可以帮助你掌握并充分利用特定平台的独特功能。
接下来,让我们从「情境」与「能力」这两个方面,对 Apple 生态体系当中的一些典型平台进行分析。
首先是 iPhone,因为这可能是我们多数人最为熟悉的平台了。
从情境的角度来看,iPhone 始终保持开机,始终与我们相随,因此它是高度移动化的;同时,iPhone 也是高度私人化的设备,我们不会轻易与他人共享使用;此外,iPhone 通常被用于高频而短时的互动,我们每次使用不会超过几分钟。
iPhone 所具有的能力可以有效地支持其情境特质。「始终开机,常伴于身」的特性要求 iPhone 必须具备良好的环境感知能力,其内置的陀螺仪、加速计等传感器可以始终在背景进程当中处理环境相关的信息,即便是在我们没有使用 iPhone 的时候;iPhone 的 Touch ID(及 Face ID 等机制)则会为我们提供私人化的保护;其高清晰度的触屏则能确保我们在短时间的互动过程中获得轻松与愉悦的体验。
与 iPhone 类似,Watch 也具备「始终开机,常伴于身」的特性,且同样是高度私人化的。但 Watch 具有更强的即刻性,所面向的是更为短暂的互动,譬如你只需一瞥便可以从表盘上获取与当下情境最为相关的信息;而提示信息在你注视稍久时还会进一步提供详细信息。
Watch 所具备的能力与其私人化的情境特质息息相关。Watch 可以追踪你的运动状态、地理位置及心率;其触觉反馈可以通过轻触手腕来提醒你查看信息;而表盘也是高度定制化的,你可以让最为需要的信息始终呈现在表盘之上,便于一瞥之间快速获取。
而 iPad 则具有较为复杂的情境特质,既可以被用于稳定的环境,同时也支持移动化场景。你可以用 iPad 完成一些而聚焦的任务,也可以将其作为放松型设备来享受影视或游戏体验。而所有这些互动过程都比 iPhone 或 Watch 更加持久。
从能力的角度,iPad 的大屏正是对这些情境特质的有效支持。充足的屏幕尺寸可以帮助你完成高精度的操作,环境光传感器可以使其良好适应于日夜不同的光照条件;高保真扬声器和高精度触屏可以为影音或游戏带来更具沉浸感的视听体验;若是配合 Apple Pencil,iPad 还能帮助你完成更加、更具创意性的工作。
再来看 Mac。其情境特质具有高度的专业性,你可以进行非常而聚焦的工作,譬如设计和开发 app;MacBook 可以被作为共享设备来使用,但它同时也是个人化的,因为多数使用者都拥有独立的个人帐户;我们通常会长时间使用 MacBook 或 iMac,譬如每天都会有几个小时的互动时间。
在能力方面,为了支持高度专业化的任务,Mac 具备着非常高的性能表现;键盘鼠标可以帮助你进行而复杂的操作;多任务能力允许你以自己所需的方式进行工作;而多帐户体系则能使 Mac 适用于更多样的工作场景。
最后来看 Apple TV。这是生态当中最具共享性的平台,我们通常会与家人或朋友一起观看;TV 最具稳定性,始终与电视机绑定在一起,不会四处移动;TV 是完完全全的放松型设备,我们用它来享受影音或游戏,每次使用时长通常在三十分钟到几个小时之间。
配以高清显示屏,TV 的画质将会鲜活得呼之欲出;TV 的遥控器轻便易用,你可以轻松地将其传递给朋友和家人;TV 可以与 HomeKit 良好配合,使其高度稳定的特性得以在「家庭」这个场景中充分地发挥;其界面设计特别面向 10 码左右的距离进行优化,使你可以轻松地窝在沙发里享受娱乐体验。
通过以上分析,你便能理解,为何了解每个平台的「情境」与「能力」对于你的目标平台选择来说是如此重要的事了。
「情境」是平台的立命之本,而「能力」则决定了其独特性。
对于你的 app 来说也是如此。你需要问自己两个关键问题:我的 app 可以在怎样的情境里体现产品价值?要实现产品价值,需要哪些特定的技术能力作为支持?
在 Apple 内部,每当需要为 app 选择目标平台时,我们都会反复进行一项简单的练习。现在我来为各位进行演示。
首先让我们以「健身记录」 app 为例。
想想看「健身记录」的产品特性,你会发现它首先必须具备移动性。它需要追踪你全天的运动行为,以便进行的数据统计。因此它需要设备平台具备「始终开机,常伴于身」的特质,即高度的移动性。
同时,「健身记录」还必须是私人化的。它应该能且只能追踪你个人的数据。
接下来,我们要通过象限图来建立情境特质与平台之间的映射关系。其中横轴代表「移动性」,从左到右递减;一系列 Apple 设备平台按照各自的特质分布在轴线上,譬如 Watch 最具移动性,而 TV 最具稳定性。
而纵轴代表「私人性」,从上到下递减。其中 Watch 最具私人性,TV 则最具共享性。
对于「健身记录」而言,由于要同时具备高度的移动性与私人性,因此在象限图当中会大致位于左上方的位置。这便解释了为什么它会出现在 Watch 和 iPhone 当中,而非其他平台。
接下来我们以 GarageBand 为例。
GarageBand 涉及到的人机互动是高度精准型的,因为人们需要非常准确地操作音频内容,使它们出现在正确的时间和地点。
此外,GarageBand 必须良好地支持多任务,因为人们往往会将多种音频器材和乐器连接进来同时进行演奏。
我们通过象限图来建立映射关系。其中横轴代表交互的性,左端为粗放型,最具代表性的平台是 Watch,因为其屏幕较小,而人们的手指相对粗大,难以完成具有高精度要求的操作;右端为精准型,代表平台为 MacBook 或 iMac,因为键鼠操作具备最高的度。
纵轴则代表「多任务能力」,从上到下递减。在 Mac 上,我们可以轻松地进行多任务操作;而对于 Watch,你每次只能完成一项任务。
GarageBand 需要同时具备高度的交互能力,以及良好的多任务能力,因此在象限图当中会大致位于右侧偏上的位置,所对应的即是 Mac、iPad 和 iPhone。
这两个例子都非常简单,各自仅涉及到两方面的情境特质。在实际当中,我们通常需要将更多、更复杂的特质因素考虑进去;最终,我们希望能够为 app 找到最适合其生存的平台。
以上便是跨平台设计流程中的第一步,「平台选择」,即综合考量不同设备的情境特质及能力特征,进而为 app 选择最为适合的平台。
对于同一个页面布局,几乎每个人的写法都不一样,有人喜欢Flex弹性盒子布局,有的人则喜欢Float浮动布局,有些人喜欢Margin负值布局,等等。从来就没有一种统一的布局方案,现在大伙写代码也就放飞自我,只要能在规定的环境上跑起来,不会乱就行了。但是,身为脑瘫正经前端,我们还是有必要分出在不同情况应使用的布局。
这一篇博客比起作为文章,不如作为工具书。当你对布局迷茫时,不妨打开看看。我们可以不求甚解,只需要先把所有布局掌握熟练。
文章目录
CSS3 终极布局指南
正常布局(语义化布局)
正常布局,按照浏览器的内置CSS渲染
应用场景
带来的问题
挫
不兼容
没有自适应
解决方案
Float浮动布局
什么是浮动?
浮动元素的排列
浮动解决的布局问题
浮动带来的问题
父元素高度坍缩
不希望浮动时清除浮动
总结
定位布局
定位的应用
static
relative
absolute
高度坍缩
对比float
总结
fixed
祖先未使用transform:none
使用
sticky 粘性定位
Flex布局
浏览器支持
Flex使用介绍
Flex容器属性
flex-direction 排布方向
flex-wrap 控制换行
flex-flow [排布方向/控制换行]的简称
justify-content 子项目在主轴上的排布
align-items 子项目在交叉轴排布
align-content 定义多根轴线排布
Flex子项属性
order 子项排布靠前排名
flex-grow 子项放大比例
flex-shrink 子项缩小比例
flex-basis
flex
align-self
Grid 布局
参考
声明
正常布局(语义化布局)
正常布局,按照浏览器的内置CSS渲染
大道至简在远古时代,CSS还有没被发明,浏览器渲染HTML的时候,只是按照规定好的如标题、段落、表格等格式渲染。且不同的浏览器对于相同元素的渲染也是不同的,现在这项传统艺能保留到了今天。
不过到了今天,正常布局也稍微被W3C重视了一下。在HTML5的规定中,新增加了不少语义化的元素。所谓语义化元素就是让大家规定它就是来做这件事的。
新增加的语义化元素。
标签名称 作用
hearder header 标签定义文档的页面组合,通常是一些引导和导航信息。
nav nav 标签定义显示导航链接不是所有的成组的超级链接都需要放在nav标签里。nav标签里应该放入一些当前页面的主要导航链接。 例如在页脚显示一个站点的导航链接(如首页,服务信息页面,版权信息页面等等),就可以使用nav标签,当然,这不是必须的。
article article标签装载显示一个独立的文章内容。例如一篇完整的论坛帖子,一则网站新闻,一篇博客文章等等,一个用户评论等等 artilce可以嵌套,则内层的artilce对外层的article标签有隶属的关系。例如,一个博客文章,可以用article显示,然后一 些评论可以以article的形式嵌入其中。
section section 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
aside aside 用来装载非正文类的内容。例如广告,成组的链接,侧边栏等等。
hgroup hgroup 标签用于对网页或区段的标题元素(h1-h6)进行组合。例如,在一个区段中你有连续的h系列的标签元素,则可以用hgroup将他们括起来。
time time 标签定义公历的时间(24 小时制)或日期,时间和时区偏移是可选的。该元素能够以机器可读的方式对日期和时间进行编码,这样, 举例说,用户代理能够把生日提醒或排定的事件添加到用户日程表中,搜索引擎也能够生成更智能的搜索结果。
mark mark 标签定义带有记号的文本。请在需要突出显示文本时使用 <mark> 标签。
figure figure标签规定独立的流内容(图像、图表、照片、代码等等)。figure 元素的内容应该与主内容相关,但如果被删除,则不应对文档流产生影响。
可以看到HTML5规定中增加了不少新的标签,但是这些标签大部分并不是为了补充正常的文档布局的,而是服务于搜索引擎的爬虫。不要觉得页面布局只是给人看的!对于布局清晰地页面,搜索引擎的爬虫也会给出更高的分数。
应用场景
作为布局的基石。
开发较为单一的页面,比如电子书阅读页面,面向视力障碍人士的报纸页面等。
带来的问题
挫
使用浏览器默认的CSS意味着你不可定制自己的页面,对于像<ul>、<table>这样的标签,你也只能忍受上世纪的设计风格了。
不兼容
先前说了,每个浏览器对于基础的HTML节点的渲染都不一样,也就是说你写的页面在IE上是一个风格,换到Safari上又是一种风格。
没有自适应
有一说一,正常布局(语义化)还是用来当基石比较好,对于响应式、自适应那还得看下面伙计的发挥。
解决方案
解决挫的方法就是使用style属性,也就是使用CSS美化我们的页面。解决不兼容的问题则需要初始化CSS,大伙应该在不少的页面的头部见过一大坨css代码吧,就像下面Google页面。(部分)
body{color:#000;margin:0}body{background:#fff}a.gb1,a.gb2,a.gb3,.link{color:#1a0dab !important}.ts{border-collapse:collapse}.ts td{padding:0}#res,#res .j{line-height:1.2}.g{line-height:1.2;text-align:left;}.ti,.bl{display:inline}.ti{display:inline-table}#rhs_block{padding-bottom:15px}a:link,.w,#prs a:visited,#prs a:active,.q:active,.q:visited,.kl:active,.tbotu{color:#1a0dab}.mblink:visited,a:visited{color:#609}.cur,.b{font-weight:bold}.j{width:42em;font-size:82%}.s{max-width:48em}.sl{font-size:82%}
1
页面初始化也是很重要的,它可以使我们的代码健壮的运行在各个环境的浏览器上。
Float浮动布局
什么是浮动?
如果首先要认识一个物品,认识一个东西的最好方式是了解为什么会产生它,也就是要翻它的历史。——NaoTan·Ma·Nong
看上图,啊,报社最爱的环绕,一堆文字环绕一张图片,这样的布局使得页面紧凑,并且有较好的阅读体验。如果我们要在HTML中实现这样的布局应当怎么设置呢?手动设置换行?不行,缺少灵魂。如果能使文字绕过图片排列下来就好了。
于是Float属性出世,它不仅解决了文字环绕问题,并且带来了新的布局方案。
如上面的布局,我们用代码实现主要部分。
.side-bar{
float:left;
}
.main-content{
float:left;
}
1
2
3
4
5
6
浮动元素的排列
当一个元素被设置为浮动元素时,首先,它会被移除文档流,设置float:left|right则元素会向设置方向排列,直到遇到父元素边框(或者说最大宽度)或者另一个浮动元素时停止。
当设置父元素display:flex时,子元素的浮动值无效!
浮动解决的布局问题
使用浮动我们可以解决传统的两列布局、三列布局的自适应。下面代码是用浮动实现的两列布局。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>两列布局</title>
<style>
body,
html {
margin: 0;
background-color: rgb(228, 228, 228);
}
header {
margin-bottom: 20px;
}
footer {
margin-top: 20px;
}
.layout {
height: 50px;
border: 1px solid black;
}
aside {
width: 25%;
float: left;
border: solid 1px black;
height: 500px;
}
article {
width: 70%;
border: solid 1px black;
height: 500px;
float: right;
}
</style>
</head>
<body>
<header class="layout"></header>
<div style="overflow:auto;">
<aside>
</aside>
<article>
</article>
</div>
<footer class="layout"></footer>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
效果如下
浮动带来的问题
父元素高度坍缩
一般来说新手在学习浮动布局之后,遇到的第一个问题就是父元素高度坍缩。什么是高度坍缩?
看上图,在父元素的四个子元素均为浮动元素,由于浮动元素的特性浮动元素脱离文档流,所以父元素不会被撑起高度。
如何解决?答案很简单,使用BFC块级格式上下文。当父元素为BFC的时候,内部计算高度会带上浮动元素的高度。
不希望浮动时清除浮动
使用clear属性可以使元素清除周围的浮动。
如上图,对段落文字清除浮动,导致原本环绕的文字,另起一行。顺便解决了高度坍缩的问题。
总结
浮动在带来方便的同时也引入了新的问题,如果能处理好这些问题那么浮动也可以当做布局的主力,但是都已经9102年了,我们应该追随CSS3的布局方案,尽量少使用浮动。
定位布局
收拾房子的时候总会把物品按照相应的位置放置,这样会让房间看上去更加整洁。所以,我们CSS也是可以这样做的。
使用position属性,调整元素的位置。position一共有四种定位类型:定位元素、相对定位、绝对定位、粘性定位,五种取值:static、relative、absolute、fixed、sticky。
名称 描述 定位类型
static 该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index属性无效。 定位元素
relative 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。 相对定位
absolute 不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。 绝对定位
fixed 不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。 绝对定位
sticky 盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky对 table 元素的效果与 position: relative相同。 粘性定位
一般使用position属性时,会使用其相对定位与绝对定位、粘性定位,它们都使用top、bottom、left、right来调整自身位置,但是调整的基准不一样。
定位的应用
static
static是元素正常出现在文档流中的定位,文档流中的排列为自上而下,自左至右。一般来说block元素自占一行,inline元素横向排列。
正常情况下在我们的页面中大部分元素为static定位,对于一些特殊需求我们需要使用其他定位。比如像wiki中的关键词,鼠标移动上去的时候,关键词下面显示式卡片。
relative
relative是在实现一些特殊布局的时候经常使用的一种定位方式。设置为relative的元素并不会脱离文档流,但是可以通过top、bottom、left、right调整元素对于默认基准的位置。
.box {
display: inline-block;
width: 100px;
height: 100px;
background: red;
color: white;
}
position: relative;
top: 20px;
left: 20px;
background: blue;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
使用相对定位可以实现一些炫酷的效果。
.content{
text-align: center;
margin: 20px;
}
.card{
position: relative;
display: inline-block;
width: 200px;
height: 200px;
background-color: darkgray;
top: 210px;
right: 170px;
visibility: hidden;
}
span:hover+.card{
visibility:visible;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="content">
<span>鼠标移到我身上!</span>
<div class="card">
</div>
</div>
1
2
3
4
5
6
效果
但是,使用相对定位依然会出现一些问题。relative定位并不会脱离文档流,所以.content元素的高度为200px。
absolute
与relative定位不同的是absolute是脱离文档流的,而且相对基准是position属性不为static的祖先元素,如果祖先都是static则元素相对body定位。并且,对于absolute元素,如果不设置top/bottom/left/right的话依然排列在正常布局位置。
html,
body {
margin: 0;
}
.content {
position: relative;
/ top: 50px; /
margin-top: 50px;
}
.static {
position: static;
}
.relative {
position: relative;
margin: 20px 0;
}
.absolute {
display: inline-block;
width: 50px;
height: 50px;
background-color: lightcoral;
position: absolute;
}
.non-ab {
display: inline-block;
width: 50px;
height: 50px;
background-color: darkblue;
margin-left: 100px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div class="content">
<div style="height: 50px;"></div>
<div class="static">
<div class="non-ab">
</div>
<div class="absolute">
</div>
</div>
<div class="relative">
<div class="absolute">
</div>
<div class="non-ab">
</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
上面的代码很有意思,有兴趣的同学可以放在codepen上面跑一下子。这个例子验证了absolute的排列方式。当我们知道我们在做什的时候,也就不需要墨守成规(对于absolute元素的父元素统一设置relative属性)了。
高度坍缩
只要是脱离了文档流的元素都会出现高度坍缩,所以在使用absolute属性时,请确保父元素不会因此而改变。
对比float
Float与absolute都会使元素脱离文档流,但是众所周知对相同元素设置float与设置absolute会出现不同的效果。这是因为float与absolute本身的排列不一样。
float:脱离文档流,排列时以父元素为基准,并且会为占用其他浮动元素的位置。
absolute:脱离文档流,排列时分情况:第一种情况,对于未设置left、right、top、bottom属性的元素,排列在正常显示位置,并不占用空间。第二种情况,设置位置属性的元素,基于非static祖先元素排列。
上面两者比较显著的差异为float会影响下一个float元素,但是absolute元素不会。
总结
说absolute为绝对定位也并不贴切,它也是基于祖先元素定位的,只是脱离了文档流。我个人还是比较推荐在处理元素相对位置问题上使用absolute属性的,但前提是您已经深刻理解了absolute的排列方式。
fixed
不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。
fixed元素也会脱离文档流,并且和absolute元素一样,当不设置任何left、top、bottom、right值的时候,元素依然按照正常定位的位置放置。
祖先未使用transform:none
当祖先元素未使用transform:none的时候,fixed元素相对于该祖先元素进行定位。
在上面的图片中,我设置小黄块为fiexd属性,并让父元素设置为 使用transform:matrix(1, 0, 0, 1, 0, 0);,这时候小黄块并没有相对于body进行定位,当滚动条下拉时,小黄块定位固定在父元素左上角。
使用
fiexd元素一般用在如:to-top按钮,或者侧边悬浮面板,或者悬浮导航栏之中。
sticky 粘性定位
盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky对 table 元素的效果与 position: relative相同。
上面我们使用了fiexd与transform,发生了我们意想不到的效果,那就是fixed元素并未相对于body进行移动,也没有在父元素中进行标准的fixed定位。现在我们使用以下sticky属性来看一下效果。
<style>
.box{
box-sizing: border-box;
height: 150px;
border:solid 3px black;
margin: 0 0 20px 0;
overflow: auto;
}
.block{
width: 50px;
height: 50px;
background-color: orange;
}
.sticky-1{
position:sticky;
top: 0px;
}
</style>
<div class="box box-1">
<p>下面这个小黄块设置为sticky</p>
<div class="sticky-1 block">
</div>
<p>
hahah
</p>
<p>
hahah
</p>
<p>hahaha</p>
<p>hahaha</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
当我们向下滚动的时候神奇的事情发生了。
小黄块固定到了父元素的top:0位置了,不仅如此,再向上滑动后,小黄块又回复了当时的位置,而且占用了文档本身的位置。
使用这个特性我们可以制作浮动的Header组件,当用户向下滑动至窗口上侧的时候,Header组件也跟随窗口滑动。
Flex布局
对于前端工程师来说,最让人头疼的莫过于自适应布局。对于不同分辨率的设备要做到页面统一,在CSS3出现之前,还是挺不容易的。还有就是前端工程师头疼的一个布局问题:垂直居中。
CSS3中新出了一种布局技术:CSS弹性盒子布局,我们来看一下MDN是如何介绍的。
CSS 弹性盒子布局是 CSS 的模块之一,定义了一种针对用户界面设计而优化的 CSS 盒子模型。在弹性布局模型中,弹性容器的子元素可以在任何方向上排布,也可以“弹性伸缩”其尺寸,既可以增加尺寸以填满未使用的空间,也可以收缩尺寸以避免父元素溢出。子元素的水平对齐和垂直对齐都能很方便的进行操控。通过嵌套这些框(水平框在垂直框内,或垂直框在水平框内)可以在两个维度上构建布局。
接下来,我会使用Flex布局技术,设计一些我们常使用页面布局,并指出优点与缺点。但是,我们首先要来看一下浏览器的支持程度。
浏览器支持
特性 Firefox (Gecko) Chrome Internet Explorer Opera Safari
基础支持 20.0 (20.0) 21.0-webkit 29.0 10.0-ms 11.0 12.10 6.1-webkit
主流的浏览器全部支持Flex属性。注:与社会脱轨的IE9并不支持Flex,如果想写出兼容IE9的页面,请不要使用Flex。
Flex使用介绍
使用flex务必清楚一些属性概念。
Flex容器:对于一个基本元素(不含任何CSS属性,如div),设置display:flex,即可创建一个Flex容器。
Flex子项:父元素为Flex容器的元素,称之为Flex子项,其排布受到父元素影响。注:一定是父元素为Flex容器的元素,祖先不算。
排布方向:指Flex子项在Flex容器中的排布方向。排布方向有两种:column、row。在Flex容器上使用flex-direction: column|row(默认);即可设置。
主轴:指的Flex容器中是与排列方式相同的方向的轴。如设置Flex容器direction: column;则其主轴为竖直方向。
交叉轴:指的Flex容器中是与排列方式相反的方向的轴。如设置Flex容器direction: column;则其主轴为水平方向。
我们一定要清楚上面的基础概念,这对深入使用Flex有很大的帮助。下面我会介绍一些Flex常用的属性,主要分为两部分:对Flex容器、对Flex子项。
Flex容器属性
flex-direction 排布方向
flex-direction 属性指定了内部元素是如何在 flex 容器中布局的,定义了主轴的方向(正方向或反方向)。
flex-direction属性接受以下值:
row:子项目在flex容器中横向,从左至右排列。
row-reverse:表现和row相同,也是横向,但是是从右到左。
column:子项在容器中竖向排列,从上至下。
这里不贴图了
column-reverse:表现和column相同,子项在容器中竖向排列,从下至上。
这里不贴图了
flex-wrap 控制换行
CSS flex-wrap 指定 flex 元素单行显示还是多行显示 。如果允许换行,这个属性允许你控制行的堆叠方向。
取值:
nowrap(默认)
flex 的元素被摆放到到一行,这可能导致溢出 flex 容器。 cross-start 会根据 flex-direction 的值 相当于 start 或 before。
wrap
flex 元素 被打断到多个行中。cross-start 会根据 flex-direction 的值选择等于start 或before。cross-end 为确定的 cross-start 的另一端。
wrap-reverse
和 wrap 的行为一样,但是 cross-start 和 cross-end 互换。
flex-flow [排布方向/控制换行]的简称
CSS flex-flow 属性是 flex-direction 和 flex-wrap 的简写。
示例:flex-flow: column-reverse wrap;
justify-content 子项目在主轴上的排布
CSS justify-content 属性定义了浏览器如何分配顺着父容器主轴的弹性元素之间及其周围的空间。
justify-content同时受到父容器主轴的影响。
取值:
start
从行首开始排列。每行第一个元素与行首对齐,同时所有后续的元素与前一个对齐。
flex-start(默认)
从行首开始排列。每行第一个弹性元素与行首对齐,同时所有后续的弹性元素与前一个对齐。
flex-end
从行尾开始排列。每行最后一个弹性元素与行尾对齐,其他元素将与后一个对齐。
center
伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同。
left
伸缩元素一个挨一个在对齐容器得左边缘,如果属性的轴与内联轴不平行,则left的行为类似于start
right
元素以容器右边缘为基准, 一个挨着一个对齐,如果属性轴与内联轴不平行,则right的行为类似于start.
space-between
在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐。
space-around
在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半。
space-evenly
flex项都沿着主轴均匀分布在指定的对齐容器中。相邻flex项之间的间距,主轴起始位置到第一个flex项的间距,主轴结束位置到最后一个flex项的间距,都完全一样。
看上去与space-around的排布很相似,但其实还是有一些区别的。space-evenly会在每一行均匀分布间隙,而space-around是均匀分布项目。
借一张图
看上去我们要学的属性很多,但是其实我们只需要记住我们常用的几个属性就行:flex-start、flex-end、space-between、center、space-around、space-evenly。以上这几个就是我们常用的属性值,通过设置主轴方向、设置排列方式,我们可以灵活地组织我们的元素。
align-items 子项目在交叉轴排布
CSS align-items属性将所有直接子节点上的align-self值设置为一个组。 align-self属性设置项目在其包含块中在交叉轴方向上的对齐方式。
取值:
normal
这个关键字的效果取决于我们处在什么布局模式中:在绝对定位的布局中,对于被替代的绝对定位盒子,这个效果和start的效果的一样;对于其他所有绝对定位的盒子,这个效果和stretch的效果一样。 在绝对定位布局的静态位置上,效果和stretch一样。对于那些弹性项目而言,效果和stretch一样。对于那些网格项目而言,效果和stretch一样,除了有部分比例或者一个固定大小的盒子的效果像start。这个属性不适用于会计盒子和表格。
flex-start
元素向侧轴起点对齐。
flex-end
元素向侧轴终点对齐。
center
元素在侧轴居中。如果元素在侧轴上的高度高于其容器,那么在两个方向上溢出距离相同。
因为align-items其实和justify-content我这里就不放一些图片凑字数了。
align-content 定义多根轴线排布
该属性对单行弹性盒子模型无效。(即:带有flex-wrap: nowrap)。
CSS的align-content属性设置了浏览器如何沿着伸缩盒子容器(flexbox container)的纵轴和网格容器(Grid Container)的主轴在内容项之间和周围分配空间。
它的取值和align-items差不多,经常有人会把他们搞混。
align-content一般定义多行的交叉轴排列。
绝大多数情况下我们使用align-items即可实现我们的需求。
Flex子项属性
order 子项排布靠前排名
CSS order 属性规定了弹性容器中的可伸缩项目在布局时的顺序。元素按照 order 属性的值的增序进行布局。拥有相同 order 属性值的元素按照它们在源代码中出现的顺序进行布局。
取值:
<integer>
表示此可伸缩项目所在的次序组。
flex-grow 子项放大比例
CSS flex-grow 属性定义弹性盒子项(flex item)的拉伸因子
取值:
<number>
默认值0,即如果存在剩余空间,也不放大。负值无效。
flex-shrink 子项缩小比例
CSS flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。
总而言之,你定了这个属性,其他项目会先压榨你的空间,然后再均匀缩小其他项目。
flex-basis
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
注:分配多余空间之前!!
也就是说你给的flex-basis值大于当前分配空间时,依然会被压缩。
flex
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
align-self
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
这个属性了不得,它也是我们经常用的子项目属性之一。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
1
2
3
就像上面的图,他可以决定子项目的交叉轴单独排列方式。
Grid 布局
未完待续…明天补上
参考
HTML5语义化标签属性-HTML5属性手册
All About Floats | CSS-Tricks
清除浮动的四种方式及其原理理解
【前端Talkking】CSS系列——CSS深入理解之absolute定位
CSS 弹性盒子布局
Flex 布局教程:语法篇
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
three.js 的简单实例
三大主件: 渲染器、场景、相机
思想核心: 相机获取到场景内显示的内容, 然后再通过渲染器渲染到画布上面
渲染器: 实例化渲染器的同时生成的一个 Canvas 画布, 之后将这个画布添加到了 DOM 当中
场景: 场景只是一个容器, 显示的内容需要进行添加, 添加一个内容称作一个网格, 每个网格基本上包括几何体和材质, 网格也称之为模型
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>three</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body onload="init()">
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="js/three.min.js"></script>
<script type="text/javascript" src="js/stats.min.js"></script>
<script type="text/javascript" src="js/dat.gui.min.js"></script>
<script>
//声明一些全局变量
var renderer, camera, scene, geometry, material, mesh, stats, rotate = true;
//初始化渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer(); //实例化渲染器
renderer.setSize(window.innerWidth, window.innerHeight); //设置宽和高
document.body.appendChild(renderer.domElement); //添加到dom
}
//初始化场景
function initScene() {
scene = new THREE.Scene(); //实例化场景
}
//初始化相机
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); //实例化相机
camera.position.set(0, 0, 15); //初始化的坐标
}
//创建模型
function initMesh() {
geometry = new THREE.BoxGeometry(2, 2, 2); //创建几何体
material = new THREE.MeshNormalMaterial(); //创建材质
mesh = new THREE.Mesh(geometry, material); //创建网格
scene.add(mesh); //将网格添加到场景
}
//运行动画
function animate() {
requestAnimationFrame(animate); //循环调用函数
//判断是否可以旋转
if(rotate) {
mesh.rotation.x += 0.01; //每帧网格模型的沿x轴旋转0.01弧度
mesh.rotation.y += 0.02; //每帧网格模型的沿y轴旋转0.02弧度
}
stats.update(); //更新性能检测框
renderer.render(scene, camera); //渲染界面
}
//性能检测框
function initStats() {
stats = new Stats();
document.body.appendChild(stats.dom);
}
//创建调试框
function initGui() {
//控制参数初始值
controls = {
positionX: 0,
positionY: 0,
positionZ: 0,
rotate: true
};
gui = new dat.GUI(); //实例化对象
gui.add(controls, "positionX", -10, 10).onChange(updatePosition);
gui.add(controls, "positionY", -5, 5).onChange(updatePosition);
gui.add(controls, "positionZ", -10, 10).onChange(updatePosition);
function updatePosition() {
mesh.position.set(controls.positionX, controls.positionY, controls.positionZ);
}
gui.add(controls, "rotate").name("旋转").onChange(function(e) {
rotate = e;
});
}
//初始化函数,页面加载完成是调用
function init() {
initRenderer();
initScene();
initCamera();
initMesh();
initStats();
initGui();
animate();
}
</script>
</body>
</html>
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
1.获得内容 - text()、html() 以及 val()
text() - 返回所选元素的文本内容
html() - 返回所选元素的内容(包括 HTML 标记)
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <p id="p1">圣诞快乐,<b>新年快乐</b></p> //给p元素里边的文本一部分加上b标签 <button id="b1">显示文本</button> <button id="b2">显示html</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#b1").click(function(){ alert( $("#p1").text() ); //获取文本 }); $("#b2").click(function(){ alert( $("#p1").html() ); //获取html内容 结果会包含b标签 }); }); </script>
val() - 返回表单字段的value值
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <input type="text" id="ip" value="nihao"> <button id="but">显示value值</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ alert($("#ip").val()); 结果返回表单元素的value值(nihao) }); }); </script>
2.获取属性 - attr()
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <a id="aa" href="www.baidu.com"></a> <button id="but">显示元素属性</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ alert($("#aa").attr("href")); }); }); </script>
1设置内容和回调函数 - text()、html() 以及 val()
text() - 设置所选元素的文本内容
html() - 设置所选元素的内容(包括 HTML 标记)
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <p id="p1"></p> <button id="b1">显示文本</button> <button id="b2">显示html</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#b1").click(function(){ $("#p1").text("圣诞快乐,<b>新年快乐</b>") ; //设置文本 }); $("#b2").click(function(){ $("#p1").html("圣诞快乐,<b>新年快乐</b>") ; //设置html内容 结果会包含b标签 }); }); </script>
text()、html()回调函数
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <p id="p1">新年快乐</p> <button id="b1">显示文本</button> <button id="b2">显示html</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#b1").click(function(){ $("#p1").text(function(){ return "happy new year"; //调用函数,返回一个新的文本 } ) ; }); $("#b2").click(function(){ $("#p1").text(function(){ return "happy <b>new</b> year"; //调用函数,返回一个新的文本 } ); }); }); </script>
val() - 设置表单字段的value值和回调函数
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <input type="text" id="ip"> <button id="but">显示value值</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ $("#ip").val("happy"); }); }); </script>
val()的回调函数
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <input type="text" id="ip"> <button id="but">显示value值</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ $("#ip").val(function(){ return "happay"; }); }); }); </script>
2.设置属性 attr()
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <a id="aa" href="www.baidu.com">11111</a> <button id="but">显示元素属性</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ alert($("#aa").attr( { "href":"http://news.baidu.com/" } )); //attr()里边,要加{}号 }); }); </script>
attr()的回调函数
<script type="text/javascript" src="jquery-1.11.2.min.js"></script> <body> <a id="aa" href="www.baidu.com"></a> <button id="but">显示元素属性</button> </body> </html> <script type="text/javascript"> $(document).ready(function(e) { $("#but").click(function(){ alert($("#aa").attr({ "href":function(){return "http://news.baidu.com/" } } )); //attr()里边,要加{}号 });}); </script>
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
jQuery 拥有可操作 HTML 元素和属性的强大方法。
jQuery DOM 操作
jQuery 中非常重要的部分,就是操作 DOM 的能力。
jQuery 提供一系列与 DOM 相关的方法,这使访问和操作元素和属性变得很容易。
提示:DOM = Document Object Model(文档对象模型)
DOM 定义访问 HTML 和 XML 文档的标准:
“W3C 文档对象模型独立于平台和语言的界面,允许程序和脚本动态访问和更新文档的内容、结构以及样式。”
获得内容 - text()、html() 以及 val()
三个简单实用的用于 DOM 操作的 jQuery 方法:
text() - 设置或返回所选元素的文本内容
html() - 设置或返回所选元素的内容(包括 HTML 标记)
val() - 设置或返回表单字段的值
下面的例子演示如何通过 jQuery text() 和 html() 方法来获得内容:
<!DOCTYPE html>
<html>
<head>
<script src="/jquery/jquery-1.11.1.min.js"></script>
<script>
$(document).ready(function(){
$("#btn1").click(function(){
alert("Text: " + $("#test").text());
});
$("#btn2").click(function(){
alert("HTML: " + $("#test").html());
});
});
</script>
</head>
<body>
<p id="test">这是段落中的<b>粗体</b>文本。</p>
<button id="btn1">显示文本</button>
<button id="btn2">显示 HTML</button>
</body>
</html>
val()方法例子:
<!DOCTYPE html>
<html>
<head>
<script src="/jquery/jquery-1.11.1.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
alert("Value:"+$("#test").val());
});
});
</script>
</head>
<body>
<p>姓名:<input type="text" id="test" value="米老鼠"></p>
<button>显示值</button>
</body>
</html>
获取属性 - attr()
jQuery attr() 方法用于获取属性值。
<!DOCTYPE html>
<html>
<head>
<script src="/jquery/jquery-1.11.1.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
alert($("#w3s").attr("url"));
});
});
</script>
</head>
<body>
<p><a url="img/001.jpg" id="w3s">W3School.com.cn</a></p>
<button>显示 href 值</button>
</body>
</html>
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
在做设计的过程中,大部分设计师只专注于主操作流程、主页面、分支流程、小页面和页面的不同状态。却容易忽略产品中容易出现的各种异常状态。
当用户停留任何一个界面,进行任何一个操作都可能发生异常状态。
如果接到每个需求都去制定一次异常状态,这样的后果可能会使得产品的不同模块、不同流程,异常状态都不一致。全局规范性被破坏,同时设计师的效率也降低。
因此全局制定异常状态规范很有必要,后续就不需要再设计,开发直接复用异常状态的规范。省时省力、提率、设计规范、运行更流畅、减少代码重复率、安装包也会更小。
异常状态一共有以下 10 类:
当移动设备网络异常时,导致无法上传和下载数据,从而无法正常的使用产品。
网络异常存在两种场景:
1. App主动行为
当无网络时,用户打开 App,通常有三种方式提醒用户当前网络异常。
tips 提示,通过 tips 提示用户当前网络不可用,tips 使用场景一般为用户打开后,界面停留在首页,且首页以列表形式展示,这样的话, tips 才能合理的融入到界面中,常见使用这种布局方式的有微信、qq等。
使用toast提示用户网络异常,同时提示用户可以去使用非数据影响的操作。例如网易云音乐,当无网络时候,告知用户可以去正常听已下载的音乐。
使用对话框,引导用户进入设置页面,关闭飞行模式或者打开 Wi-Fi,例如美团进入首页后的对话框提示。
2. App被动行为
当前无网络时,用户点击操作,无法正常使用产品,这时候通常有两种处理方式。
一种是当前界面出现 toast 提示。另一种是进入下一级界面,以缺省页的形式提醒用户当前网络异常。
例如手机淘宝,没有网络时,用户点击会进入下一页,出现缺省页提示,告知用户网络异常,同时提供刷新按钮。
美团在无网络时,点击其他 tab bar,出现 toast 提示用户当前网络异常,稍后重试。
3. 小结
当涉及需要消耗大量流量数据时,且非 Wi-Fi 情况下,这时候需要告知用户。常见的例如看视频,听/下载歌曲、视频通话、下载上传文件等。
例如B站,当使用移动数据看视频,则通过提示语和对应按钮上的流量值告知用户。
网易云音乐在非 Wi-Fi 情况下,下载音乐时,通过对话框,告知用户当前使用数据流量,同时提供可继续下载的功能,也提供通过办理新业务解决数据流量的问题。
空数据一共分为两种类型,分别为初始状态和清空状态。
1. 初始状态
用户首次使用,没有任何内容数据时,需要用户进行某种操作才能产生内容的界面,这时候需要提示用户需要进行某种操作。
例如淘宝App,当用户没有把商品加入购物车时,进入购物车界面,会给出提示购物车界面为空。给出用户提示,给出相对应的入口按钮,引导用户操作。
如果初始状态,无任何内容直接给出一个空白界面,用户可能会以为该界面出 bug 了。
Gmail 直接用一个插画提示用户收件箱为空。
一般对于初始状态的设计,常规做法是简单的插画配合简洁的文案,必要的时候给出引导用户操作行为的按钮。
现在流行的设计趋势是插画越轻量越简单越好,以免抢夺了文案信息。
2. 清空状态
当用户清空当前的页面内容,产生了空界面,这时候需要有明确的提示告知用户出现当前页面的原因,且告知用户该如何处理。
清空状态是对初始状态的进一步细化。清空状态的界面和初始状态设计很相似,唯一不同的是文案的提示。
有的产品直接把清空状态的界面按照初始状态来设计,这样也是可以的,缺点就是没有告知用户产生空状态原因是初始化还是清空所致。
在加载过程中,App 向服务器请求数据,如果是网络原因导致,则使用网络异常的设计规范。
如果非网络异常原因,则可能因为服务器异常导致接口请求不到数据,从而加载失败。
第一次请求失败,有些场景可能重试 2 次,例如微信支付宝,这种情况可使用 toast 告知用户加载失败的原因。
任何操作行为的交互界面都伴随着操作失败的概率。
当用户操作失败时,在当前页面给予一个反馈,告知用户操作失败,最好告知用户操作失败的原因,让用户知道接下来如何避免操作失败。
因为服务器异常是小概率事件,但是也会发生。
当服务器异常时,且用户在操作过程中,出现这种情况,一般可设计为对话框提示,明确告知用户,服务器出现问题,让用户稍后重试。
例如下图的华为云备份恢复界面:
用户在搜索过程中,除了出现正常的匹配结果,还存在无匹配结果的情况。针对搜索无结果的情况,要给予用户操作无结果的提示。
几乎搜索无结果的状态都是在内容区出现对应提示。例如 iOS 相册,通过搜索关键词,当没有匹配照片时,则出现对应的提示,如下图右侧图:
下图淘宝买家版后台,当用户搜索关键词无结果时,出现对应的提示语和插画。
无权限的场景,通常适用于 b 端产品,对于不同组织架构的企业员工,会存在不同的权限。
例如部分重要的内容,非同一组织架构的员工无权限查看,这种情况,用户点击进入一般给出对应的提示。
当然最好的方案是在 App 上面过滤掉无法查看的内容,但是存在员工间的转发行为,这时候无权限的员工,点击进入,则显示暂无权限查看的提示页面。
一般 App 功能正在开发中,这种情况不会在 App 界面中展示出来,只有完全开发完毕并上线后才会出现在 App 上。
但是也有一些产品的特殊业务,会将一些未开发的功能展示出来,例如微信公众号,长按微信文章,即出现对应的提示。
也有一些新闻频道还没有开发完毕上线,这时候用户点击进入下级界面,则出现对应的提示语/插图提示,如下图所示:
有的时候,文件或者页面内容被删除,但由于文件或者页面内容的上一级页面有缓存,所以当用户点击进入时,会出现文章/文件被删除的情况。
已被删除的异常状态,常见的设计是用户进入新页面出现对应的插画和标题提示。
例如下图微信公众号文章内容被作者删除,读者点击进入,加载后的界面就出现内容被删除的提示。
以上就是常见的 10 种异常状态的简单介绍和说明。在制定异常状态的设计规范时,可以参考本篇文章。
当然也有公司特殊的业务导致存在很特殊的异常状态,针对这种情况,可以适当的增加、删除或者修改,使其更适用于自己公司的项目。
文章来源:优设
局部变量
局部变量:在函数内部声明的变量,只在函数内部起作用。函数的参数也是局部性的,只在函数内部起作用,对于其他的函数或脚本代码是不可用的。
函数可以访问函数内部定义的变量,如:
<p>函数可以访问函数内部定义的变量:</p>
<button type="button" onclick="myFunction()">点我</button>
<p id="demo"></p>
<script>
function myFunction() {
var a = 4;
document.getElementById("demo").innerHTML = a a;
}
</script>
全局变量
在web页面中全局变量属于 window 对象,全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。
函数也可以访问函数外部定义的变量,如:
<p>函数可以访问定义在函数外的变量:</p>
<button type="button" onclick="myFunction()">点我</button>
<p id="demo"></p>
<script>
var a = 4;
function myFunction() {
document.getElementById("demo").innerHTML = a a;
}
</script>
全局和局部变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
问题描述:
做抽屉式菜单时候,在 ie 7 下发现 li 元素之间会留白,如下图:
原以为是样式的问题,后来看到有博文写到“行框的排列会受到中间空白(回车\空格)等的影响,因为空格也属于字符,这些空白也会被应用样式,占据空间,所以会有间隔”。
解决办法:
li 标签之间的空白,可以通过设置 li 标签的 font-size 为 0,可以解决:
li{
padding:0;
margin:0;
height: 30px;
line-height: 30px;
font-size: 0; / 设置 font-size 为 0 即可 /
}
修改后的效果如图:
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如“黄金分割”之于构图,“视觉层级”之于页面节奏,都是基础且必不可少。本文与你分享如果一步步从原型开始构建APP视觉层级。
工作中,你是否经常听到“视觉层级”这词?就犹如“用户体验”一样让人耳熟能详。抛开装逼因素,这两个词的多次提及,可见其重要程度。
音乐有节奏,好的音乐能通过音阶的高低起伏变化表达音乐情绪。
例如:《Main Title》即使你没看过《冰与火之歌》,光听音乐你是否能感觉到音乐给你营造千军万马恢弘之势。《Playing Love from The Legend of 1900》你是否想到一个宁静夜晚,佳人与你倾诉衷肠,柔情似水。
反之,节奏不好,则无法和听众达成共鸣。
绘画有节奏,张驰有度、大小对比、远近疏密变化,构成了画面的节奏。反之,没有节奏,则画面平淡。
同样的,APP UI也有节奏。页面良好的视觉层级,方便用户在浏览的过程中抓取关键信息,帮助用户快速达到目的。
拿到原型,明确页面目的和需求的1、2、3层级,并理解消化。开启设计师的隐形技能:根据一句话或者一个词,在大脑开始构建画面布局。在构思阶段,建议同时浏览同类型UI设计以及交互布局,在找参考的过程中,结合自身APP的页面目的一起构思,并在纸上绘出可行性方案。
由于,APP是为人服务。那么我们需要知道,人眼浏览习惯模式的科学依据。
曾有一数据显示:如果在3S内无法吸引用户,你将流失这个用户。如今我们所在的时代快节奏、碎片化,用户的日常浏览是“扫描”而非“阅读”。所以,了解人眼浏览习惯,变得十分重要。
人眼浏览习惯有:F型;Z型;其他;
还有,其他浏览模式,海哥HMI人机交互在他一篇文中《用户是怎么阅读的?尼尔森F模型》提到:
在明白人眼视线流程后,我们开始运用视觉手段,吸引用户来看我们想给他看的内容,并按照我们的预想顺序,依次阅读。
对比,让视觉有轻重,用户看起来不累。需要强调的信息放大,没那么重要的东西缩小。如果同一层级的模块,通过颜色或者样式的变化来表达。如:字体大小对比,颜色对比;模块大小对比;图片大小对比等。
字体千千万形状各不相同,然而他们都有着相似之处:字重的大与小。在同一字号大小下,字重大的笔画,以面构成,会比字重小的,更具视觉冲击力。
需要强调的信息,字号变大,字体加粗,这样就能区分主与次,建立更易读的视觉层级。
为了各个模块间的和谐组合和视觉上的凸显与美观,我们需要灵活运用各种样式表达。卡片投影;形状;材质等;
同一类别信息,模块化整合。便于用户浏览操作,视觉上不零散,整体美观。多模块化的组合,注意留白以及页面的节奏轻重。
以上要点,要根据实际情况灵活巧妙运用。在做的过程中,通过Mirror工具实时查看页面效果,不断改进,加强表达。
宗白华说过:“一切艺术都趋向音乐”。确切说一切“广义的”艺术都趋向于音乐状态。优秀的UI视觉层级表达,就如音乐一样有节奏变化,波浪起伏,是一种视觉享受。无论是平面还是UI,视觉层级,需要像“黄金分割原理”一样,是内化进设计师的身体里一个元素。多多实战练习,不需要死记硬背,就会刻在我们的大脑深处。
文章来源:站酷
无论是2B产品,还是2C产品,用户系统都是基础。对于非互联网产品从业者,2C用户系统的场景和功能通过日常各类APP的使用,大家都非常熟悉。因此,笔者通过和2C产品的对比,谈谈2B SaaS产品的用户系统设计。
2C产品面向的用户是个人,用户系统的核心是获客,因此大多2C产品的用户系统设计重点在于方便用户注册、登录,能够建立精准的用户画像,从而达到流量变现的目标。
2B产品面向的用户是企业,用户系统的核心是组织、员工精细化管理,提升人效,从而实现节约成本的目标。
2C产品的注册主要用于个人用户注册场景,重点在于提供多种渠道的注册方式,如账号、手机、第三方社交应用(微信、微博等),其核心目标是既能方便用户注册,又能多渠道多平台账号打通。
2B产品的注册分为两部分:企业管理员代表企业注册和企业员工注册。
2B平台型SaaS产品,和2C最大的区别在于产品需要用户付费。因此,平台方为企业(平台租户)提供了注册入口,一方面需要方便租户能够通过其他渠道快速注册试用产品,一方面需要验证企业相关信息,识别该用户确实为潜在用户。
1)企业注册:
当企业管理员代表企业注册时,需要提供的注册信息:管理员昵称、手机号、邮箱、企业工商信息(名称、组织机构代码、地址、法人信息等)。
其中工商信息的完整度,不同的产品要求不一样,需要根据具体产品而定。如果方便注册拉新,尽量减少工商信息填写要求,如果产品安全性要求较高,可以尽量要求工商信息填写完整。
2)企业工商信息认证:
这部分并非强需求场景,取决于产品的安全性要求。一般安全性要求较高的平台产品,会在企业注册后,进入到企业工商信息认证环节。此环节要么是平台管理员人工审核,要么通过第三方认证验证企业工商信息是否合规。企业完成认证后,即可试用产品。
如非安全性要求较高的产品,可以直接跳过该环节,租户通过注册页信息填写完整后既注册成功。
3)企业员工注册:
登录场景比较容易理解,目前B端产品相较C端产品仍然比较传统,多采用邮箱/手机进行登录。
未来也希望可以实现,B端产品能够和更多C端产品平台打通,可通过通用的第三方账号进行登录,实现业务与社交的连接。
用户画像是2C产品至关重要的内容,只有精准的用户画像,才能更精准的服务好用户。无论是电商,还是资讯平台,基于用户画像的精准营销投放才是产品的核心。
2B的产品很少有讲用户画像相关的内容,事实上对于2B产品而言,用户画像也至关重要。
笔者目前从事CRM产品相关工作,CRM核心要解决的问题就是帮助你的客户获客,那么如何去建立客户的企业标签,去按照企业标签属性,借助大数据分析,帮你的客户找到他的客户群,是笔者近期在研究的课题。
2C的产品从本质上来讲不存在组织结构,个人用户即为产品主体,但会存在群组/社群的概念。
2B产品的应用主体是企业,而组织结构是企业运营管理的必要手段和方式。因此组织结构管理是用户系统的重要组成部分。
1)建立组织结构
组织的单元是部门,因此管理员需要能够按照企业组织结构建立、调整(编辑、合并)、删除部门。
2)部门树结构
部门作为组织结构的单元,只是组织结构的分子,而要形成组织,就要按照企业的业务形态要求形成一定的层级体系。因此部门不仅仅只是简单的信息描述,还需要有层级描述,这就需要我们在建立部门时按照层级结构建立部门,定义清楚所建立的部门是上级部门、下级部门。
3)通讯录展示
管理员通过后台创建完组织结构后,企业员工可通过前台查询按照部门结构展示的通讯录。
角色管理是B端产品的特有功能,企业员工按其所负责的业务模块划分不同的岗位职责。
由于企业数据具有较高的安全性和私密性要求,按照岗位职责的不同,不同岗位的员工对于业务数据的操作/查看权限不同。
因此,我们设计了角色管理,该角色并非严格意义上的岗位职能角色,而为了区分不同的员工不同的系统权限所设计的系统角色,这就是RBAC设计。
1)建立角色
建立角色的主要目标即为建立一个用户权限组,该权限组内的用户具有相同的权限。
2)分配角色权限
基于角色分配系统权限,以实现不同的角色下的用户拥有不同的权限。
员工管理是B端产品的特有功能,员工是企业组织的重要组成部分,员工也是产品真正的终端用户。
B端产品从本质上是要能够帮助企业员工提升工作效率,提高企业人效,以实现企业管理者降低运营成本的目标。
1)新建员工
前面提到的用户注册即为新建员工的过程。包括被动邀请和主动注册两种形态,主要目标是将员工信息注册至系统,并建立员工和企业的关联关系。
2)建立员工汇报关系结构
为了实现精细化管理,企业内部一般按照组织结构设定员工的汇报关系,因此从CEO到基层员工会形成组织关系树,该结构可以和组织结构完全一一对应,即该部门下的所有员工均汇报给部门负责人,但也有部门内部分不同的小组,不同的人汇报给不同的小组负责人。
因此汇报关系和组织结构关系有一定关联,但并不是完全一一对应,所以我们需要设计员工汇报关系功能。
3)员工离职设定
为了保证企业数据的安全,员工离职后,需冻结员工账号,离职员工将不能以该企业员工的身份登录系统,以确保企业数据的安全性。
至此,2B用户系统的功能基本设计完整,其重难点在于组织结构、权限控制,需要重点关注。
文章来源:人人都是产品经理
蓝蓝设计的小编 http://www.lanlanwork.com