图标是 UI 设计中最基础也是很重要的部分,辅助人们更好的理解功能内容。随着扁平化设计风格的普及,图标的风格越来越简约,看似简单的图形,实际要准确的表达含义,也是需要注意一些方法的。以下是图标设计技巧的分享内容:
设计图标是一个艺术创作的过程,里面也有很多需要被关注而不可忽视技巧。要知道如何设计好图标,是对于 UI 设计师来说是不可或缺的重要技能。
在我设计图标的时候,我个人认为有以下7个规则:
一个图标一个非写实的表现。不需要担心图标不够真实,消除不必要的细节,用基本的形状只保留最基础的部分,让这个图标更容易被理解。
有时候图标会因为有更多细节而传达了更复杂的意思,这反而是样式问题!
在整个图标系统中,你的图标要保持同一种样式来确保图标完美协调。比如同样的形状,填充,描边粗细,尺寸等。要制定好可以被复用的栅格,规范和样式。
如果可以的话,尽可能重新设计这些图标,而不要混入其他不同风格的图标来使用。
设计「完美像素」的图标,特别是在图标非常小的时候。这样图标的描边就可以保持锐利,不会有模糊。注意半像素的情况出现,尽量避免小数点参数。
这也可以帮你保持图标的辨识度,在你等比缩放他们的时候保持清晰。
确保你的图标的所有形状有足够的空间。笔画和空间过于狭小会使图标更难被理解。
最少给2px的负空间
确保你的图标看起来是正确的,适当的调整元素的对齐来达到视觉上的平衡。
不要只关注参数,如果有需要就用上你的眼睛来衡量,轻微移动这些元素。
所有图标保持同样的尺寸,在图标周围定义一个可调整的内边距范围,尽量让元素设计在这个范围内。不要挤满所有元素。
当图标需要额外控件时可以超出这个内边距范围。
在设计阶段,你的图标可能看起来是完美的,但还是需要将图标放到实际的界面环境中,测试他们是不是完美,有没有可以调整的细节问题。
确保每个新增的图标和其他图标显示一致。
你在设计图标过程中,有用到以上的这些技巧吗?可以在评论区告诉我,你是怎么怎么设计图标的。
文章来源:优设网 作者:布莱恩臣
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
一起深度用案例解析B端导航设计中的交互
hello各位在B端奋斗的小伙伴们,你是否会时常因为面对导航多种多样的形式从而面对需求时无从下手,你又是否因为虽然见过了很多的案例仍然不得导航设计的要领和精髓,没关系,今天我们就一起来解决这个在B端设计中困扰我们多时的难题,从交互的角度结合案例对导航进行一个立体的剖析
如果你准备好了那么就请系上安全带现在就发车
要探讨一个概念那么首先需要知道的是其精准的定义,才能展开研究,而所谓的导航(Navigation)的精准定义可以阐述为:是一种对信息的分类,帮助用户找到想要的信息、完成预期的任务
如果你觉得这个定义很抽象,那么不妨从这个角度去理解,如果说任何界面上的功能都能够找到在我们物理世界的隐喻的话,那么导航映射的就是我们物理世界中的路牌、导览、线路示意图等,因为立足于其功能而言,导航的作用用一种大白话的说法就是:告诉用户你从哪里来,你在哪里,你可以去哪里
由此我们对导航有了一个较为准确的把控,那么请在座的各位快速回答我一个问题,你能够告诉我以上6个内容那些不是导航吗?
3
2
1
OK公布答案,如果你的答案是2和6那么恭喜你,你对导航的理解是较为优秀的,2和6的名称大家想必也不陌生那就是:菜单,但是不夸张的说日常的工作中仍旧有不小数目的一波同学搞不清楚这二者的区别,那么如何对二者进行一个有效的区分呢
同样是从定义来入手,参照前面我们给导航进行的定义方式,菜单就是:是一种对动作的分类和集合,
帮助用户快速达到某个功能,也就是说当你对菜单的某一个栏目进行点击时会立马生成一个具体的动作,而导航则是对信息的分类与合集
那么明白了这点我们就可以对导航进行分类了,提到导航的分类大家一定会脱口而出一堆词汇如:顶部导航、底部导航、左侧导航、舵式导航、标签导航、菜单导航……没错这的确是一种分类,但他只是导航在外观这个维度的分类,并不是我们今天从交互、结构层去讨论的重点
而立足于结构来对导航进行分类又将是如何呢?较为科学的来说是以下几类:
全局导航
局部导航
辅助导航
内嵌导航
友好导航
远程导航
下面我们来对这6类导航进行一步一步的具体分析
所谓全局导航是指他可以覆盖整个产品的通路,往往表现为产品的一级分类(而且大部分情况都是一级分类),他不一定包含全局信息,但是一定可以让用户可以去到其目标的关键节点
所谓局部导航是指在同一个框架中,可以到这个节点上的上下级通路,他一定存在于严格的父子级关系中
所谓辅助导航就是提供用户在全局/局部导航不可达到相关内容的快捷途径(这个快捷途径在本产品内)
所谓内嵌导航也叫上下文导航,是指嵌入页面自身内容的导航,通常同在上下文超链接、引导搜索等
所谓友好导航是指它可以为用户提供一个便利的前进途径,在需要的时候能够找到入口信息,通常在不需要的时候成隐藏状态
所谓远程导航是指不包含在产品结构中,以独立的方式存在产品内,通常表现为网站地图、索引表(地址选择、品牌选择)等
在从结构的层面了解了导航的基本类型之后,顺便给大家提一提导航的外观,这里并不展开说,大家需要知道的是导航的外观使用遵循的是“同构异型”的准则,什么意思呢?同样的结构(比如同一组数据集:商品、商品名称、商品价格)可以嵌套进入不同的外观如:卡片式、列表、详情……这个视具体的业务情况、使用场景而定
常用的导航外观基本分为以上七种外观即:菜单栏、树状表、顶栏、选项卡、面包屑、文字链接、步骤
知道了导航的结构分类和使用场景,那么不妨来给大家一些关于导航本身的小贴士作为原则参考解决大家在实战中的一些问题
对于B端产品来说稳定相当重要!因为B端产品对于用户来说使用和学习成本、门槛较大,如果你很频繁地对其路径进行修改调整,用户就会因为产品不符合操作的习惯、心智模型对产品很容易滋生负面情绪,对于产品本身来说这样的伤害是需要尽量避免的
还是从稳定的方面来说,我们需要保证的是导航的变化不会因为产品的变化而发生很大的变化,举个很简单的例子就是当我们的产品的功能增多时,尤其是二级导航的项目增多,导致原来如果是横向布局的导航不得不改成纵向布局的导航,这就所谓的因为产品的变化发生很大的变化,所以在选择导航布局的时候就需要打下一个很好的基础便于日后的拓展
这是站在一个外观和交互共同的层面去看,导航的大小一定要足够,而且其位置一定要是用户认为足够清晰的,确保在视觉反馈的的层面对于用户来说是友好的,其次就是所有的可交互区域需要有积极的响应,与内容区要有对比,可以将其称为界面的热情度,这也是一个优秀界面的自我修养
一个页面中允许出现两个主导航,同一个界面中允许出现两个同样的导航项,并不是说一个项在导航中只能够出现一次,并没有那么死板
这对于To B 的设计来说十分重要,不同于To C的产品,B端产品的一个重点就是要符合用户的预期,所以我们一定要避免“因为有趣所以这设计”这个思路
界面上面所有的界面编排,所有的组件,所有的控件,所有的模式都是可以找到隐喻的,比如文字链和带“跳转”的文字链,它代表的隐喻是不一样的,所以我们就需要赋予其不同的外观和交互响应对应户进行反馈
回到最初导航的定义,它的本质是对信息进行分类,让用户快速完成任务,这也是导航的本职工作,很多时候不一定要拘泥于这个项目它应该严格存在于哪个层级之中这样的思路进行设计,而是根据用户的需求,如何将这个项目合理的分类于最适合的集合之中
这是一个立足于外观的点,根据大量的案例分析和眼动测试,目前市面上最为常见的按照信息权重布局的导航可分为:横向式、纵向式、纵横式,由于这部分我们不展开说,所以直接在上图整理了每种布局的特征、优劣势和应用场景
知道了上面的分类和注意事项之后,下面我们用一个具体案例来对导航的交互层面设计进行一个深度体验(因为此内容十分精彩也涉及到机密,所以不在这里做具体展示,以示意的方式来叙述),总共分为六步,看看这是否也是你工作场景中比较头疼的呢
需要搞清楚导航项的定义是因为导航项的定义决定了你的目标界面是什么,所谓的目标界面就是导航所引导你到的哪一个分类的信息处
所以我们首先先来整理一下导航中每个导航项的界面定义,这也是我们日常工作中对导航梳理十分重要的一步
当问题被罗列出来之后我们就会自然而然的产生各种各样的疑问,比如导航分类之间存在有的存在流程上的关系,但是有的分类却并不属于流程,这是为什么呢?再比如有的导航分类和导航项之间名字一样但内容却不一样这又是为什么呢……(想一想这是不是我们工作中也经常遇到的疑问呢)这都是后面我们需要去优化的地方
保留住上面的问题,我们来做第二步,这一步我们需要搞明白用户的使用路径,因为这样我们可以很好的给任务类产品做一级分类
通过基于不同角色的用户体验地图我们可以得出不同的用户操作路径,于是便可以很顺畅的得出这一套操作流程的大框架
基于业务中的任务链路推导出每一步的操作路径,于是我们就可以将用户的操作路径就可以提炼为一级导航
得出了一级导航,下面我需要角色的权限进行一下区分,这也是B端产品的必备属性
于是我们为每一个导航项进行了角色权限的梳理对应,那么一级导航中每个导航分类所对应的角色也瞬间一目了然,这里面多说一句,当用户用不同权限的账号登录产品时,能看到不同的内容这才是一个优秀的拥有权限设计的导航
到了这一部分对于一些完全没有接触过数据的同学来说理解起来可能会一些难度,我们首先需要知道的是:“相同的数据来源,可以帮我们区分界面性质,而且相同的数据来源,往往会有一组相同的界面来围绕”
在此需要记住三个概念:
1.元数据:数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能,例如一件商品、一个客户
2.记录集:指定数据库中检索到的数据集合,例如订单列表、发货列表
3.关系列表:对来描述对象和对象的关系,比如你和我是好友,你和我在同一个企业微信群
于是我们为导航项进行数据性质的区分归类,也就是说相同数据类型的实体往往围绕着某个元数据并且包含系列的界面,当我们这里整理完后发现,相同数据性质的实体(这里可以理解为导航项)貌似可以归类在一起,这是我们作为分类的一个依据
根据相同的数据性质将导航项归入应该归入的二级导航中,此时不妨和最初的版本进行对比,我们的一级二级导航相对而言已经通过改版清晰了很多
这一步其实是比较好理解的,很简单的法则:“高频次高优展示,低频次降低权重甚至隐藏”这是针对于二级导航中每个导航项的排布进行的设计。这里不妨把频次由高到低量化成为:实时关注、每天关注、每月关注、很少使用、极少使用这个几个概念,分别用五角星、三角形、矩形、圆形、菱形进行代表
而关于使用频次的高低甄别一般我们可以通过用户调研和数据埋点的两种常用方式来进行,这里并不展开讲
于是我们可以将使用频次作为一列新的参考放入导航项的表格中,瞬间清晰明了
根据使用频次调整每个导航项的顺序
这一步涉及的就是外观了,不妨回顾一下2.8中对于导航的三种常见布局,根据产品的操作复杂程度等综合需求,我们选择了第二种形式成为最终形式
文章来源:站酷 作者:核糖bro
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
做中后台产品的设计,基本都逃不开导航布局这个大框架。
基于用户的 Z 字形扫描行为,重要的导航应当选择左侧导航或顶部导航。
可是横着竖着有那么大差别吗?被人问道为什么这么选择,该如何回答?
今天给大家些灵感,从以下四个角度分析一下:
JR Kingsburg 曾经做过一次实验(A comparison of three-level menu navigation structures for web design),研究 3 层导航中,哪种组合使用效率更高。
这三层中,每一层都有横向和纵向两种可能性,所以实验总共有 2×2×2=8 种对照组:
他为这 8 种导航布局做了不同电商原型,让用户来买东西,并记录各种数据,结果发现了很多有意思的数据:
综合这些数据,看起来整体表现较好都是「左上上」、「左左上」、「左左左」。
科学虽然很严谨,却缺乏灵活度,例如本次试验的场景单一(电商购物),而且用来测试的界面未免也太简陋了吧!
所以我们再从其他角度思考看看。
从占据面积的角度来看,横向导航比纵向导航省地方,因为只要细细一条就好了。
然而,选项数量不多时横向是可以;选项多起来,横向导航就很拥挤了。
毕竟纵向导航方便滚动,横向导航很少有用户会尝试滚动查看的,「…」也不是什么方便的操作。
所以,如果确定选项少可以选横向,不确定或者数量多建议保险起见选纵向。
任何导航,都要占据屏幕不少空间,这对尺寸适配都是一件麻烦事。哪怕产品并不需要为移动端做响应式布局,只要是网页端,就得考虑窗口尺寸的变化问题。因为设计师的 Mac 和大量用户的 PC 甚至平板电脑之间,展示上的差异真的不小。
横向导航占据空间最小,同时也是最难做尺寸适配的。尤其是如果上面除了导航之外,还放有各种 logo、头像、图标、搜索…各种东西时。横向导航一般都有三种状态:展开、折叠和收起。但是纵向导航就简单了,只需要两个状态:展开和收起。顶多再让展开状态的宽度能够自适应变化或手动拉伸就差不多了。
这么看来,如果产品需要考虑很多不同尺寸适配的问题,纵向导航是最简单的选择,除非横向导航的内容不多维护起来不麻烦。
我之前为了研究确定按钮放在左边还是放在右边好,做了一系列实验分析,结果得出超出我预期的结论…放哪都没多大问题,统一就好。于是,我想这个问题也可以类比一下。
大部分网站都是横向导航,所以说如果产品是以网页版为主,且用户会经常穿插跳转使用其它网页,那么也使用横向导航比较符合习惯。
而无论 PC 还是 Mac,系统页面的导航在左侧的情况比较多,所以说如果产品是系统软件的话,纵向导航比较符合习惯。
然而,更更更更更重要的是,千万不要同一个产品不同端或不同子系统的导航不一样!用户很可能一会儿用这个,一会儿用那个,结果操作习惯换来换去,人都弄晕啦!还有,就是改版换导航肯定要让老用户不满,好不容易养成习惯改起来容易吗?所以说,决定导航布局时还是要谨慎才好哦。
文章来源:优设 作者:体验进阶
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
前言
在企业工作中,每一个问卷调研都始于一个商业问题,问卷的质量也决定了最终结果是否能对业务起到帮助。本文将从定义问题-问卷设计-数据清洗与分析-报告撰写这四个基本步骤相对完整地阐述企业问卷调研,希望可以给大家提供一些研究方法上的思路。
定义问题:情境分析法(SCQA)
在商业问题解决的过程中,既有公司内部的因素,也有外部行业的因素,影响因素错综复杂;周围的环境也比较容易发生变化,具有很大的不确定性;同时又要保证解决方法的可落地性,产生实际的价值。相对来说,会比较复杂。在进行问卷设计之前,更有必要的是将问题梳理清楚,再决定是否采用问卷这种方式。
1.1 结构化思考:使用SCQA描述项目
SCQA是将不确定性考虑在内,一种结构化的问题分析方法,可以比较好地系统思考、查漏补缺。它包含四个环节:
情境(Situation):由大家都熟悉的现状或事实作为起点,包含对象、所处阶段等
冲突(Complication):实际情况往往和我们的目标有冲突,颠覆了稳定的状态。说出行动的原因,包含威胁、机会和等着我们去克服的困难点
问题(Question):基于冲突提出问题,要怎么解决这个困难点
回答(Answer):我们的解决方案是什么,定位出需求点
1.2 如何洞悉情境和冲突:搞清楚为什么做调研
假设我们拿到上述案例作为调研项目,可以有两种方式去进行洞悉情境和冲突:
一是思考为什么要做这个研究;二是跟相关利益者访谈尽可能多地获取信息。
1)思考为什么要做这个研究:
- 需要回答什么问题?
- 为什么回答这些问题很重要?
- 打算如何使用最终的调研结果?
2)跟相关利益者访谈:
- 核心业务方是谁?其他业务方是?
- 每个业务方的关注点是什么?难点是什么?
- 各个相关方的目标之间是否冲突,是什么冲突?
根据上述方法,可以得到对应的情境和冲突:
情境:目前有三种产品方案A/B/C,分别对应的价格为100元/1000元/10000元。通过上述思考和信息了解,会知道这个事情和谁有关,在这个事件中承担什么角色。
冲突:B的销量不佳,跟其他方案差异不明显,瞄准客群很有可能有重叠,未成交客户难转化,希望可以方案B进行调整。在用户层,可能其他方案中的功能能满足需求,不需要购买方案B;在公司层,整体收入结构可以更优化、健康;在业务层,系统和流程可能不太合理,有些可能需要重构。
1.3 问题拆解其实是建立一个假说/逻辑树的过程
我们可以将问题进行拆解,拆解应遵循MECE原则(相互独立且完全穷尽),这么做的好处是可以把问题进行逐层分解,逐级分析,最大可能保证需要考虑的因素全面不遗漏。
案例中的问题,可以从用户方面、竞品方面、成本/利润方面进行拆解,针对每一个层面的问题又可以进行拆分。
对问题进行细致拆分之后,针对每个问题有不同的解决方案,有一些问题可以用问卷来解决,有一些问题需要使用其他方式进行解答。
问卷并不能解答所有问题~~
问卷设计
2.1 问卷的用途:定量为主
一般通过问卷来进行大样本的数据收集,主要以用户的基础数据、行为数据和态度数据为主,既可以作为独立的调研项目,可以跟其他方式进行结合,比如说结合访谈、结合企业内部的数据,本文比较推荐的方式是多种方式结合进行交叉验证,提升调研结果的可靠性。
2.2 问卷设计的原则
基于第一部分的定义问题阶段,已经对问题进行了分析,在此基础之上,我们需要确定哪些问题可以由问卷进行解答,并明确问卷的研究目标与参与对象。特别地:利益相关方(项目组成员间)在项目前期应该达成统一,避免后续产生分歧,付出额外的沟通成本不说,还有可能相互甩锅。
2.3 问卷的基本结构
一份问卷的基本结构包含标题、招募语、甄别题、主问卷、用户基本特征、结束语。
2.4有逻辑的设计问题
一份有效的问卷需要从如何提问、如何措辞、如何设置答题逻辑、如何设置题目选项这些方面去考虑,设置有效的问题。以下是问卷设计中的一些基本原则:
2.5 提升回复率的tips
个性化:在说明信件/邮件或邮件开头注明回复者的名字、研究活动的目的、所需时间。向回复者强调他们反馈信息的重要性。需要注意的是,这里出现信息错误,会降低回复率。
控制篇幅:问卷完成时间不要超过10分钟,注意控制问题数量,避免出现需要大量思考、较难回复的题型。
用户激励:奖励参与者油卡/现金红包/优惠券等,昂贵的激励物没有特别显著提高回复率,所以小的激励就可以。
数据清洗与分析
3.1 数据清洗原则
剔除有效范围外的数据:排除异常作答时间值(比如作答时间为10秒),判断为作答不认真。可以根据题项来确定,一般10道题设置筛选出60秒之内的问卷。
剔除连续重复值:在时间范围内,再核查问卷是否出现连续重复值,出现的问卷予以删除。如果问卷数量较大,可以使用STATA软件编码或Excel条件函数判断进行处理。
剔除违背逻辑一致性的数据:在时间范围内,核查问卷是否存在前后逻辑不一致的题,比如总体满意度打分为非常满意,但后续题目都选择了非常不满意。
剔除有缺失值的数据:严格来说应该将有缺失值的用户予以删除,但有时候回收样本量没有那么大,则可保留。
3.2 数据分析方法
数据分析方法有非常多,要在众多的分析方法中选择一种也是比较难的事,无论选择什么样高大上的方法都是其次,最重要的是选择的分析方法能说明问题,能体现数据的价值。
比较分析是一个简单的、比较通用的、易于理解的数据分析方法,可以分成趋势分析、特征重要性、分组分析三种。
报告撰写
最后,条理清晰地展现数据信息,表达你的观点。报告写作的过程是一个相对费劲的过程,特别是数据量多的情况下,总是觉得还有一些数据价值没有被挖掘出来,但此时不要拘泥细节,细节可以回头再补,会大大提升效率。
4.1 问卷的报告框架
报告主要发现:将总结放在最前面,阅读者可以通过简短的总结大致了解报告观点,方便他们决定是否需要继续了解详细内容
目录和分目录:报告包含的内容组成部分,让阅读者对报告内容有初步概览
调研背景和目的:陈述整个报告的背景和目的,对调研的范围进行必要说明
单页-详细内容描述:有逻辑的描述项目的发现,总结数据表现,挖掘价值
单页-详细内容描述示例:
问卷调研不止是问卷本身,还包括前期项目组沟通、项目成员分工与配合、后续结果推广、结果推动落地等,前期做好项目组沟通、明确项目分工,建立一个清晰的运行机制,有利于项目组成员对结果的认同,后续也有清晰的路径去分工解决问题。所以,每一个环节都体现工作的价值,都同样重要。希望大家在关注研究方法提升的同时,也可以更多关注更多工作方法提升。
文章来源:站酷 作者:酷家乐UED
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
function _getValue(target, valuePath, defalutVal) {
let valueType = Object.prototype.toString.call(target)
console.log(valueType)
// if (valueType == "[object Array]") {
let paths = valuePath.replace(/\[(\d+)\]/, `.$1`).split('.')
let result = target
for(const path of paths){
result = Object(result)[path]
if(result == undefined){
return defalutVal
}
}
return result
}
测试:
let obj = {
a:{
b:[
{
c:2
}
]
}
}
console.log(_getValue(obj, 'a.b[0].c')) //2
function isEqual(res1, res2) {
let a = getTypeOf(res1)
let b = getTypeOf(res2)
if(a !== b){
return false
}else if(a === 'base'){
console.log('base',res1,res2)
return res1 === res2
} else if(a === 'array'){
if(res1.length !== res2.length){
console.log('array',res1,res2)
return false
}else{
//遍历数组的值比较
for(let i =0;i<res1.length;i++){
if(!isEqual(res1[i],res2[i])){
console.log('array',res1[i],res2[i])
return false
}
}
return true
}
return true
}else if(a === 'object'){
let ak = Object.keys(a)
let bk = Object.keys(b)
if(ak.length !== bk.length){
return false
}else{
for(let o in res1){
console.log(res1[o])
if(!isEqual(res1[o],res2[o])){
console.log('object',res1[o],res2[o])
return false
}
}
return true
}
}else if(a === 'null' || a === 'undefined'){
console.log('null')
return true
}else if(a === 'function'){
console.log('function')
return a === b
}
}
function getTypeOf(res) {
let type = Object.prototype.toString.call(res)
switch (type) {
case "[object Array]":
return 'array'
case "[object Object]":
return 'object'
case "[object Null]":
return 'null'
case "[object Undefined]":
return 'undefined'
case "[object Number]"||"[object String]"||"[object Boolean]":
return 'base'
case "[object Function]":
return 'function'
default:
return 'typeError'
}
}
测试:
let a = {
a:20,
b:{
c:30,
d:[1,2,3]
}
}
let b = {
a:20,
b:{
c:30,
d:[1,2,3]
}
}
console.log(isEqual(a,b)) //true
function _flat(arr){
let result = []
for(let i = 0;i<arr.length;i++){
if(Array.isArray(arr[i])){
result = result.concat(_flat(arr[i]))
}else{
result.push(arr[i])
}
}
return result;
}
let arr = [1,2,[3,4,[5,6]]]
_flat(arr) //[1,2,3,4,5,6]
//es6
function _flat2(arr){
while(arr.some(item=>Array.isArray(item))){
arr = [].concat(...arr)
}
return arr
}
let arr = [1,2,[3,4,[5,6]]]
_flat2(arr) //[1,2,3,4,5,6]
简单深克隆,不考虑内置对象和函数
function deepClone(obj){
if(typeof obj !== 'object') return
let newObj = obj instanceof Array?[]:{}
for(let key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = typeof obj[key] === 'object'?deepClone(obj[key]):obj[key]
}
}
return newObj
}
复杂版深度克隆 考虑内置对象 比如date regexp 函数 以及对象的循环引用的问题
const isObject = (target) => typeof target === "object"&& target !== null;
function deepClone2(target, map = new WeakMap()) {
console.log(target)
if (map.get(target)) {
return target;
}
// 获取当前值的构造函数:获取它的类型
let constructor = target.constructor;
// 检测当前对象target是否与正则、日期格式对象匹配
if (/^(RegExp|Date)$/i.test(constructor.name)) {
// 创建一个新的特殊对象(正则类/日期类)的实例
return new constructor(target);
}
if (isObject(target)) {
map.set(target, true); // 为循环引用的对象做标记
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = deepClone(target[prop], map);
}
}
return cloneTarget;
} else {
return target;
}
}
filter去重
function _unique(arr){
return arr.filter((item,index,array)=>{
return array.indexOf(item) === index
})
}
es6 Set
function _unique2(arr){
return [...new Set(arr)]
}
includes
function _unique3(arr){
let newArr = []
arr.forEach(item => {
if(!newArr.includes(item)){
newArr.push(item)
}
});
return newArr
}
双层for循环
function _unique4(arr){
for(let i =0;i<arr.length;i++){
for(let j =i+1;j<arr.length;j++){
if(arr[i] === arr[j]){
arr.splice(j,1)
j--
}
}
}
return arr
}
indexof
function _unique5(arr){
let newArr = []
for(let i = 0;i<arr.length;i++){
if(newArr.indexOf(arr[i] === -1){
newArr.push(arr[i])
})
}
return newArr
}
function _typeOf(obj){
let res = Object.prototype.toString.call(obj).split(' ')[1]
let mold = res.substring(0,res.length-1).toLowerCase()
return mold
}
_typeOf(5) //number
_typeOf('5') //string
function getParamsObj(params){
let paramsStr = params.replace(/^.+\?(.+)/,"$1")
let paramsArr = paramsStr.split('&')
let paramsObj = {}
for(let [key,value] of paramsArr.entries()){
if(/=/.test(value)){
let valArr = value.split('=')
val = decodeURIComponent(valArr[1]) //解码
val = /^\d+$/.test(val)?parseFloat(val):val //判断是不是数字
if(paramsObj.hasOwnProperty(valArr[0])){
paramsObj[valArr[0]] = [].concat(paramsObj[valArr[0]],val)
}else{
paramsObj[valArr[0]] = val
}
}
}
return paramsObj
}
//从一次传入多个参数 编程多次调用每次传入一个参数
function add(a, b, c, d, e) {
return a + b + c + d + e
}
function curry(fn) {
let dFn = (...args)=>{
if(args.length == fn.length) return fn(...args)
return (...arg)=>{
return dFn(...args,...arg)
}
}
return dFn
}
let addCurry = curry(add)
addCurry(1,2,3)(2)(3)
//添加了两个功能
// 图片加载完成后 移除事件监听
// 加载完的图片从imgList中移除
let imgList = [...document.querySelectorAll('img')]
let length = imgList.length
const imgLazyLoad = function () {
let count = 0
let deleteIndexList = []
imgList.forEach((img, index) => {
let rect = img.getBoundingClientRect()
//获取元素到视图的距离 top元素上边到视图上边的距离 left元素左边到视图左边的距离 right... bottom...
if (rect.top < window.innerHeight) {
// img.src = img.dataset.src
img.src = img.getAttribute('data-src')
deleteIndexList.push(index)
count++
if (count === length) {
document.removeEventListener('scroll', imgLazyLoad)
}
}
})
imgList = imgList.filter((img, index) => !deleteIndexList.includes(index))
}
imgLazyLoad()
document.addEventListener('scroll', imgLazyLoad)
图片懒加载:https://juejin.cn/post/6844903856489365518#heading-19
函数防抖 触发高频事件 事件在n后执行,如果n秒钟重复执行了 则时间重置
//简易版
function debounce(func,wait){
let timer;
return function(){
let context = this;
let args = arguments;
console.log(timer)
clearTimeout(timer)
timer = setTimeout(function(){
func.apply(context,args)
},wait)
}
}
let btn = document.querySelector('button');
function aa(){
console.log(111)
}
btn.onclick = debounce(aa,2000)
// 复杂版
// 1.取消防抖
// 2.立即执行功能(点击之后立即执行函数 但是 wait时间之后在点击才能在立即执行)
// 3.函数可能有返回值
function debounce(func,wait,immediate){
let timer,result;
const debounce = function () {
const context = this
const args = arguments
if(timer) clearTimeout(timer)
if(immediate){
console.log(timer)
var callNow = !timer
timer = setTimeout(function () {
timer =null
},wait)
if(callNow) result = func.apply(context,args)
}else{
timer = setTimeout(function (params) {
result = func.apply(context,args)
},wait)
}
return result
}
debounce.cance = function () {
clearTimeout(timer)
timer=null
}
return debounce
}
let btn = document.querySelector('button');
function aa(){
console.log(111)
}
btn.onclick = debounce(aa,2000,true)```
函数节流 触发高频事件 且n秒只执行一次
//使用时间戳
function throttle(func,wait) {
var context,args;
var previous = 0
return function () {
context = this;
args = arguments;
let nowDate = +new Date()
if(nowDate-previous>wait){
func.apply(context,arguments)
previous = nowDate
}
}
}
//定时器
function throttle(func,wait) {
var context,args;
var timer;
return function(){
context = this;
args = arguments;
if(!timer){
timer = setTimeout(function () {
timer = null;
func.apply(context,args)
},wait)
}
}
}
//组合版 options.leading 为true 立即执行一次 options.trailing为true 结束之后执行一次 默认为true function throttle(func, wait ,options = {}) { var context, args, timer,result; var previous = 0; var later = function () { previous = options.leading === false ? 0 : new Date().getTime(); timer = null; func.apply(context, args) if (!timer) context = args = null; } var throttle = function () { var now = new Date().getTime() if (!previous && options.leading === false) previous = now; context = this; args = arguments; //下次触发 func 剩余的时间 var remaining = wait - (now - previous); if (remaining <= 0 || remaining > wait) { // if (timer) { // clearTimeout(timer); // timer = null; // } previous = now; func.apply(context, args); if (!timer) context = args = null; } else if (!timer&& options.trailing !== false) { timer = setTimeout(later, remaining); } } throttled.cancel = function() { clearTimeout(timer); previous = 0; timer = null; } return throttle } function aa(e) { console.log(111) console.log(e) } let btn = document.querySelector('button'); btn.onclick = throttle(aa, 2000,{ leading:false, trailing:true
})
转自:csdn论坛 作者:Selfimpr欧
移动互联网的迅速崛起,让移动网页,移动客户端越来越重要,客户端的页面设计也是一门很大的学问。科技迅速发展的今手机屏幕的尺寸越来越放大化,但却始终 很有限,因此,在APP的界面设计中,精简是一贯的准则。这里所说的精简并不是内容上尽可能的少量,而是要注重重点的表达。在视觉上也要遵循用户的视觉逻 辑,用户看着顺眼了,才会真正的喜欢。
接下来为大家分享精美的app UI设计案例:
icon的设计会贯穿全套设计稿,所以在设计的环节中必不可少,优质的icon设计会帮助品牌和企业更好的树立形象,形成自己的设计语言。
接下来为大家分享一些经典案例:
--手机appUI设计--
--icon图标赏析--
更多精彩文章:
据中国天气网微博预报,大风和沙尘已经到达北京西北部边界,即将开始影响北京。
此前报道:
大风携裹沙尘已到河北张家口,傍晚前抵京
北京市气象台刚刚预报,目前,大风携裹着沙尘,已经影响到河北西北部张家口地区,未来继续向东南推进,下午自北向南影响本市,预计傍晚前影响北京大部。
根据预报,今天下午至前半夜本市有沙尘天气,最低能见度6公里左右。随着中午前南风增大,下班前转北风,沙尘下午就影响北京了。明天接着还有大风天气,但沙尘影响不会持续。
气象部门表示,由于上游土壤湿度较3月份增加,加之降水的抑制作用,此次沙尘强度明显弱于3月15日和28日的沙尘暴过程。
根据北京市生态环境监测中心的实况,目前全市空气质量已经达到轻度污染水平。
针对此次天气过程,北京市气象台已于14日10时30分发布大风黄色预警信号、16时30分发布沙尘蓝色预警信号。市森防办与市气象台已联合发布森林火险橙色预警。(来源:北京日报客户端记者 骆倩雯)
注意!沙尘已到内蒙古中部 可能影响北京晚高峰
今天(4月15日)上午9点半左右,今年第三次蒙古气旋东移带来的沙尘天气已经抵达内蒙古中部,并正在向东南移动。今天傍晚前后可能影响到京津冀一带,或对北京晚高峰造成影响。
据气象北京微博消息,今天上午9点30分前后,沙尘天气已经抵达内蒙古中部,并正在逐渐向东南方向移动,内蒙古、甘肃、宁夏等地风沙渐起。
↑内蒙古鄂尔多斯市今天上午已经出现明显沙尘天气。(摄/赵建军)
据中国天气网首席分析师胡啸介绍,预计今天下午,这股沙尘将会逐渐自西向东影响京津冀一带,北京平原地区午后也会逐渐加大,风力普遍可达4~5级,阵风8~9级,伴有扬沙天气,晚高峰可能是核心影响时段,公众出行需关注临近预报,做好防风防沙准备。
此外,据北京日报客户端消息,北京市教委已建议停止全市大中小学校、幼儿园、中等职业学校及校外教育机构停止体育课、升旗、早操、课间操、运动会、体育考试、外出社会实践等室外活动。提醒学生注意安全,减少不必要的外出活动。各单位要加强巡视巡查力度,及时消除各类安全隐患。(来源:中国天气网)
今天还是一篇非常干货的原创文章。
内容分为两点:
图标的基础特征
动手设计之前,咱们先对完整的图标集进行分析。
弄明白在画整体的系统图标集合时,各个图标得具备哪些特征,有哪些切入点,可以作为我们在实际绘制时候的依据。
先来看几组 iconfont 的案例,看不太清的同学可以戳图片放大。
围绕上面这些案例,咱们可以归纳出图标的几点设计原则。比如:
1. 设计图标需要考虑延续性,图标之间互相牵连影响
图标几乎不会以单个的形式出现,大多数都是以组归类。符号整体性与统一性,都是依靠单个 icon 的共性特征建立起来的。
比如 iconfont 中的这组icon,图标圆形的外轮廓,就保持了一致。其次用户头像的代表符号,也很好保持了延续性。
正是这种小特征,共同组成了图标库的整体特征。
2. 设计手法趋同、图形内容差异
第二点好理解,设计风格、手法要素需要统一,但是内容传达的差异必须要拉开,避免图形趋同导致功能混淆。
比如下面两个案例,由于过于相近,导致用户很难理解图标含义,是天气,还是设置按钮,这种情况我们在设计时需要极力避免。
总结来说,就是图标的共性往往体现在设计手法上,比如颜色、形状粗细、细节的一致性,这些都是设计风格的统一。
而图标的特性,往往体现在形状内容差异,形状会决定图标的信息传递含义。所以共性要趋同,特性要拉开,这个是设计图标集的基本原则。
3. 功能大于形式,图形能理解的情况下样式越简洁越好
不知道大家是否关注,曾经在设计圈风靡一时的MEB图标风格,产品圈却非常冷门,几乎没有产品在继续用这种风格作为功能性质图标。
△ 该作品来自于网络图片,仅作交流使用
因为虽然图标增加了小装饰后,显得有趣精致,但其实也增加了图标的识别难度以及识别效率,反而背离了图标的设计初衷。
所以对于系统功能图标而言,必要的简洁性,高效的识别率,才是关键。
图标的设计约束性
聊完了设计主张及基本的特征。接下来咱们开始剖析图标的设计细节,包括分析制定图标的系统设计规范,应该从哪些方面入手。
规范的第一点,就是图标的基础形状比例。这个比例,主要是约束长与宽,共包含了四个关系,分别为「正方形 : 横矩形 :竖矩形 :圆形」
这四个关系的约束,会让图标集里的所有图标大小,看起来是一致的、统一的。横矩形、竖矩形这两个比例,会决定整套图标的饱满程度,横竖比例越一致,图标整体越饱满。
这点大家可以自己斟酌,如果是泛娱乐型的产品,icon可以更饱满一些。如果是偏工具化产品,那么还是可以优先保障图标的识别度,饱满程度倒是其次。
圆润饱满型:
刚正工具型:
定了比例后,接下里就是对图标的细节刻画。对于线性图标而言,最重要的细节就是线条粗细;对于面性图标而言,最重要的就是正负形之间的间距。
所以这些核心元素,在图标的核心线条、核心区域部分,间距样式都应当保持统一。
通常在移动端@2x内,主流icon的粗细为3px,而4px大多数都是为功能性导航icon,细一点的图标通常看起来会更精致一些。
当然也有部分产品使用的是2px,比如新版的YouTube,其次还有些较为复杂的icon,单根粗细的线段不一定能满足其需求,所以还需要制定一条副线的粗细。
细节可以根据产品的调性来定,统一即可。
大比例跟基本元素确定后,也可以制定一些图标的个性化元素规范,比如图标的圆角大小、角度位置,等一些特殊的样式。
像这些个性化的规范,颗粒度可以Case By Case来定义,圆润还是方正,可以根据产品的视觉风格来定义就好。
这些规范样式定好,就可以充分的让图标集内的图标,从设计上是保持一致的,且具有特色感。
上面讲了关于图标的分析及规范。为了方便大家掌握,接下来咱们就来讲讲,具体动手做,流程是什么样的。这里我给个我的步骤作为参考:
第一步:绘制好图标基本网格
第一步,当然是确定好图标icon的大小,以及上面我提到的基本尺寸比例,四个关系「正方形 : 横矩形 :竖矩形 :圆形」的约束,构建好基本骨骼。
我这里以图标容器大小为 56×56,预留8px安全间距,图标最大大小为 48×48。
由于视差关系,圆形在图标里面的尺寸是最大的,所以圆形的大小为48×48。因为我想图标饱满一些,所以正方形的大小我两边各减去2,为42×42。
然后再绘制出横矩形(48×36)与竖矩形(36×48),各线段之间的间距保持一致。
然后各个形状居中对齐,这样四个关系「正方形 : 横矩形 :竖矩形 :圆形」定好后,基本的容器就制定好啦。
第二步:设定图标基本规范
接着制定好图标的基本规范,为了方便大家看得清,我这里设定图标的线条粗细为3px,圆角为6px,干净简洁一些,让它看起来更饱满。
角度、断点啥的,我这里就不定义了,因为只是示例给大家看,讲一下流程,所以尽可能简单一些。大家在做练习的时候,也可以尝试自己去定义一下。
第三步:绘制图标
好了后就可以开始绘制图标啦。我这里分别绘制十五个,作为示例
然后就是使用路径工具,根据创意去绘制完善图标了。绘制的过程中,也可以不断调整,让图标看起来更协调,更饱满,更容易识别。
花了十五分钟左右,简单的十五个图标草稿就画好了,接下来咱们开始调整细节。
第四步:整体性调整
所有的图标绘制好了后,咱们就可以整体性的开始打磨细节,把图标形状的一些折角处、大小样式调整一致,让图标的节奏更清晰,整体样式更统一。
这样一组精致的系统icon就绘制好啦。
接着咱们也可以加点特色风格进行尝试,比如填充一个颜色。
当然细看的话,图标部分细节还是有点糙,其实还可以再调调,但这个主要做示例用,大家自己在做练习的时候,可别像我一样偷懒嗷
上面讲了很多方法经验,文末给大家来点实际的。
我珍藏了很多较为不错的大厂图标集合库,日常在画图标没灵感的时候,就会打开看看这些,参考一下。
文件都是矢量格式的,编辑方便,还很全面。今天拿出来送大家白嫖了
文章来源:优设网 作者:UX小学
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
“色彩是我们感知世界的重要媒介,对于信息传达有着重要的作用,能使人们能够更有效的感知设计的意图和内涵,使传达更高效。且人对色彩的视觉感知与想象能力,能够指导人做出预测、理解和决策。”
— lyft kevyn arnott
随着世界的数字化转型进程大爆发,科技把每一张有形的办公桌移到了云端,用户沉浸在数字构建的世界中。腾讯文档作为先进的生产力工具,产品生态越来越多元丰富,多品类多终端的复杂环境展现在我们面前,开始真正的朝复杂庞大的大规模设计迈进。我们希望能以更加专业、高效的设计姿态迎接腾讯文档的未来挑战。
色彩是体现品牌与基因的关键因素,构建科学高效的色彩系统,建立产品的品牌形象,对产品设计极具指导意义。
腾讯文档在色彩上也进行了一些深入的挖掘和沉淀,一方面希望带给用户全新的品牌印象和认知,另一方面构建科学有效的色彩系统,为产品的发展提供优质高效的设计系统基础。本文将聚焦于色彩系统的构建。
腾讯文档代表着效率协作的先进生产力,从云端创作到云端协作,打破了办公空间的实体界限。我们希望,新的品牌色,能够为腾讯文档塑造更加有未来科技感及智慧感的视觉感受和认知。
我们将标准色由平静的天蓝色,升级为更加生动、进取、科技、可靠的明亮清澈的钴蓝色。这种蓝色具有更多的电子意味,蕴含了更多的活力和想象力,承载了腾讯文档对未来数字世界新挑战的态度和形象的进化。
同时我们认为灰色在腾讯文档的色彩系统中起着至关重要的作用,为产品界面创造结构、表达边界、建立信息层次。我们将灰色赋予了统一的品牌认知感受,将蓝色加入到中性灰色里,生成了腾讯文档特有的蓝灰色。
至此,腾讯文档标准色进化升级,它体现了腾讯文档对可靠稳定的技术、产品体验的追求,以及对未来智能的数字世界的不断创新和进取,蕴藏着无限的可能性。
在一个科学有效的色彩系统里,往往包含至少两种色彩:主色+辅助色,两者互相搭配组合成产品体系的整体色彩感受,减少用户在产品体验中对反复出现的主色的视觉疲劳。
腾讯文档的产品生态愈来愈丰富多元。我们拥有多品类的产品,为用户提供了丰富的产品功能,其中云端协作、文档资产的沉淀管理是腾讯文档的非常重要的能力,在线文档、在线表格、在线幻灯片、在线收集表、在线思维导图、在线流程图以及文件夹等的品类图标,又是用户在对文档进行协作分享及沉淀时,识别不同类型文件的关键因素。基于此,腾讯文档相较于其他产品需要更多的辅助色。
于是,如何有效的选择既符合品牌调性又有区别度的辅助色是构建腾讯文档色彩系统的关键。在辅助色选择上,我们以邻近色、互补色、对比色为主要方法构建了辅助色彩体系。
1. 创建色相色板,保持相同明度、相同饱和度
我们以腾讯文档标准色#1E6FFF(H 218 S 88 B 100) 为起始点,S(饱和度)、B(明度)保持不变,H(色相)以 218°为起点,以 15°为增量或减量标准,生成 24 色色板。这个色板是我们选取辅助色的重要依据。
2. 以邻近色、互补色、对比色为原则选择丰富的辅助色彩
为了保持腾讯文档的基础品牌调性,并保证其具有极清晰的识别度,我们以品牌蓝色为起点,选择了相对较多的邻近色,以保证在色温上保持腾讯文档整体色调的清爽感。并利用对比色及互补色,选择更加丰富多元的色相,以保证能够满足各种使用场景下对色彩的需求。
总的原则是利用邻近色构建有质感、品牌感的色彩家族,利用对比色及互补色扩展色相,以制造更强烈的色彩对比,满足一些冲突性场景。
3. 校正辅助色
虽然我们保持相同的饱和度和明度,使用科学的方法得到了较为合适的色相,但由于色彩本身自带感官明度属性,导致在视觉感受上的感官体验并不同频。
黄色、绿色的明度即发光度较高,蓝色就稍微偏暗一些,导致色板看起来不一致。为了让不同色相看起来更加协调,需要调整色板的明度和饱和度,以保证视觉感官体验同频且更加和谐舒适。
校正原则:
校正后我们得到了清澈明亮、清晰易分辨的腾讯文档的主色+辅助色。并且针对视障群体进行了色彩测试。
灰色是产品体验设计中至关重要的一节,工具型产品大部分是由各种各样的容器、面板、列表组成。灰色为产品界面创造结构、表达边界、建立信息层次,保持舒适的对比度是提高可读性和吸引用户注意力的关键。
前面我们已经定义了腾讯文档的蓝灰色,在界面的设计中,我们将其与中性的灰色结合,共同构建灰色的色彩体系 。
腾讯文档蓝灰色相扩展:
中性灰色色相扩展:
为构建一个高效易用的灰色调色板,我们将蓝灰色彩作为 Y 轴,有透明度的中性灰色作为 X 轴,两者透明度保持一致,建立起腾讯文档有梯度的、丰富的灰色调色板。
对比度是否合理是阅读体验是否舒适的重要评价维度,过高或者过低的对比度都会影响阅读体验及识别度。下图是对比度的钟型曲线图,随着对比度的增加,舒适度和识别度都在上升,但一旦超过一个界点,对比度越增加,识别度和友好度亦会逐步下降。
为保证视障用户的使用,保证足够的对比度,遵守 WCAG 2.0 的标准,我们对调色板灰色的对比度进行了可用性测试,以指导腾讯文档体验设计中灰色调色板的使用。
是:对比度在 AA 标准以上,符合 W3C 标准,可以使用。
中:仅可用于 disable 状态。
否:对比度在 AA 标准以下,不符合 W3C 标准,不可使用。
定义好文档的主色、辅助色以及中性色后,我们需建立完整的调色板来满足不同场景下颜色的使用。以传达品牌精神,建立色彩层级,或传达信息,或强化界面层级。
在色彩系统中,很多产品使用 Tints and shades 系统,通过在颜色上面增加白色,或者增加黑色,来改变它的明度和饱和度,形成同色系的调色板。但这种方法得到的调色板往往比较刻板僵硬,故腾讯文档采用了另一种方式,将已生成的灰色色板与色相叠加,在符合无障标准的区域,选择不同明度饱和度的色彩,形成有梯度、有层级的彩色调色板。
Tencentdocs_blue:
生成主色-蓝色色阶:
用同样的方法将辅助色生成色阶:
现在,我们有一个梯度丰富,能够支持腾讯文档设计系统的调色板了~
实际案例
实践才是硬道理,我们尝试以这个调色板为指导来调整优化腾讯文档链接色的优化调整。
为保证用户阅读体验的舒适度,链接之类的彩色文本,要求颜色在背景下可以达到 4.5:1 对比度以上,以使它能够清晰的从灰色文本、背景中脱颖而出。于是,我们放弃了品牌蓝_1E6FFF,选择了品牌蓝 70_175CEB 作为链接色。
以后,选择颜色,so easy~
这个长长的制作调色板的故事就要结束了,我在这项工作中,重新审视过去设计中的设计决策方法,在其中学到了很多东西,希望本文对您也有所帮助。
我们经常快速的动手,依靠主观情感去选择颜色,在刚开始可能没遇到什么特别的问题,但随着产品的壮大和发展,往往会越来越凌乱。抽丝剥茧的搭建色彩系统,真正让色彩为设计服务,简化团队的工作,相信您会有更愉快的工作体验~
文章来源:优设 作者:腾讯ISUX
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
蓝蓝设计的小编 http://www.lanlanwork.com