首页

JS基础知识整理06-函数

seo达人

使用function关键字定义函数

函数声明会被提升(Hoisting),将声明移动到当前作用域顶端的默认行为。



参数:

如果函数调用的参数太多(超过声明),则可以使用函数的内置对象arguments

arguments.length 会返回函数被调用时收到的参数数目

arguments[index]可以得到相应的参数



传递对象的时候是使用引用来传递的,如果函数修改了对象属性,则原始对象也改变了。





调用:

以函数形式调用函数:(这种方式调用默认的是全局对象调用)

function myFunction(a, b) {

return a * b;

}

myFunction(10, 2);



作为方法来调用函数:(这种方式调用属于函数的拥有者myObject)

var myObject = {

firstName:"Bill",

lastName: "Gates",

fullName: function () {

return this.firstName + " " + this.lastName;

}

}

myObject.fullName(); 



通过函数构造器来调用函数:(如果函数调用的前面是 new 关键字,那么这是一个构造函数调用)

function myFunction(arg1, arg2) {

this.firstName = arg1;

this.lastName  = arg2;

}

var x = new myFunction("Bill", "Gates");

x.firstName; 



call()和apply()方法:

var person = {

fullName: function() {

return this.firstName + " " + this.lastName;

}

}

var person1 = {

firstName:"Bill",

lastName: "Gates",

}

var person2 = {

fullName: function(city, country) {

return this.firstName + " " + this.lastName + "," + city + "," + country;

}

}



call() 方法是预定义的 JavaScript 方法。

它可以用来调用所有者对象作为参数的方法。

通过 call(),您能够使用属于另一个对象的方法。

如:

person.fullName.call(person1)// person1来调用person的fullName方法



call()可以带参数,参数对应按顺序的传给方法

person2.fullName.call(person1,"Seattle", "USA")



apply()方法和call()方法类似

区别在于接收参数的方式不一样。

call(obj,"x","y") 方法分别接受参数

apply(obj,["x","y"]) 方法接收数组形式的参数





箭头函数:(ES6)

箭头函数不需要function关键字、return关键字和大括号

var x = function(x, y) {

  return x y;

}



var x = (x, y) => x
y;

两个的作用相同。



箭头函数没有自己的this、如果函数是单个语句,则只能省略 return 关键字和大括号

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

Hibernate--使用离线查询DetachedCriteria完成对列表的筛选

seo达人

User表:





User类:

package pers.zhang.domain;



public class User {



private Long user_id;

private String user_code;

private String user_name;

private String user_password;

private String user_state;

public Long getUser_id() {

return user_id;

}

public void setUser_id(Long user_id) {

this.user_id = user_id;

}

public String getUser_code() {

return user_code;

}

public void setUser_code(String user_code) {

this.user_code = user_code;

}

public String getUser_name() {

return user_name;

}

public void setUser_name(String user_name) {

this.user_name = user_name;

}

public String getUser_password() {

return user_password;

}

public void setUser_password(String user_password) {

this.user_password = user_password;

}

public String getUser_state() {

return user_state;

}

public void setUser_state(String user_state) {

this.user_state = user_state;

}

}



ORM元数据:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"&gt;

<hibernate-mapping package="pers.zhang.domain" >

<class name="User" table="sys_user" >

<id name="user_id"  >

<generator class="identity"></generator>

</id>

<property name="user_code" column="user_code" ></property>

<property name="user_name" column="user_name" ></property>

<property name="user_password" column="user_password" ></property>

<property name="user_state" column="user_state" ></property>

</class>

</hibernate-mapping>



控制层:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("utf-8");

//获得查询参数

String userIdStr = request.getParameter("userId");

String userName = request.getParameter("userName");

//获得离线查询对象

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);

//拼装查询条件

if(userIdStr != null && !"".equals(userIdStr)) {

Long userId = (long) Integer.parseInt(userIdStr);

detachedCriteria.add(Restrictions.eq("user_id", userId));

}

if(userName != null && !"".equals(userName)) {

detachedCriteria.add(Restrictions.like("user_name", userName, MatchMode.ANYWHERE));

}



//作为参数传递给service层

UserService userService = new UserService();

List<User> list = userService.findUserByCondition(detachedCriteria);



request.setAttribute("userList", list);

request.getRequestDispatcher("list2.jsp").forward(request, response);

}



Service层:

public List<User> findUserByCondition(DetachedCriteria detachedCriteria) {

//传递给Dao层

UserDao userDao = new UserDao();

return userDao.findUserByCondition(detachedCriteria);

}

1

2

3

4

5

Dao层:

public List<User> findUserByCondition(DetachedCriteria detachedCriteria) {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();



//关联session

Criteria criteria = detachedCriteria.getExecutableCriteria(session);

//查询

List<User> list = criteria.list();

return list;



}



前端页面:

忘记写查询数据回显了…



<%@ page language="java" contentType="text/html; charset=utf-8"

    pageEncoding="utf-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title></title>

<script type="text/javascript" src="js/jquery-2.1.0.js" ></script>

<script type="text/javascript" src="js/bootstrap.min.js" ></script>

<link rel="stylesheet" href="css/bootstrap.css" />

</head>

<body>

<form class="form-inline" role="form" method="post" action="${pageContext.request.contextPath }/findUserByCondition">

  <div class="form-group">

    <input type="text" class="form-control" id="exampleInputEmail2" placeholder="用户ID" name="userId">

  </div>

  <div class="form-group">

    <input type="text" class="form-control" id="exampleInputPassword2" placeholder="用户名" name="userName">

  </div>

  <button type="submit" class="btn btn-default">筛选</button>

</form>



<div style="text-align: center; width: 600px;">

<table class="table table-hover">

  <tr><td>编号</td><td>用戶ID</td><td>用户名</td><td>昵称</td><td>密码</td></tr>

  <!-- 显示数据 -->

  <c:forEach items="${userList }" var="list">

  <tr><td>${list.user_id }</td><td>${list.user_code }</td><td>${list.user_name }</td><td>${list.user_password }</td><td>${list.user_state }</td></tr>

  </c:forEach>

</table>

</div>





</body>

</html>



测试:



蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

聊聊那些拥有“边际效应”的产品

雪涛

讲述边际效应对应不同线上线下产品的不同状态以及优势

现如今对于大多数的互联网产品来说,其实都大致会用到“边际效应”这个概念,在看似华丽渲染的互联网背后,真正支撑着的是对人的深刻认识与理解。当然,现如今的产品很多都有规律可循,包括商业模式、变现方式等等,那么这次我们就来说说那些在互联网中产品的边际成本递减效应的设计。



边际成本

首先呢,在这里我要先为大家解释一下何为边际成本。

从概念性角度解释:边际成本指的是每一个单位新增的产品(或购买的产品)所带来的总成本增量。

( 举例 )

比如说现如今的共享单车,在仅生产第一辆的时候,其公司花费的成本是极大的,它包含:设计费、电话费、路程费、人工费等等等等……但是,在生产第100辆的时候,小车儿的成本就低很多了,再不创新的前提下,只要复制就可以了,而如果在生产第1000辆的时候,那成本就更低了,这就是经济规模带来的效应。那么,同样的复制,为什么越复制越便宜呢?其实,这里面有一个对等的增产量对比,由于小车数量的增多,遍布区域的扩大,所以,也就导致公司的机会成本增高,也就是成本更低,所以,考虑边际成本递减的同时,也要考虑机会的增多。



边际成本递减

刚才说到的其实就是边际效应里成本递减的模式,也是我们这次讨论产品的核心,所谓的边际效应递减,就是指在其他条件不变的情况下,如果一种投入要素连续的等量增加,当增加到一定产值后,所提供的产品增量就会下降,同时可变要素的边际产量就会递减。


我在举个例子:日常的滴滴打车,就是递减的模式,因为滴滴大多数的供给侧平台用户就是私家车出来接单,所以,当平台每多接入一辆车,那么对于滴滴平台来讲边际成本就越趋于零。

其实,类似于滴滴打车这样的线上+线下的资源整合性平台,更加符合互联网的经营模式,这是因为互联网在21世纪,就是以免费为前提的,随着用户的增多,边际成本的下降,无非就是在完善经营的条件下,多开一些服务器和宽带罢了,其他的成本几乎已经可以忽略不计,而这也正是互联网产品成为霸主的必要因素之一。


    注(供给侧:经济学术语的一种,意思是指供给方面,国民经济的平稳发展取决于经济中需求和供给的相对平衡。 供给显示了随着价钱升降而其它因素不变的情况下,某个体在每段时间内所愿意卖出的某货物的数量。在某一价格下,消费者愿意购买的某一货物的总数量称为需求量。在不同价格下,供给量会不同。供给和需求也就是说价格与需求量的关系。若以图像表示,便称为供给曲线。)



边际成本的线下产品案例


奶茶案例

在我们逛街购物时,几乎都会买一杯奶茶饮品,而这里面就运用到了边际效应的负效应模式,他们运用第二杯半价的手段来提升消费者对产品第一次的贪婪程度,也就是“欲望值”,同时也提升了产品的销售,但边际成本不变,当消费者购买后,负效应可能就会产生,因为消费者不一定能喝完。这里就体现的是商品价值取决于人的欲望和欲望被满足的程度比例。



服装案例

再比如商场内大牌服装都写着全场8折,其实仔细想想,8折的价格真的很划算么?他们这么做也同样是在运用了边际效应的同时调取了消费者心理的欲望值,在消费者第一次购买时,单纯考虑的爽点而非负效应,但随着商品购买完的数量,才真正会产生负效应。



电影票案例

还有一个是关于电影票的,我的一个朋友会经常去看电影,之前去看电影的时候是在现场买的票,那次售票员给他推送了一个非常超值的套餐,就是单买一张票是原价48元,但是近期有一个限量套餐,这个套餐里包含:5场电影+1桶爆米花,价格是149元,但是需要一次性消费,听起来是不是非常超值?我的朋友考虑反正也没事,那就多看几场,还便宜。但是如果按照边际成本递减与负效应来讲,这绝对是一件亏本的买卖,谁能一直做着看十几个小时的电影不走?我想电影院也一定有这样的数据才会推出这样的套餐吧。但随着消费者购买人数越多,边际成本递减,其他人也会纷纷模仿,这里面包含一个人类固有的“羊群效应”,也就形成了商业价值,但随着消费者看电影时间的延长,负效应也随之而来。


    注(羊群效应:羊群效应理论,也称羊群行为、从众心理。经济学里经常用“羊群效应”来描述经济个体的从众跟风心理。)



边际成本的线上产品案例


微信

首当其冲的,自然是微信了,这个传奇产品堪称边际成本做的最好的一个,在我们之前都是运用短信电话的时候,每发一条短信,每打一个电话都要考虑不同的费用,但由于微信的出现,极大的解决了用户的这个痛点,微信已最核心的打字聊天、语音/视频通话为主要支点,并赋予各种特色产品辅助。在微信最大化的边际成本趋于零的同时,迅速扩大了用户使用产品的范围区,所以,作为互联网的边际成本,我想微信的在这方面确实做的很好。



GoFun出行

这款产品为共享汽车类型,属于线上+线下产品,Gofun出行的边际成本做的比较合理是,首先是他的供给侧能力较足,因为依托了首汽集团的优势资源,极大的降低了边际成本,并通过对用户的日常作息将碎片打车时间、坐公交时间、出游时间等需求作为整体分析,提供了这一种出行服务,并且现在的产品里还融合了长时间租车服务,这就极大的又一次挖掘了一批潜在用户,在边际成本递减并趋于零的同时,反响的用户群体范围也在逐渐扩大。同时这个产品还在登陆时跳出有广告提示,“分享可得免费时长开车券等优惠”,这种手法也是除了在边际成本递减的同时,运用的用户酬赏机制,目的是通过用户引流用户。



摩拜单车

在文章开篇的时候我拿共享单车举过例子,其实摩拜单车的性质与共享汽车的性质大体一致,主线路相似程度可达到80%,这里我要和大家说一个定律,关于用户的定律。当产品开发者抓区并成功解决掉某几种目标用户的痛点后,其相等模式可无限制复制,并形成范围值生产从而解决掉这几种用户对等的群体用户痛点。

我给大家举个例子应该就彻底明白了,就像医药行业诊断,当医生遇到一种从未遇见过的病毒时,其第一次需要花费的成本是极其昂贵的,但只要一旦得到解决,那么当再次遇到同类型病毒时,就可以快速复制解决,其边际成本迅速降低,反之收益增高,同时同类型病毒则可批量解决。共享汽车和单车产品正是边际成本与复制的这一体现。




总结

边际成本在20世纪时是非常难得的一个概念,因为在20世纪的成本里,几乎都是建立在“原子经济”上的,而直到21世纪互联网形体的出现,边际成本将真实的成倍数下降,这是因为21世纪的成本发生了转移,建立在了“比特经济”上。

所谓原子经济的本质就是需要以大规模生产取胜,它所遵从的是绝对的单一化、标准化、格式化创造。这种创造,并不能形成边际成本的递减,甭别说是趋于零,它需要的是逐渐递增服务,就像和滴滴打车对抗的线下出租车,随着消费者的增多,它能做的不是整合,而是新增出租车和司机进行匹配,如果不加入互联网行业,他们将很难维持下去。


而比特经济,则正好是多元化、个性化、小众化、扁平化的。它所崇尚的就是一种主客一体、多元共生共存的理念、可以使使用者分享满足感和快乐感。这样的好处是在快速扩大用户群体区值的同时还能使边际成本下降。



文章来源:站酷


本质思考是产品创新的基础

雪涛

不知道从什么时候我开始 对“创新”这个词感到些许乏力和恐惧,开始思考为什么有些人能看透问题本质?于是有了本文的探索和总结。

平时我们大部分时间都在做一些“应激反应”的事情,经常处于“被安排”的情况下,大脑逐渐懒得去思考背后的东西,通常根据自己的主观意愿做出一些反应。慢慢依赖一些“道听途说”而来的方法论来做一些事情,“套用”效果也不理想。

有一定履历的产品经理多数也会迷上“经验论”。

  • 迷上自己过往的经验,“我以前做这活动就是用这个策略的,效果很不错”。
  • 迷上他人的经验,“那天和老同学吃饭,他们这个裂变做得不错,我们也搞一个”
  • 迷上竞争对手的经验,“它们的狙击枪也有这个功能,我们也加一个”。

种种行为都是没有通过本质思考的行为表现,都是一些脉冲式的思考。别人做什么 ,我们也跟着去做,只能在这个行业里面产生细微的迭代,无法实现真正的创新。

关于创新,埃隆马斯克引爆了一个概念,回归到事物本质,看透问题本源的思维叫“第一性原理”,它不是一个定律也不是真理,而是一种思维模式。

我先不解释到底什么是第一性原理,因为本来就处于蒙圈的情况下再去看一些专业的解释就会更加蒙圈。

下面分享一个故事,一起来了解一下本质思考这种思考方式,抛开哲学、生命、宇宙本质,围绕“抢域名”这件事,主角蔡文胜是如何将域名抢注成功率从十万分之一变成50%以上?他到底是怎么做到及如何思考的。

背景:fm365.com注册于1999年10月21日,因忘记续费,到2003年10月21日过期,当时这个网站是联想重金打造的门户网站流量非常可观,当时可能有10万人要想抢注这个域名。

想抢注域名的人都知道域名释放时间是在2003年10月21日,但很多人没有做好基本的调研与了解,不同域名服务商释放时间不一样,有些是次日0点,有些是30天,所以当时大部分人都不知道这个具体域名掉落时间,实际上这个域名掉落时间是在70天之后。

那么知道了域名掉落的具体日期, 也不可能一整天都去注册抢注, 还需要知道具体时间才能抢注成功,而事实上当时这个域名在美国一个域名商手上,所以掉落时间是在美国的中午12点,对应中国是凌晨3点,在那个时间点域名才完全掉落。

那么问题来了,知道了最后具体掉落日期和时间,怎样才能脱颖而出,成为那个唯一一个能把域名抢到的人?

蔡文胜做了以下4件事:

第一件,首先注册域名上所有信息、 名字、邮箱等字段事先填好 ,这个过程大概需要5秒钟, 然后直接按f5就可以了,只要1秒不到,就能提交注册信息。

第二件,蔡文胜当时查了一下这个网络请求到底是怎么走的,发现这个请求是先从厦门连到上海,上海连到美国,请求的路径非常长,当时在2003年网速还是非常的慢,所以蔡文胜索性租了一台上海的服务器,直接从上海连到美国,这样至少在中国理论上是最快的。

第三件,节省注册资料字节长度,把88888@qq.com改成 1@1.com,因为这信息回头也可以修改,压缩后比完整的信息要少几百个字节,这样加快提交速度,又提高成功率。

第四件,当时据说抢注这个域名的人有10万人,蔡文胜预估有大概前面3件事能淘汰掉90%的人,还和剩余10%的人进行竞争,所以还是不能保证能够注册并抢注成功。最后蔡文胜搞了一个自动点击脚本,每秒提交1000次。最终蔡文胜从10万人里面脱颖而出,成为唯一一个抢到域名的人。

回归到抢域名这件事的本质上,把域名开放时间设为T0,提交信息到域名服务器的时间设为T1,使T1-T0的时间最短就能抢注成功。

看完上面的故事,回归产品人如何训练/培养自己的本质思维。

01 摆脱原有思维惯性

每个人都有一定思维惯性,看到事物会下意识的做出一些反应。

在《思考,快与慢》书中的知识叫“快系统”,人会本能直觉迅速做出一些判断和反应,这套系统好处是大脑反应非常快,功耗低还”省电“。

所以我们一旦意识到自己在用过往或他人、竞争对手等经验时先打住,不是说不能用,而先思考这些“经验”对现在是否真正能用上。

每个人都有自己对主观意识,特别是产品经理这个岗位主观意识真的太强了。在数据报表或调研结果上看到一批数据会带上自己的主观想法来解释这一批数据原因。

摆脱原有的思维惯性应该启动大脑的“慢系统”,慢系统需要调动我们的逻辑思维等能力,一旦启动逻辑思维能力周期很长,启动很慢很费力,所以我们日常那么多事情处理的时候,没有什么时间去切换慢系统,所以会造成前面所说的应激反应。

当然我们也非常难做到每次都使用“慢系统”来解决问题,大脑处理不过来,头发也坚持不住,但我们可以锻炼出好的思维方式,让自己思考时不轻易的跑到原有的思维惯性去。

02 成为“问题少年”

蔡文胜在抢注FM365这事上就是不断追问自己,“我还能不能更快一点?”、“我怎样才能比别人更快抢到!”、“如何将请求路径变短?”、“怎样才能提升请求速度?” 从解决问题的路径上,根据目标一层一层的不断的对自己发问,最终这些问题都会迎刃而解。

有问题请教别人也是突破思维惯性的好方法,抛开对错,观点过滤,交流时可以认真听但不要照着做,和老板给你提需求是一个道理。问题方和解决方看到的视角都是不一样的,利于思维开阔。

03 在实践中获得反馈

“实践”指的洞察已发生的事物做出自我思考的问题和想法、比如在“产品分析”环节重点研究下对方可能接下来会做些什么事,预估做了会产生哪些结果?当前的业务形态为什么会这样设计?

总之产品方法论有时候并没有那么重要,最重要的不是学习别人的方法论,而是通过自己的本质思考,不断总结出自己的方法论,有意识的去训练自己的思维习惯,养成思维模型,这对产品经理才是重要的事情。

文章来源:人人都是产品经理

复杂问题该用理性决策还是感性决策?

雪涛

一、明知识、默知识与暗知识的四象限图

AI被热捧那么久,王维嘉博士的《暗知识》是第一本把它讲明白的中文科普书。

这本书第一个知识框架,就是下面这张4象限图:

思考方式的革命(一)复杂问题该用理性决策还是感性决策?

(该图来自:王维嘉的《暗知识》)

该图将知识按“是否可表达”、“是否可感受”的两个维度分为四类:

  • 可表达的“明知识”(包括可感受的牛顿定律和不可感受的量子力学)
  • 不可表达但能感受到的“默知识”
  • 而“暗知识”则是:不可表达、又没法感受到。

具体来说,暗知识是机器发现的,人类无法感受也无法表达的知识。

就像围棋,人类2000年来保留的棋谱大概有3000万个(8位数),但围棋上棋子的摆放方法的可能性有2的361次方个(108位数),中间何止相差万亿倍。人类对围棋的认知,就是基于3000万这个8位数范围的认知。与机器相比,相差10的100次方。这部分机器能掌握而人不能的,就是暗知识。

这是本书让人惊叹的第一个点,通过设立一个新的二维坐标模型,就能够找到人类以往概念上的盲区!其次,王博士选的词汇也是超一流的,“暗”和“默”两个字都很有神采。

虽然是“科普书”,但书里还是不得不讲到人类的“神经网络”、计算机的“机器学习”、“卷积”等复杂概念。

我用自己的语言,以“识别一只猫”为例,为大家简单讲述一下AI吧:

(1)识别猫与计算“1+2=?”不同,前者是“默知识”—— 无法用准确的语言描述出来。在计算机历史上,通过“尖尖的耳朵”、“长尾巴”、“圆眼睛”等信息来识别猫的程序都失败了。

(2)我们闭上眼睛想想,如何把一只猫与一只豹子的照片区别开,需要补充很多语言描述。把一只猫与一只狗区别开,又需要补充一些描述,其实人是不能把“识别一只猫”这件事情用语言明确说清楚的 —— 既然人说不清,传统计算机程序就做不到。但人,哪怕是三岁的孩子都能区别猫和狗,背后是什么原理呢?

(3)后来科学家通过研究人类大脑的神经网络,发现大脑是通过分层判断,最终在神经元中留下“历史痕迹”的逻辑链条的。这是很有趣的生物学现象,一个神经元受到的刺激(生物电击)越多,得到的营养就越多、就会成长得越强大。而每次判断在每层神经元中留下的痕迹,就会强化今后整个人脑神经网络的判断能力。

(4)计算机科学家根据对人类大脑神经网络的认识,开发了计算机“神经网络”。这个网络不但可以识别“猫”,而且识别猫的过程也同样无法输出成为人能认识的“文字描述”。

(5)这些识别算法就沉淀在“神经网络”中(表现为数据及数据关系),无法被人类直接掌握,人只能通过安装了神经网络的计算机获得这个能力。

(6)不知大家注意到没有,为了让计算机解决这个“默知识”的问题,我们最终是用了“暗知识”来解决。

(7)这类“暗知识”,能够在计算机之间快速复制,但无法在人和人之间复制,人和人之间能传递的只能是控制AI计算机的方法。

暗知识大体说完,我再回到与我们的思考方式相关度更高的“默知识”。

二、《思考,快与慢》的“系统1”

《思考,快与慢》这本书大约是我2013年读到的,我认为这是那一年我读到最好的书。好就好在研究老对象(人类行为与注意力)的过程中,用了新思考框架,并建立了有说服力的体系。

几年来,这本书被我放在电脑显示器下面,意喻为“抬高了我的视野”。当然,最初是为抬高了显示器,起到保护颈椎的作用。

思考方式的革命(一)复杂问题该用理性决策还是感性决策?

书里是这样定义人的两种思维模式的:

  • 系统1 —— 其运行是无意识且快速的,不怎么费脑力,没有感觉,完全处于自主控制的状态。例如会骑自行车的人,他在骑车时是不需要主动意识指挥手如何转动车把的,系统1会接管这些动作。
  • 系统2 —— 将注意力转移到需要费脑力的大脑活动上来。例如:大家可以回忆一下自己第一次骑自行车的场景,当时是需要非常专注地控制双手和双脚的,所以往往手忙脚乱。我记得我如果稍不能控制,双手是会放掉车把,抱住旁边的足球门柱的不知各位刚学自行车时,是否也是如此?

当系统2学习掌握了重复使用的套路后,大脑会将重复工作转给系统1。

我高中时,经常因为简单的数学加减乘除四则混合运算错误,导致考试得不到高分。我训练自己做了大量专项练习,后来不仅计算过程不出错,而且感觉当时是把简单的四则运算从“系统2”挪到“系统1”了。考试时,手上做着乘法竖式,脑子里考虑是否有更好的解题思路。

从另一个角度看,大脑的重复套路工作从“系统2”转给“系统1”,还有一个更大的好处 —— 降低能力消耗。

系统1反应很快,对能量的消耗远低于系统2。我查了《人类简史》、《文明是副产品》等书籍,看到这样的资料:晚期智人的大脑占体重的1/20,但耗能、耗氧量却达到全身的1/5。在工业革命前的5万年里,智人供养这样一个大脑是极其不容易的,所以我推断:

  • 第一,大脑不会有大比例未开发区域,因为咱们的大脑结构在5万年前成熟时(今天人的脑容量与5万年前差别不大),人体根本没有多余的营养可以供它浪费。
  • 第二,从机制上,大脑会尽量把一些套路工作从系统2转给系统1,以期降低脑力消耗。

系统1毕竟简化了判断过程,是否会造成很多误判呢?我相信是的,但因为能量的限制,人类当时应该是找到了中间最优解。

我认为:《思考,快与慢》的“系统1”,学习的其实就是前一节说的“默知识”。

还是以骑自行车为例,咱们可以教新手一些保持自行车平衡的要领,但一个新手学会骑车的过程,是实践重于理论的。最后形成的知识,就是无法说清的“默知识”,这个默知识保存在我们每个人的“系统1”当中。

当然,系统1与系统2的关系还有很多层次,并对人类社会产生了深远影响。

例如:遇到紧急情况时(“快撞到行人了”),系统2会从系统1接管人体控制权,多费一点脑力控制好自行车的方向,避免造成交通事故。

毕竟我的读者都是toB企业同事,我还是讲一个书中与咱们业务有关的故事。作者丹尼尔·卡尼曼是诺贝尔经济学奖获得者,21岁时(1955年)曾经在以色列军队里负责设计士兵面试流程。这之前,面试官完全根据感觉打分,结果筛选出来的新兵合格率很低。卡尼曼做了一套设计,听起来和我在《SaaS创业路线图(六):如何扩张团队?》中的做法类似,就是要求面试官严格按框架打分。

思考方式的革命(一)复杂问题该用理性决策还是感性决策?

思考方式的革命(一)复杂问题该用理性决策还是感性决策?

(上图为我系列文章(六)中提供的打分表)

卡尼曼不是他的面试官们的上级,面试官们不喜欢做“打分机器人”。卡尼曼的让步是,同意面试官根据标准格式打分后,最后“闭上眼睛给士兵打个总分”。

最后的结果是,新的测评方法大幅提高了有效率。45年后卡尼曼回到该部队,发现他的面试方法还在延用。

而我的面试表最后也有这样一行:“自己是否愿意带领此人去完成一个困难的任务?”其实这是一个非常感性的问题,与表格其它部分(记录工作年限、记录回答情况等)非常不同。

我观察,这就是在很多领域中,决策复杂问题的一个优选方法:

  1. 把抽象问题具象化:先用理性框架(“明知识”)、从多个角度用数字化的方法分项打分;
  2. 再把具象问题抽象化:从内心出发,我是否要用这个人?(使用了“默知识”:更感性,但往往更准确)

这个过程的好处是:

  1. 过程可操作性好,让决策者全面思考,不会漏项;
  2. 利用决策者的抽象判断能力(“默知识”),更高纬度地做出判断,不会因为打分表的设计缺陷造成决策错误。

我们企业决策中,如果死板地使用调查前设计的“打分表”,往往会错过发展机会。因为环境在剧烈变化,调查前很难做出完美的打分表。而“默知识”会让我们熟悉业务的决策者更准确地做出判断。

三、内隐学习和外显学习

上面说了很多“默知识”的例子,具体怎么学习和使用“默知识”呢?最近“得到APP”的精英日课正好也推出了一篇文章“内隐学习和外显学习”。

简而言之,外显学习就是学习“明知识”的过程,掌握历史知识、化学公式……

内隐学习,则是学习“默知识”的过程,学到的是个“感”。例如:英语的语感。

1993年高考时,记得我的英语成绩大约是140分(满分150)。因为不考口语,这全都是英语语法和单词,大多是“明知识”。

但我工作后能在外企说流利的英文,全有赖于大学时在华中理工(现在的华中科技大学)有一个教“外贸英语”的廖老师。他逼着我们每人整篇整篇地背诵外贸英语,上课经常现场考对话,当时那个厌恶哪……没想到坚持了一个学期,死记硬背了几百句常用对话后,英语“语感”就形成了。大脑中可以用英文思考问题,我是一生受用。

“精英日课”引用的一个调查研究还有个有趣的结论:外显学习明知识,注意力越集中越好;但集中注意力反而会妨碍内隐学习。

为什么?因为“默知识”是没有明确规则的,越努力找规律越学不会,不如放松一些,让头脑直接沉浸在直观信息中,这样更容易领悟那个“感”。

在企业经营中,我们经常需要新的创意:如何设计一个摆脱俗套的新激励方式?如何做营销上的创新?如何设计一个全新的内容?这时候,让注意力分散些,看看不相关的书籍、讨论一些别的话题,可能灵感会来的更快。

就像我写这篇文章,目的与路线图系列是一样的,还是想帮助大家提升经营管理能力。但如果不引入更多关于思考方式、关于人类发展史的文章,就会跳不出日常操作的层面,不能给大家带来新的空气。

四、小结

这篇文字是“思考方式革命”的第一篇。我讲的不是明知识、也不是默知识,我讲的是一些新的思考方法

(1)如何通过增添新的维度,让你对研究对象(无论是客户群、团队或产品服务)增加新的评估方式?操作工具就是最前面的四象限图。

(2)设计新体系时,用词要精准。王维嘉博士用一个“暗”字,一个“默”字,把体系讲的很清楚。“名不正言不顺”,这是我经常说的道理。一个事儿的“名字”选错了,要费很多口舌解释,到头来没听到解释的人看了还是会误解。

(3)计算机AI算法是基于人类的“神经网络”模型的。企业管理中,一个体系的设计、一个测算模型的建立,都要基于“自然”的业务规则,基于人性的需求进行考量。我不是讲抽象的“道”,我说的是可以操作的规则。

(4)例如:人的大脑将重复套路工作交给系统1,就是符合降低消耗的规则的。而“能量的限制”就是工业革命前的20万年里控制人类发展的主要因素。

(5)我们做企业,也是同样有很多限制,财务上有利润要求、有任何时点现金流不得低于安全线的要求。这属于“明知识”。

(6)在不能用“明知识”直接通过计算做出决策的复杂情况下,基于“感觉”的判断实际上更准确。所以专业知识重要,但业务背景更重要。

(7)但如果只靠“感觉”决策,也很危险。文中举了一个新兵打分的例子。最佳方法是:让决策者先结构化地全面多维度打分,然后再“感性”地做出最终判断。

(8)注意力分散些,有利于创新。所以需要新点子时,要给团队成员新环境、新场景和一些新时间。

(9)默知识这么重要,如何得到?要反复练习,不专注(忘掉规则)地学习。

品牌年轻化=品牌年轻人化?

雪涛

当下消费市场,年轻人是绝对的主力人群。对于品牌来讲,抓住年轻人就是抓住了市场,于是品牌们纷纷开始“年轻化”。但是在这条路上,一不小心,可能就会陷入“坑”中。本文笔者对品牌年轻化进行分析解读,总结了自己的看法,供大家学习参考。

互联网打破了渠道与媒介的壁垒,加速了整个社会消费观念、品味、需求的变迁。无论是消费观念还是购买能力,显然当下的年轻人是绝对的主力人群。

对于品牌而言,就好像牧羊一般,草在哪儿,羊群就在哪儿,不追草的羊不是已经饿死,就是在饿死的路上。

于是品牌年轻化好似成为了一切品牌问题的解药,不幸的是,这些品牌在年轻化的道路,都走到了相似的逼仄中,年轻化仅仅达到了“形”的贴近,却夭折在了“神”的部分。

那品牌年轻化到底该如何做呢?

木兰姐认为,在回答这个问题之前,我们需要先弄清楚一点:

品牌年轻化≠品牌年轻人化

与人一样,品牌也有自己的生命周期,会经历诞生-成长-成熟-老化的过程。但与人不同的是,品牌生命周期并不单纯以年龄来划分,而是与市场环境、经济环境、消费者行为绑定在一起。

但很多品牌往往容易陷进一个误区:认为品牌年轻化就是年轻人化,于是先给年轻人贴几个标签,然后再把这些标签贴在自己身上,试图收获年轻人的认同,混进他们的圈子,用看似时尚、热门、流行的元素将自己打扮成“年轻人”,但往往最后结果却是不被年轻人买单的无效沟通。

举个例子:

KFC前段时间的形象风波就是大型的翻车现场,让消费者者觉得品牌对“年轻”有误解。

KFC为了更贴合年轻消费者对颜值的要求,完全翻转了大家对爷爷慈祥微胖的印象,以更时尚的高颜值形象走入消费者眼帘。

但这个形象横空出现,只给消费者带来了短暂的视觉冲击,并没有让其产生情感上的认同,甚至是吓到了部分消费者,很多人直呼不买账。

△图片截取自网络

所幸这只是KFC品牌年轻化的一次尝试,并没有真正投入市场,也没有给品牌带来太多的影响。

从KFC的案例中我们可以得到什么样的警醒呢:或许品牌用表面的装嫩的方式能够获得一时关注,但混入年轻人的圈子,走进他们的内心却有些难度。

就像1000个读者就有1000个哈姆雷特一样,1000个消费者可能会有1000种需求或喜好,品牌无法对这个群体“一刀切”,也没有一个品牌能做到被所有年轻人追捧。

要知道,这一代年轻人并不是很多品牌自以为所谓的 “狂拽炸酷吊炸天”这么简单,品牌需要做的是真正洞察年轻人的生活态度,先在价值观上找到和年轻人真正的契合点,强调 “我”,而不是追随 “他”。

那正解如何呢?

一、为品牌灌注新鲜活力

就像物理学中的杠杆支点一样,支点找得准不准,直接影响其他要素的确定。对企业而言,突破品牌桎梏,精准地找到品牌年轻化的支点,才是赢得消费群体的王道。

而这个“品牌年轻化”的支点,木兰姐认为应该是为品牌灌注新鲜活力,延长或恢复品牌的“青春期”,让品牌可以一直活跃在时代主力消费人群的面前,不至于被消费者和市场遗忘。

无疑,旺旺是其中的佼佼者者。

旺旺在年轻化的道路上摸索出了一条康庄大道,除了主打情怀回忆杀,还不断尝试将品牌时尚化,以此来满足年轻人的潮流需求,比如六一携手奈雪的茶推出宝藏奶茶;与自然堂联合,打造自然堂x旺旺定制款气垫BB霜组合装,以及联名款服装等,一系列令人意外又惊喜的跨界合作,无疑赚足了眼球。

这一波国民经典IP与原创潮牌的跨界合作,不仅意味着旺旺已经洞察到现如今年轻一代的喜好,更代表了旺旺作为一个国民老品牌,有着高度的包容性,在打破以往成就、固化的品牌形象后,以有活力、年轻化、时尚潮流的品牌范儿,不断刷新品牌的高曝光度,以及年轻人对品牌的认可度。

可以说,旺旺在尝试年轻化营销的同时,也能看到其要做年轻化内容、年轻化产品、年轻化品牌的决心。

还有我们的国民老品牌百雀羚,不管是提到广告,还是产品,百雀羚都是美妆界永远绕不开的话题,而百雀羚能在消费者心中留下如此重要的认知,都离不开其一直以来的努力和创新。

从三生花系列到现如今的故宫美什件,从《一九三一》到今天的《见微知著》、《多了一点》,通过消费者喜欢的方式,为品牌注入新鲜的血液,让经典老品牌显得“年轻力”十足,成功激活了消费群体,并在品牌年轻化的形象和销售转化量上都实现了质的突破。

可见,只有为品牌注入与时代相符的新内涵,才能积极契合消费族群的变迁,才是品牌永葆年轻的护城河。

二、传递年起人认同的品牌价值观

提到这一点之前,我们先来看一个2018年最佳汽车营销广告案例,来自奥迪。

在这支广告里,奥迪没有流于表面的年轻元素,而是全程展现了一位滑雪飞人,观众跟着他脚下的双板划过几乎地球上所有的地貌:山地,森林,沙漠,草原,火山,长城,海洋…

而整个片子中,奥迪车全程没有入境,只在影片结尾,蓝色海洋的背景里出现奥迪的广告语:“All Conditions Are Perfect Conditions.(所有场景,都是完美场景)”。

但就是这支充满“挑战、无畏、前进等精神”的广告大片最后赢得戛纳社会化营销金奖,引起热议,深受年轻观众的喜爱。

这说明了什么?品牌年轻化,不应拘泥于品牌面貌的年轻,更多的是品牌内核的年轻

再举个极端的案例:

年过123岁的锐步(Reebok)签下80岁“高龄青年”王顺德为品牌代言人。这个加在一起超过200岁的“超高龄组合”,如果纯粹按年纪来说,绝对称不上“年轻”,而如果单从代言人王顺德的外形上硬要找一点年轻元素的话,可能也就能是那一头狂野白发中的“狂野”了。

为什么会选中王顺德?锐步看中了王顺德身上年轻的态度——坚持、自信、突破极限,向消费者传递出“任何年纪,都可以活出自己的样子,突破极限,打破年龄的疆界”的心态。

而这跟当代年轻人释放个性,崇尚平等,追求自由,积极进取,享受生活,不喜欢权威,不喜欢说教的价值观是一致的,锐步升华了代言人背后的品牌精神。

所以木兰姐认为,如果你正在为品牌年轻化发愁,不妨从品牌的核心精神和态度入手,形成年轻的品牌价值观,去发现目标消费群的价值需求,找到一个能在你们之间产生共鸣的态度,让他们对品牌产生认同。

三、帮用户发声彰显自我

此外,90后及00后的自我意识是全面觉醒的,与以往的群体不同,他们天生具有强烈的表达欲及掌控欲,这也进一步催化品牌要用“陪伴心态”去与年轻人相处,真正懂他们,帮他们发声,彰显自我……最终成为他们心里“陪在他们身边的人”。

比如说江小白的文案,其实不少是用户自己写的文案,然后通过筛选量产出来。再比如有时间火爆的《我的说明书》H5、DIY类H5,引发了同类H5作品的爆发,背后都是用户的自我价值表达。

还有今年五四青年节百度APP通过创意互动手绘形式,站在年轻人的角度,说出了他们的心声,彰显年轻人的才华和态度,也是狠狠地刷了一波存在感。

我们从不拒绝新事物

青年人,就要站在时代与潮流的风口浪尖

甭管哪年,在爱国这个原则性问题上

我们的脾气还是有点大

在国家最需要我们的时候

青年人逆风而行,救民于水火之中

这就像安装了八个情感按键,撬动用户心中的共鸣开关,最终完成内容与用户的深度沟通,让用户认同品牌价值;更重要的是设计出文案,让用户表达自我,从而在用户群中分享传播品牌价值。

由此可见,年轻化不是品牌的一厢情愿,而是品牌和消费者的合谋:“看见世界,找到自己”。

结语

最后,木兰姐想说,年轻化的“套路”不可能一成不变,无须刻意贴合年轻人时下的热点,抓住深的洞察获得年轻人共鸣,才是品牌年轻化的最好方式。

文章来源:人人都是产品经理

区分「取消」与「关闭」的设计差异

雪涛

区分取消与关闭,可以很大程度上避免丢失用户已操作的内容。在关闭视图之前保存用户的更改,使用文本标签而不是「X」图标,并在破坏性操作之前提供确认对话框。

让人迷惑的「X」图标

很久以前,「X」这个符号是用在地图上,标记「宝藏的藏身地」。但在今天的数字化界面中,「X」符号不再用来标记位置,而是被用来取消进程,或者关闭某个临时页面/弹框。但是如何确定「X」代表的是「取消」 还是「关闭」?有的时候可以确定,有时却模糊不清难以界定。

其实,主要的问题在于「X」图标缺少了文本标签。当同一个图标在不同的界面,却代表不同的含义,该图标的可用性就会受到影响,因为用户判断不了到底是什么含义。

为什么要区分「取消」与「关闭」

当用户单击/点击「X」按钮来关闭模态弹框或视图时,系统会完全取消该过程并清空之前所有操作,这让人沮丧,甚至抓狂。因为用户通常认为「X」图标表示取消或者关闭,所以区分这两种可能性对于交互的成功至关重要。

在某些情况下,区分取消 or 关闭并不重要。当一个弹窗占据你的大部分屏幕时,点击「X」按钮(尽可能快地),既可以关闭该模态,也可以取消它可能触发的任何进程。

但是,如果页面中包含正在运行的计时器,正在播放的音频,正在选择多个选项标签,或其他类型未保存的内容,那就很有必要说明「X」图标所代表的意义。因为用户可能打算让计时器或音频继续运行,或者希望立刻应用这些选好的选项标签,或保存正在进行的工作,同时希望关闭该视图继续其他操作。

例如:丝芙兰在结账过程中,使用模态窗口来展示用户可以添加到购物车的免费商品。在以下示例中,单击「 ADD(添加)」按钮选择商品后, 该按钮直接被变成了「 Remove(移除)」,看起来似乎商品已经被添加到购物车中了。但是,实际上当用户单击右上角的「X」图标后,该商品并不在购物车中。他需要再重复这个步骤,最后点击「Done(完成)」按钮,商品才会被加入购物车。

Sephora:单击右上角的「X」会取消选择这些试用商品整个过程。用户必须先单击「ADD」,再单击「Done」才能将商品添加到购物车。

如何避免丢失用户正在操作的内容

要避免丢失用户正在操作的内容,首先需要确定用户的意图,是取消还是关闭,并提供明确的选项。有以下几种方法:

  • 主动要求用户确认他们的意图;
  • 使用明确的文本标签而不是模糊图标;
  • 显示两个不同的按钮:「X」图标表示关闭视图(可以自动保存页面内容/操作),而「取消」则代表放弃该过程。

1. 要求确认

如果用户在已经执行操作的模态弹框或页面视图中,点击「X」图标,app 则可以在关闭视图之前,直接询问用户是否应用该操作,来确认其意图。此解决方案非常适合会破坏用户工作的破坏性取消操作。例如,过滤器视图可能会被意外关闭,并且关闭会导致用户丢失其选定的选项。

这个问题在移动端界面上很常见,因为过滤器视图占用了很大的屏幕空间,这使用户很难或不能判断是否已经应用了那些选择。为了防止这种潜在的错误,在关闭过滤器视图之前,跟用户确认是否要应用这些选择并关闭视图,抑或是清除这些选择。例如:下图中,当用户选择后,点击「X」图标时,Lowes 会出现如下确认弹框。

左 :点击「X」图标或返回箭头,所有的选项都会被取消,并将用户带回上一个页面。右:点击「X」后,出现一个确认对话框,确认用户是应用还是取消筛选,然后再返回结果列表页。

同样,当用户关闭正在进行的课程时,语言学习应用Duolingo 会显示一个确认对话框,课程进行中不能中途离开,除非确认「退出」。至少,该 APP 向用户传达了这一限制,同时他们也可以选择「取消」来继续课程。点击「X」按钮将结束当前课程。为了防止出错,结束前会出现一个确认对话框。

缺点:

  • 虽然确认对话框在避免「X」图标有歧义方面很有效,但它却添加了额外的步骤;
  • 用户在按下「X」图标之前还是不知道它到底做了什么,代表什么意思,因此他们可能会对这个操作感到疑惑。

2. 使用文本标签

不要完全依赖对话框来让用户确认模糊的「X」图标,而是使用明确的文本标签。文本可以消除歧义,并清楚地传达将发生的操作:取消与关闭。

Yelp 的筛选页面在屏幕顶部提供了标有「Cancel(取消)」和「Reset(重制)」的按钮,在底部提供了一个大大的「Apply(应用)」按钮。类似地,Etsy 中的 Filters 视图提供了「Clear(清除)」和「Done(完成)」两个按钮。

注意:Etsy 使用「Done」而不是「Apply」,因为过滤器一经选择就可以被应用,而这里是关于开关切换与否的建议。

(左)Yelp:Cancel、Reset 和 Apply 这三个文本标签既直接又清晰,这样用户就不太可能不小心关闭视图而丢失他们过滤器中的选择。(右)Etsy:Clear 为用户取消提供了一种清晰的方式,而点击 Done 则返回到「产品列表」页,其中的选择已经应用。

3. 关闭并保存

如果必须使用「X」图标而不是文本标签(比如为了以节省空间,或者正在遵循团队的设计语言),请谨慎使用,并在用户完成前保存操作/内容。另外,可以提供一个单独的「取消」按钮,让用户在进程之外有一个紧急出口,并消除「X」在两种含义之间的歧义。

例如:Gmail 会自动保存在非模态窗口中填写的邮件信息到草稿(Drafts)。这样的好处是,用户在需要折叠或关闭该窗口时,仍然保存原来的内容以便于下次继续编辑。将鼠标悬停在消息窗口右上角的「X」图标上时,会显示一段提示:Save & Close(保存到草稿并关闭)。此外,点击窗口右下角的「垃圾桶」图标可以删除该邮件,这个图标离顶部的「保存和关闭」选项很远,可以防止用户误点。

Gmail:Hover 透露,「X」图标是用于关闭窗口而不是删除草稿,它允许用户保存并关闭消息窗口而不会丢失刚刚正在编辑的邮件。

对于长进程或倾向于在后台运行的进程(如计时器),默认自动保存也是一种很好的解决方案。

例如,Glow Baby 中,后台运行喂食或睡眠计时器时,用户还可以浏览 APP 的其他区域。因为这些计时器一般会运行很长一段时间。此功能还能让用户在 APP 中做其他的任务操作,例如记录之前换尿布的时间、浏览文章、逛论坛等。点击计时器视图中的「X」图标也只是关闭窗口并不会取消正在运行的计时器。

Glow Baby:(左)点击运行计时器视图中的「X」图标,在不停止计时器的情况下取消视图,从而允许用户继续使用 APP 记录其他类型的事件、参与社区讨论、阅读文章等。(中)运行计时器的状态显示在屏幕顶部的状态栏中。(右)在计时器暂停时点击「X」图标,弹出「放弃」或「取消」按钮以确认用户的真正意图。

请注意:在关闭前保存中间工作或维护正在进行的过程是主动的,但有时可能会与用户的意图相反。如果用户打算通过单击「X」按钮取消其选择,那自动应用这些选择可能会令人困惑和沮丧。

这就是为什么还必须有一个单独的「取消」按钮,给用户一个出口,而不是强迫他们必须关闭时自动保存。

结论

虽然「X」图标会造成模棱两可,而且经常导致可用性问题,但它不太可能马上从所有接口中消失。设计人员应该注意「X」图标的多重含义,消除「关闭」和「取消」之间的歧义,并提供确认对话框或自动保存等保护性措施,避免丢失任何用户正在操作的内容。

若存在疑问,请记住:先保存,再退出。

小思考

为什么手机验证码登录微信/淘宝时,验证码输入错误,二者都是用的模态对话框提示用户,而不是用 Toast 呢?

  • 微信和淘宝的用户群体都很庞大,几乎横跨所有年龄层。Toast 出现又自动消失的交互体验,用户会感到不可控,尤其是对大龄、老龄的用户不够友好。
  • 也有悖于 iOS 人机交互指南中提到的「用户控制」这一原则,我想这也是 iOS 设计语言没有 Toast 这种控件的原因之一吧。
  • 而模态对话框虽然干扰性较强,但用户可以随时控制,在使用过程中是用户掌握主导权。

补充:Toast 这一控件,原是 Android 系统的控件。但自 Android 5.0 推出原质化设计后,Toast 就被弱化,而是将 Snackbar 作为官方推荐的控件。如今在 Material Design 中更是找不到 Toast 的踪影。主要原因还是 Snackbar 在交互友好性方面比 Toast 要好,例如:支持手势交互、支持与 CoordinatorLayout 联动等。

跨平台设计 :平台选择

雪涛

在本篇开始之前,我们稍作回顾。目前已经完成的两个系列包括:「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 选择最为适合的平台。

CSS3 终极布局指南

seo达人

对于同一个页面布局,几乎每个人的写法都不一样,有人喜欢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;

}


two {

  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 的简单实例

seo达人

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界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档