首页

前端基础-HTML5新特性

seo达人

html5的新特点

1.语法更简单

a) 头部声明


<!doctype html>


b) 简化了字符集声明


<meta charset="utf-8">


2.语法更宽松

a) 可以省略结束符的标签


li、dt、dd、p、optgroup、option、tr、td、th


b) 可以完全省略的标签


html、head、body


3.标签语义化

增加了很多标签,在作页面的时候更加具有语义(定义了一些原本没有语义的div模块为有鲜明结构的语义模块)


a) <header>标记定义一个页面或一个区域的头部


b) <nav>标记定义导航链接


c) <article>标记定义一篇文章内容


d) <section>标记定义网页中一块区域


e) <aside>标记定义页面内容部分的侧边栏


f) <footer>标记定义一个页面或一个区域的底部


语义化标签图示


4.表单新增常用属性------要求掌握

required:必填


placeholder:输入内容提示


autofocus:自动获取焦点-----自动帮我们将光标点进去


<form method="post" action="http://www.baidu.com">

<!-- required 必填,必须的 -->

<!-- 自动获取焦点----自动将光标定位到表单中 -->

<input type="text" placeholder="请输入用户名" autofocus="autofocus" required="required" />

   <input type="submit" />

</form>



5.input新增type属性值

a) type=“email”,文本框中只能输入email地址




b) type=“date”,日期控件




c) type=“time”




d) type=“month”




e) type=“week”




f) type=“number”,唤醒数字键盘




g) type=“range”,滑块




h) type=“color”



H5之外部浏览器唤起微信分享

seo达人

最近在做一个手机站,要求点击分享可以直接打开微信分享出去。而不是jiathis,share分享这种的点击出来二维码。在网上看了很多,都说APP能唤起微信,手机网页实现不了。也找了很多都不能直接唤起微信。

总结出来一个可以直接唤起微信的。适应手机qq浏览器和uc浏览器。

下面上代码,把这些直接放到要转发的页面里就可以了:

html部分:


  1. <script src="mshare.js"></script>//引进mshare.js
  2. <button data-mshare="0">点击弹出原生分享面板</button>
  3. <button data-mshare="1">点击触发朋友圈分享</button>
  4. <button data-mshare="2">点击触发发送给微信朋友</button>

js部分:


  1. <script>
  2. var mshare = new mShare({
  3. title: 'Lorem ipsum dolor sit.',
  4. url: 'http://m.ly.com',
  5. desc: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat inventore minima voluptates.',
  6. img: 'http://placehold.it/150x150'
  7. });
  8. $('button').click(function () {
  9. // 1 ==> 朋友圈 2 ==> 朋友 0 ==> 直接弹出原生
  10. mshare.init(+$(this).data('mshare'));
  11. });
  12. </script>

下面是mshare.js的代码分享,把这些代码新建一个js文件放进去,然后在页面中引进就ok了。


  1. /**
  2. * 此插件主要作用是在UC和QQ两个主流浏览器
  3. * 上面触发微信分享到朋友圈或发送给朋友的功能
  4. */
  5. 'use strict';
  6. var UA = navigator.appVersion;
  7. /**
  8. * 是否是 UC 浏览器
  9. */
  10. var uc = UA.split('UCBrowser/').length > 1 ? 1 : 0;
  11. /**
  12. * 判断 qq 浏览器
  13. * 然而qq浏览器分高低版本
  14. * 2 代表高版本
  15. * 1 代表低版本
  16. */
  17. var qq = UA.split('MQQBrowser/').length > 1 ? 2 : 0;
  18. /**
  19. * 是否是微信
  20. */
  21. var wx = /micromessenger/i.test(UA);
  22. /**
  23. * 浏览器版本
  24. */
  25. var qqVs = qq ? parseFloat(UA.split('MQQBrowser/')[1]) : 0;
  26. var ucVs = uc ? parseFloat(UA.split('UCBrowser/')[1]) : 0;
  27. /**
  28. * 获取操作系统信息 iPhone(1) Android(2)
  29. */
  30. var os = (function () {
  31. var ua = navigator.userAgent;
  32. if (/iphone|ipod/i.test(ua)) {
  33. return 1;
  34. } else if (/android/i.test(ua)) {
  35. return 2;
  36. } else {
  37. return 0;
  38. }
  39. }());
  40. /**
  41. * qq浏览器下面 是否加载好了相应的api文件
  42. */
  43. var qqBridgeLoaded = false;
  44. // 进一步细化版本和平台判断
  45. if ((qq && qqVs < 5.4 && os == 1) || (qq && qqVs < 5.3 && os == 1)) {
  46. qq = 0;
  47. } else {
  48. if (qq && qqVs < 5.4 && os == 2) {
  49. qq = 1;
  50. } else {
  51. if (uc && ((ucVs < 10.2 && os == 1) || (ucVs < 9.7 && os == 2))) {
  52. uc = 0;
  53. }
  54. }
  55. }
  56. /**
  57. * qq浏览器下面 根据不同版本 加载对应的bridge
  58. * @method loadqqApi
  59. * @param {Function} cb 回调函数
  60. */
  61. function loadqqApi(cb) {
  62. // qq == 0
  63. if (!qq) {
  64. return cb && cb();
  65. }
  66. var script = document.createElement('script');
  67. script.src = (+qq === 1) ? '//3gimg.qq.com/html5/js/qb.js' : '//jsapi.qq.com/get?api=app.share';
  68. /**
  69. * 需要等加载过 qq 的 bridge 脚本之后
  70. * 再去初始化分享组件
  71. */
  72. script.onload = function () {
  73. cb && cb();
  74. };
  75. document.body.appendChild(script);
  76. }
  77. /**
  78. * UC浏览器分享
  79. * @method ucShare
  80. */
  81. function ucShare(config) {
  82. // ['title', 'content', 'url', 'platform', 'disablePlatform', 'source', 'htmlID']
  83. // 关于platform
  84. // ios: kWeixin || kWeixinFriend;
  85. // android: WechatFriends || WechatTimeline
  86. // uc 分享会直接使用截图
  87. var platform = '';
  88. var shareInfo = null;
  89. // 指定了分享类型
  90. if (config.type) {
  91. if (os == 2) {
  92. platform = config.type == 1 ? 'WechatTimeline' : 'WechatFriends';
  93. } else if (os == 1) {
  94. platform = config.type == 1 ? 'kWeixinFriend' : 'kWeixin';
  95. }
  96. }
  97. shareInfo = [config.title, config.desc, config.url, platform, '', '', ''];
  98. // android
  99. if (window.ucweb) {
  100. ucweb.startRequest && ucweb.startRequest('shell.page_share', shareInfo);
  101. return;
  102. }
  103. if (window.ucbrowser) {
  104. ucbrowser.web_share && ucbrowser.web_share.apply(null, shareInfo);
  105. return;
  106. }
  107. }
  108. /**
  109. * qq 浏览器分享函数
  110. * @method qqShare
  111. */
  112. function qqShare(config) {
  113. var type = config.type;
  114. //微信好友 1, 微信朋友圈 8
  115. type = type ? ((type == 1) ? 8 : 1) : '';
  116. var share = function () {
  117. var shareInfo = {
  118. 'url': config.url,
  119. 'title': config.title,
  120. 'description': config.desc,
  121. 'img_url': config.img,
  122. 'img_title': config.title,
  123. 'to_app': type,
  124. 'cus_txt': ''
  125. };
  126. if (window.browser) {
  127. browser.app && browser.app.share(shareInfo);
  128. } else if (window.qb) {
  129. qb.share && qb.share(shareInfo);
  130. }
  131. };
  132. if (qqBridgeLoaded) {
  133. share();
  134. } else {
  135. loadqqApi(share);
  136. }
  137. }
  138. /**
  139. * 对外暴露的接口函数
  140. * @method mShare
  141. * @param {Object} config 配置对象
  142. */
  143. function mShare(config) {
  144. this.config = config;
  145. this.init = function (type) {
  146. if (typeof type != 'undefined') this.config.type = type;
  147. try {
  148. if (uc) {
  149. ucShare(this.config);
  150. } else if (qq && !wx) {
  151. qqShare(this.config);
  152. }
  153. } catch (e) {}
  154. }
  155. }
  156. // 预加载 qq bridge
  157. loadqqApi(function () {
  158. qqBridgeLoaded = true;
  159. });
  160. if (typeof module === 'object' && module.exports) {
  161. module.exports = mShare;
  162. } else {
  163. window.mShare = mShare;
  164. }

好了,这样就可以直接唤起微信进行分享啦

jQuery超详细总结

前端达人

jQuery超详细总结

文章目录

jQuery超详细总结

一 选择器

特殊选择器

二 筛选器

用在 jQuery 选择的元素后面

都是方法,对选择出来的元素进行二次筛选

三 文本操作

总结

四 元素类名操作

五 元素属性操作

在 H5 的标准下, 给了一个定义, 当你需要写自定义属性的时候,最好写成 data-xxx="值",当大家看到 data-xxx 的时候, 就知道这是一个自定义属性

六 元素样式操作

七 绑定事件

  1. on()方法是专门用来绑定事件
  2. one() 方法是专门用来绑定一个只能执行一次的方法
  3. off() 方法是专门用来解绑一个元素的事件的
  4. trigger() 方法是专门用来触发事件的方法
  5. hover()
  6. 常用事件

    八 节点操作
  7. 创建节点
  8. 插入节点
  9. 删除节点
  10. 替换节点
  11. 克隆节点

    九 获取元素尺寸

    尺寸: 元素的占地面积

    三套方法, 四种使用方式

    十 获取元素位置
  12. offset()
  13. position()

    十一 获取卷去的尺寸(页面滚动条)

    scrollTop()

    scrollLeft()

    十二 jQuery中的函数

    ready() 事件

    each() 方法

    十三 jQuery中的动画

    让元素出现不同的移动, 改变

    标准动画

    折叠动画

    渐隐渐显动画

    综合动画

    停止动画

    十四 jQuery发送ajax请求

    jQuery 里面帮我们封装好了几个方法

    专门用来发送 ajax 请求的

    jQuery 发送一个 GET 请求

    jQuery 发送一个 POST 请求

    jQuery 的 $.ajax 方法

    jQuery 的 ajax 全局钩子函数

    十五 jQuery 发送一个 jsonp 请求

    十六 jQuery 的多库并存机制

    十七 jQuery 的插件扩展机制

    十八 jQuery 的拷贝对象问题

    十九 jQuery 的插件

    jQuery 是一个前端库,也是一个方法库

    他里面封装着一些列的方法供我们使用

    我们常用的一些方法它里面都有,我们可以直接拿来使用就行了

    jQuery 之所以好用,很多人愿意使用,是因为他的几个优点太强大了

    优质的选择器和筛选器

    好用的隐式迭代

    强大的链式编程

    因为这些东西的出现,很多时候我们要做的事情被 “一行代码解决”

    接下来我们就来认识一下 jQuery

    一 选择器

    $()

    css怎么获取元素这里就怎么写

    获取的是一组元素,当里面是id时,这组元素只有一个内容

    特殊选择器

    :first $('li:first') 获取元素集合里的 第一个元素

    //  console.log($('li:first'))

    1

    :last $('li:last') 获取元素集合里的 最后一个元素

    :eq() $('li:eq()')获取元素集合里 索引为n 的那个元素,索引从0开始

    :odd $('li:odd') 获取所有索引为 奇数 的元素

    :even $('li:even') 获取所有索引为 偶数 的元素

    二 筛选器

    用在 jQuery 选择的元素后面

    都是方法,对选择出来的元素进行二次筛选

    first() 筛选 元素集合里面的 第一个元素

    //  console.log($('li').first())

    1

    last() 筛选 元素集合里面的 最后一个元素

    eq(n) 筛选元素集合里 索引为n 的那个元素

    next() 筛选出来 元素 的下一个 兄弟元素

    nextAll() 筛选出 元素后面的 所有 兄弟元素

    nextAll(选择器) 筛选出元素后面的 所有兄弟元素 中符合选择器的元素

    nextUntil(选择器) 筛选出 元素后面的所有兄弟元素 直到 选中的元素为止 不包含选中的元素

    //  console.log($('span').nextUntil('.a10'))

    1

    prev() 筛选出来 元素 的上一个 兄弟元素

    prevAll() 筛选出 元素上面的 所有 兄弟元素 (元素集合中的元素 从上一个兄弟元素开始排序)

    prevAll(选择器) 筛选出 元素上面的 所有兄弟元素 中符合选择器的元素

    prevUntil(选择器) 筛选出 元素上面的所有兄弟元素 直到 选中的元素为止 不包含选中的元素

    //  console.log($('span').prevUntil('.a10'))

    1

    parent() 筛选出元素的 父元素

    parents()筛选出元素的 所有祖先元素 直到html元素

    parents(选择器)拿到 所有祖先元素中的符合选择器的元素

    parentsUntil(选择器)筛选出元素的 所有的祖先元素 直到某一个元素 不包含该元素

    //  console.log($('span').parents('body'))

    // console.log($('span').parentsUntil('html'))



    children() 筛选出元素的 所有子级元素



    children(选择器) 筛选出元素 所有子级元素中的 符合选择器的元素

    siblings() 筛选出所有的兄弟元素 不包含 自己



    siblings(选择器) 筛选出所有的兄弟元素中的 符合选择器的元素

    find(选择器)



    筛选 一个元素后代中的 符合选择器的元素

    在一个元素集合的每一个元素中 查找后代元素 符合选择器的元素

    index() 获取元素的索引位置



    索引位置是指 是该父元素下的第几个元素 拿到的是 数字

    三 文本操作

    html() 一个读写的属性

    html()不传递 参数的时候 就是获取元素内部的超文本内容

    html(参数)传递 参数的时候 就是设置元素内部的超文本内容

    text() 一个读写的属性

    text()不传递 参数的时候 就是获取元素内部的超文本内容

    text(参数)传递 参数的时候 就是设置元素内部的超文本内容

    val() 一个读写的属性 操作 input 标签

    val()不传递参数的时候, 就是获取标签的 value 值

    val(参数)传递一个参数的时候, 就是设置标签的 value 值

    总结

    获取

    html() 只能获取第一个元素的超文本内容

    text() 能获取元素集合内所有元素的文本内容合

    val() 只能获取第一个元素的 value 值

    设置

    html() 给元素集合内所有元素设置超文本内容

    text() 给元素集合内所有元素设置文本内容

    val() 给元素集合内所有元素设置 value 值

    四 元素类名操作

    addClass() 添加类名

    执行这个方法会给元素集合里面所有的元素添加上固定的类名

    如果有就不添加, 不存在这个类名时添加

    removeClass() 移除类名

    执行这个方法删除 元素集合里面所有元素 的指定类名

    toggleClass()切换类名

    执行这个方法会给元素集合里面的所有元素切换类名

    本身存在这个类名, 删除类名

    本身不存在这个类名, 添加类名

    hasClass() 判断有没有某一个类名

    返回的时一个布尔值, 表示这个类名是否存在

    五 元素属性操作

    在 H5 的标准下, 给了一个定义, 当你需要写自定义属性的时候,最好写成 data-xxx=“值”,当大家看到 data-xxx 的时候, 就知道这是一个自定义属性

    attr() 和 removeAttr()



    attr: attribute 属性

    attr()

    是一个读写的方法

    attr(要读取的属性名): 传递一个参数的时候是读取

    attr(属性名, 属性值): 传递两个参数的时候是设置

    removeAttr() 专门用来移除属性的

    attr 这套方法的注意:

    所有的属性都会显示在标签上(原生属性和自定义属性)

    不管你设置的是什么数据类型, 都会给你变成字符串

    removeAttr 删除 attr 设置的属性, 有多少删除多少(针对自定义属性)

    prop() 和 removeProp()



    prop: property 属性

    prop()

    一个读写的方法

    prop(要读取的属性名): 传递一个参数的时候是读取

    prop(属性名, 属性值): 传递两个参数的时候是设置

    removeProp()专门用来移除属性的

    prop 这套方法的注意:

    非原生属性, 不会显示在标签上, 但是你可以获取使用

    你存储的是什么数据类型, 获取的时候就是什么数据类型

    removeProp 删除 prop 设置的属性, 有多少删除多少(针对自定义属性)

    removeProp() 不能删除原生属性 id class style 等等

    data() 和 removeData()



    data: data 数据

    data()

    一个读写的方法

    data(要读取的属性名): 传递一个参数的时候是读取

    data(属性名, 属性值): 传递两个参数的时候是设置

    removeData() 专门用来删除数据的

    data 这套方法的注意:

    和元素的原生属性没有关系, 可以设置 id, 但是和元素的 id 没关系

    就是在元素身上给你开辟一个地方, 存储一些数据

    你设置的是什么数据类型, 拿到的就是什么数据类型

    removeData 删除 data 设置的属性

    data() 方法也能读取写在标签上的 H5 标准自定义属性

    三个方法存储内容

    attr 设置的自定义属性存储在标签身上

    prop 设置的自定义属性存储在元素对象里面

    data 设置的自定义属性存储在元素对象里面单独开辟的一个对象

    六 元素样式操作

    css()

    一个读写的属性

    不同操作需要 传递 不同的参数

    css('样式名称')

    css('width')

    获取元素的样式值, 不管是行内样式还是非行内样式都能获取

    css('样式名称', '样式的值')

    css('width', '200px')

    设置元素的样式值, 元素集合能获取多少个元素就置多少个元素

    设置的时候, 所有的单位都可以不写, 默认添加 px为单位

    css(对象)

    css({ width: 100, 不写单位默认是 px height: '200px', opacity: 0.5 })

    批量设置 css 样式

    给元素集合里面的所有元素, 批量设置样式

    七 绑定事件
  14. on()方法是专门用来绑定事件

    jQuery 里面通用的事件绑定方式

    不同操作 传递 不同参数

    on方法的各种参数描述

    on('事件类型', 事件处理函数)

    给元素集合内所有的元素绑定一个事件

    // 给 $('li') 获取到的所有元素绑定一个点击事件

        // $('li').on('click', function () {

        //   console.log('我被点击了')

        // })



    on('事件类型', '事件委托', 事件处理函数)

    把 事件委托 位置的元素的事件 委托给了前面元素合

        // 给所有的 li 标签设置事件委托, 委托给了 ul

        // $('ul').on('click', 'li', function () {

        //   console.log('我被点击了, 事件委托')

        // })



    on('事件类型', 复杂数据类型, 事件处理函数)

    给每一个元素绑定一个事件, 复杂数据类型是发事件时候传递的参数

     //   每一个 li 点击的时候, 都能得到中间那个对象

        //   就是事件对象了面

        // $('li').on('click', { name: 'Jack', age: 18 }, function (e) {

        //   console.log('我被点击了, li')

        //   console.log(e)

        // })

    1

    2

    3

    4

    5

    6

    on('事件类型', '事件委托', 任意数据类型, 件处函数)

    做一个事件委托的形式, 第三个参数位置的数据

    是触发事件的时候, 可以传递进去的数据

    on(对象)

    给一个元素绑定多个事件的方式 不能传参数

     // $('ul').on({

        //   click: function () { console.log('点击事件') },

        //   mouseover: function () { console.log('移入事件') },

        //   mouseout: function () { console.log('移出事件') }

        // })


  15. one() 方法是专门用来绑定一个只能执行一次的方法

    传递的参数个数和意义 于 on 方法一摸一样

    绑定上的事件只能执行一次
  16. off() 方法是专门用来解绑一个元素的事件的

    使用方式

    off('事件类型') : 给该事件类型的所有事件处理函数解绑

    off('事件类型', 事件处理函数) : 解绑指定事件处理函数

    注意:on 和 one 绑定的事件它都能移除
  17. trigger() 方法是专门用来触发事件的方法

    不通过点击, 通过代码把事件触发了

    trigger('事件类型') : 把该元素的事件给触发了
  18. hover()

    jQuery 里面唯一一个很特殊的事件函数

    表示一个鼠标悬停动作

    只有一个使用方式

    hover(鼠标移入的时候触发, 鼠标移出的时候触发)

     // hover 事件

        //   如果你只传递一个函数, 那么移入移出都触发这一个函数

        $('ul')

          .hover(

            function () { console.log('鼠标移入') },

            function () { console.log('鼠标移出') }

          )


  19. 常用事件

    jQuery 把一些常用事件直接做成了函数



    click()

    mouseover()

    . . . . . .

    直接使用就可以了



    使用 click 举一个例子



    click(事件处理函数)

    click(参数, 事件处理函数)

    参数: 触发事件的时候传递到事件里面的数据

        // 常用事件

        // 给 ul 绑定了一个点击事件

        // $('ul').click([1, 2, 3, 4, true], function (e) {

        //   console.log('你好 世界')

        //   console.log(e)

        // })

    1

    2

    3

    4

    5

    6

    八 节点操作
  20. 创建节点

    对应原生 js 里面的 createElement()

    $('html 格式的文本')

    // 创建一个 div 元素

        console.log($('<div>我是一个创建出来的节点</div>'))

    1

    2
  21. 插入节点

    对应原生 js 里面的 appendChild()

    内部插入

    放在页面元素的子元素位置, 放在末尾

    页面元素.append(要插入的元素)

    要插入的元素.appendTo(页面元素)

    放在页面元素的子元素位置, 放在最前

    页面元素.prepend(要插入的元素)

    要插入的元素.prependTo(页面元素)

    外部插入

    放在页面元素的下一个兄弟元素位置

    页面元素.after(要插入的元素)

    要插入的元素.insertAfter(页面元素)

    放在页面元素的上一个兄弟元素位置

    页面元素.before(要插入的元素)

    要插入的元素.insertBefore(页面元素)
  22. 删除节点

    对应原生 js 里面的 removeChild()

    页面元素.empty() -> 把自己变成空标签,将所有子元素移除

    页面元素.remove() -> 把自己移除

    没有删除某一个子节点的方法,因为 jQuery 的选择器的强大,直接找到要删除的节点, remove()
  23. 替换节点

    对应原生 js 里面的 replaceChild()

    页面元素.replaceWith(替换元素)

    替换元素.replaceAll(页面元素)
  24. 克隆节点

    对应原生 js 里面的 cloneNode()

    元素.clone()

    两个参数的值为 true或false

    第一个参数: 自己的事件是否克隆

    第二个参数: 子节点的事件是否克隆

    如果第一个参数的值为false,那么第二个参数不起作用,没有意义。

    不管你是否传递参数, 都会把所有后代元素都克隆下来

    元素 + 文本内容 + 属性 + 行内样式

    参数只决定是否克隆元素身上的事件

    九 获取元素尺寸

    尺寸: 元素的占地面积

    width 和 height

    padding

    border

    margin

    三套方法, 四种使用方式

    这些方法都是不考虑盒模型的状态(不管是什么型, 都是固定区域)

    width() 和 height()

    获取元素的 内容 区域的尺寸

    innerWidth() 和 innerHeight()

    获取元素的 内容 + padding 区域的尺寸

    outerWidth() 和 outerHeight()

    获取元素的 内容 + padding + border 区域的尺寸

    outerWidth(true) 和 outerHeight(true)

    获取元素的 内容 + padding + border + margin 区域的尺寸

    十 获取元素位置
  25. offset()

    offset: 偏移量

    是一个读写的属性

    读取

    不传递参数就是读取

    读到的元素相对于页面的位置关系

    返回值是一个对象 { left: xxx, top: xxx }

    书写

    传递一个对象就是写入 { left: xxx, top: xxx }

    注意: 绝对写入

    不管你本身和页面的尺寸是什么样,写多少就是多少
  26. position()

    postition: 定位

    只读的方法

    读取:

    元素相对于定位父级的位置关系

    得到的也是一个对象 { left: xxx, top: xxx }

    如果你写的是 right 或者 bottom, 会自动计算成 left 和 top 值给你

    十一 获取卷去的尺寸(页面滚动条)

    scrollTop()

    原生 js 里面 document.documentElement.scrollTop

    读写的方法

    不传递参数的时候就是获取卷去的高度

    传递一个参数就是设置卷去的高度

    scrollLeft()

    原生 js 里面 document.documentElement.scrollLeft

    读写的方法

    不传递参数的时候就是获取卷去的宽度

    传递一个参数的时候就是设置卷去的宽度

    十二 jQuery中的函数

    ready() 事件

    类似于 window.onload 事件,但是有所不同

    window.onload 会在页面所有资源加载行

    ready() 会在页面 html 结构加载完毕后执行

    也叫做 jQuery 的入口函数

    有一个简写的形式 $(function () {})

    each() 方法

    类似于 forEach(), 遍历数组的

    jQuery 的元素集合, 是一个 jQuery 数组, 不是一个数组, 不能使用 forEach()

    forEach语法: forEach(function (item, index) {})

    each语法:each(function (index, item) {})

    比较少用到, 因为 jQuery 隐式迭代 自动遍历

    十三 jQuery中的动画

    让元素出现不同的移动, 改变

    transition -> 过渡动画

    animation -> 帧动画

    标准动画

    show() 显示元素

    语法: show(时间, 运动曲线, 运动结束的函数)

    hide() 隐藏元素

    语法: hide(时间, 运动曲线, 运动结束的函数)

    toggle() 改变元素显示或隐藏(如果显示就隐藏,如果隐藏就显示)

    语法: toggle(时间, 运动曲线, 运动结束的函数)

    三个方法的参数都可以选填,不需要每个都填写

    折叠动画

    slideDown() 下滑显示

    语法: slideDown(时间, 运动曲线, 运动结束的函数)

    slideUp() 上滑隐藏

    语法: slideUp(时间, 运动曲线, 运动结束的函数)

    slideToggle() 切换滑动和隐藏

    语法: slideToggle(时间, 运动曲线, 运动结束的函数)

    渐隐渐显动画

    实质是透明的opacity的变化

    fadeIn() 逐渐显示

    fadeIn(时间, 运动曲线, 运动结束的函数)

    fadeOut() 逐渐消失

    fadeOut(时间, 运动曲线, 运动结束的函数)

    fadeToggle() 切换显示和消失

    fadeToggle(时间, 运动曲线, 运动结束的函数)

    以上三个方法的参数,均有默认值

    fadeTo() 设置元素透明度变为你指定的数字

    fadeTo(时间, 你指定的透明度, 运动曲线, 运动结束的函数)

    综合动画

    animate()

    基本上大部分的 css 样式都可以动画

    transform 不行, 颜色不行

    语法: animate({}, 时间, 运动曲线, 运动结束的函数)

    { }里面就写你要运动的 css 属性,默认单位为px

    停止动画

    让当前的动画结束

    因为 jQuery 的动画你一直点击,就会一直触发。即使不再点击让事件发生,还是会把没执行完的动画执行完毕。

    你点击 10 次, 他就会触发 10 次, 直到 10 次全都完毕才结束

    stop()

    当这个函数触发的时候, 就会让运动立刻停下来

    你运动到哪一个位置了就停止在哪一个位置

    finish()

    当这个函数触发的时候, 就会让运动立刻停下来

    不管你运动到了哪一个位置, 瞬间到达运动完成位置

    十四 jQuery发送ajax请求

    jQuery 里面帮我们封装好了几个方法

    专门用来发送 ajax 请求的

    $.get() -> 专门用来发送 get 请求的

    $.post() -> 专门用来发送 post 请求的

    $.ajax() ->

    发送什么请求都可以(get, post, put, delete)

    并且还可以发送一个 jsonp 请求

    jQuery 发送一个 GET 请求

    语法: $.get(请求地址, 需要携带到后端的参数, 成功的回调函数, 期望后端返回的数据类型)

    请求地址: 你要请求的后端接口地址(必填)

    携带参数: 你需要给后端传递的参数

    可以是一个固定格式的字符串 ‘key=value&key=value’

    也可以是一个对象 { a: 100, b: 200 }

    成功回调: 当请求成功的时候会执行的函数

    期望数据类型: 就是你是不是需要 jQuery 帮你解析响应体

    • 默认是不解析
    • 当你传递一个 ‘json’ 的时候, 会自动帮你执行 JSON.parse()

          // 打开页面就发送 GET 请求了

          // $.get('./server/get.php', 'a=100&b=200', function (res) {

          //   // res 就是后端返回的数据, 也就是响应体

          //   // console.log(JSON.parse(res))

          //   console.log(res)

          // }, 'json')



          // $.get('./server/get.php', { a: 300, b: 400 }, res => {

          //   console.log(res)

          // }, 'json')

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      jQuery 发送一个 POST 请求

      语法: $.post(请求地址, 需要携带到后端的参数, 成功的回调函数, 期望后端返回的数据类型)

      四个参数和 $.get 是一摸一样的

          // 打开页面就发送 POST 请求了

          // $.post('./server/post.php', 'c=hello&d=world', function (res) {

          //   console.log(res)

          // }, 'json')



          // $.post('./server/post.php', { c: '你好', d: '世界' }, res => {

          //   console.log(res)

          // }, 'json')



      jQuery 的 $.ajax 方法

      用来发送综合 ajax 请求的(GET, POST, PUT, …)

      语法: $.ajax(对象)对象是对本次请求的所有配置
    • $.ajax({

          url: '', // => 请求地址(必填)

          type: '', // => 请求方式(GET, POST, ...) 默认是 GET

          data: '', // => 携带到后端的参数

          dataType: '', // => 期望后端返回的数据类型, 默认不解析

          async: true, // => 是否异步, 默认是 true

          success: function () {}, // => 成功的回调

          error: function () {}, // => 失败的回调

          timeout: 数字, // 单位是 ms, 超时时间(超过你写的时间没有响应, 那么就算失败)

          cache: true, // 是否缓存, 默认是 true

          context: 上下文, // 改变回调函数里面的 this 指向

                  ...

                })



      $.ajax 里面失败的回调



      不光是请求失败的时候会触发

      jQuery 认定失败就是失败

      当 dataType 写成 json 的时候, jQuery 会帮我们执行 JSON.parse()

      当后端返回一个不是 json 格式的字符串的时候

      执行 JSON.parse() 就会报错

      也会执行失败的回调, 请求虽然成功, 但是解析失败了, 也是失败

      JSON.parse(‘你好 世界’) -> 就会报错了

      $.ajax 里面是否缓存的问题



      这个请求要不要缓存

      当两次请求地址一样的时候, 就会缓存

      如果你写成 false, 表示不要缓存

      jQuery 就会自动再你的请求后面加一个参数 =时间戳

      第一次请求 ./server/get.php?
      =11:10:01.325的时间戳

      第二次请求 ./server/get.php?_=11:10:02.326的时间戳

      $.ajax 里面的回调 this 指向问题



      ajax 的回调里面默认 this 指向被 jQuery 加工过的 ajax 对象

      context 的值你写的是谁, 回调函数里面的 this 就时谁

      $.ajax 里面的请求方式的问题



      $.ajax 这个方法里面, type 表示请求方式

      jQuery 还给了我们一个参数叫做 method,也表示请求方式

      当你写请求方式的时候

      可以写成 type: ‘POST’

      也可以写成 method: ‘POST’

      $.ajax 里面的接收响应的问题(2015年以后的版本才有 promise 的形式)



      jQuery 默认把 ajax 封装成了 promsie 的形式

      你可以用 success 选项接收成功的回调

      也可以用 .then() 的方式接收响应

      jQuery 的 ajax 全局钩子函数

      钩子: 挂在你的身上, 你的所有动作都和它有关系

      这些全局函数都是挂在 ajax 身上的, 这个 ajax 的每一个动作都和全局函数有关系

      全局的钩子函数

      1.ajaxStart()

      会在同一个作用域下多个 ajax 的时候, 第一个 ajax 之前开始的时候触发

      如果有多个 ajax 他只触发一次

      2.ajaxSend()

      每一个 ajax 再发送出去之前, 都会触发一下

      xhr.send() 之前触发

      ajaxSuccess()

      每一个 ajax 再成功的时候触发

      只要有一个 ajax 成功了就会触发

      ajaxError()

      每一个 ajax 再失败的时候触发

      只要有一个 ajax 失败了就会触发

      ajaxComplete()

      每一个 ajax 完成的时候触发

      只要有一个 ajax 完成了, 不管成功还是失败, 都会触发

      ajaxStop()

      会在同一个作用域内多个 ajax 的时候, 最后一个 ajax 完成以后触发

      如果有多个 ajax 它只触发一次

      作用: 通常用来做 loading 效果

       <img src="./loading.gif" alt="">

      // 利用ajax钩子函数 做一个lading效果  等待页面

       // 提前利用钩子函数准备 loading 效果

          // 每一次发送出去的时候都要显示图片

          $(window).ajaxSend(() => {

            $('img').show()

          })



          // 每一次完成的时候都要图片再隐藏起来

          $(window).ajaxComplete(() => {

            $('img').hide()

          })



          // 每次点击按钮的时候都会发送一个 ajax 请求

          $('button').click(() => {

            // 发送一个 ajax 请求

            $.ajax({

              url: './server/get.php',

              data: { a: 100, b: 200 },

              dataType: 'json',

              success: function (res) {

                console.log('请求成功了')

                console.log(res)

              }

            })

          })

      十五 jQuery 发送一个 jsonp 请求

      jQuery 也提供给我们发送 jsonp 请求的方式

      jsonp: 利用 script 标签的 src 属性来请求

      返回值: 是一个字符串, 字符串里面写了一个 函数名(后端传递给前端的参数)

      使用 $.ajax() 这个方法

      必须写的:dataType: 'jsonp'

      发送 jsonp 请求

      jQuery 帮我们准备好了一个函数名, 并且以参数的形式带到了后端

      jQuery 帮我们带过去的 callback 参数, 就是它准备好的函数名

      后端就应该返回一个 jQuery 准备好的函数名()

      其他参数

      jsonp: '', 你带到后端表示你函数名的那个 key, 默认值是 callback

      cache: false, 当 dataType === ‘jsonp’ 的时候, 默认 cache 就是 false

       // 发送一个 jsonp 请求

          $.ajax({

            url: 'http://127.0.0.1/server/jsonp.php',

            dataType: 'jsonp', // 表示我要发送一个 jsonp 请求

            jsonp: 'cb', // 表示参数里面的 cb 属性时我准备好的函数名

            cache: true, // 表示缓存本次请求

            success: function (res) {

              console.log(res)

            }

          })







          //   jQuery 准备好的函数名

          //     + jQuery34108160883644340862_1582255906750

          //     + 变量名包含 数字 字母 下划线 $

          //     + function jQuery34108160883644340862_1582255906750() {}



      十六 jQuery 的多库并存机制

      因为 jQuery 引入页面以后, 向全局添加了两个名字

      一个叫做 $

      一个叫做 jQuery

      万一有别的类库也起名叫做 jQuery 或者$ 怎么办

      当我两个库都需要使用的时候

      因为向全局暴露的名字一样, 就会发生冲突了

      谁的文件引再后面, 谁的名字就占主要位置了

      两个只能选择一个使用

      jQuery 提供了一个方法

      我可以不占用$ 或者 jQuery 这个名字

      noConflict()

      语法: $.noConflict() 或者jQuery.noConflict()

      当你执行了 noConflict() 以后, jQuery 就交出了$的控制权。

      jQuery向全局暴露的不在有$ 这个名字了。当你执行了noConflict(true) 以后, jQuery就交出了 $ 和jQuery 的控制权。

      交出去以后, 我的 jQuery 就用不了

      noConflict() 的返回值: 就是一个新的控制权

      你只要接收一个返回值, 你定好的变量是什么,jQuery 的控制权就是什么

       // 交出 $ 的控制权

          // $.noConflict()



          // 交出 $ 和 jQuery 的控制权

          // $.noConflict(true)



          // 改变 jQuery 的控制权

          var $$ = $.noConflict(true)



      十七 jQuery 的插件扩展机制

      jQuery 还提供给我们了一个机制, 就是你可以向 jQuery 里面扩展一些方法



      两个方法



      $.extend()

      扩展给 jQuery本身使用的

      语法:

      $.extend({ 你要扩展的方法名: function () {}, 你要扩展的方法名: function () {}, ... })

      使用的时候就是 $.你扩展的方法名()

      $.fn.extend() => $.extend($.fn, { 你扩展的方面名 })

      扩展给 jQuery 元素集合使用的



      语法 $.fn.extend({ 你要扩展的方法名: function () {}, 你要扩展的方法名: function () {}, ... })



      使用的时候就是 $(选择器).你扩展的方法名()



      $('div').html()



            // 1. 扩展给 jQuery 本身

          //    jQuery 本身没有操作 cookie 的方法

          // $.extend({

          //   setCookie: function (key, value, expires) {

          //     // 写上设置 cookie 的方法

          //     if (expires) {

          //       var time = new Date()

          //       time.setTime(time.getTime() - 1000 60 60 8 + 1000 expires)

          //       document.cookie = ${key}=${value};expires=${time}

          //     } else {

          //       document.cookie = ${key}=${value}

          //     }

          //   },

          //   getCookie: function (key) {

          //     // ...

          //   }

          // })



          // 使用我们扩展的方法去设置 cookie

          // $.setCookie('a', 100)

          // $.setCookie('b', 200, 10)





            // 2. 扩展给元素集合

          //    扩展一个全选的方法

          //    方法以执行, 就能让 input checkbox 变成选中状态或者不选中状态

          $.fn.extend({

            selectAll: function (type = true) {

              // type 就是你传递进来的选中或者不选中一个标志

              //   你不传递的时候, 我默认是 true, 你传递了就用你传递的

              // console.log(this) // 就是你调用的时候前面的哪个元素集合

              this.each(function (index, item) {

                // 让元素集合中的每一个 input 的 checked 属性为 true

                item.checked = type

              })



              // return 这个元素集合, 达到一个链式编程的效果

              return this

            }

          })





          $('button').click(() => {

            // 让所有 input 框变成选中状态

            console.log($('input').selectAll().attr('hello', 'world'))

          })



      十八 jQuery 的拷贝对象问题

      $.extend() 深拷贝 与 浅拷贝

      传递一个对象的时候, 可以做到插件扩展机制

      传递多个对象的时候, 可以将后面几个对象的内容复制到第一个对象里面

      语法:

      $.extend(是否深拷贝, 对象1, 对象2, 对象3, ...)

      是否深拷贝: 默认是 false, 可以不写

      从 对象2 开始, 后面所有对象的内容都会被拷贝到 对象1 里面

      再拷贝的时候, 如果有重复的 key, 那么以写在后面的为准(后来者居上)

      十九 jQuery 的插件

      基于 jQuery 使用的, 别人封装好的插件



      我们拿来使用就可以了, 前提就是要有 jQuery



      例子 一个叫做 jquery-validate 的插件



      专门用来做表单验证的

      你输入的内容是不是符合规则

      下载

      引入文件

      去复制粘贴


      <!-- 引入文件 -->
      <!-- 注意: 先引入 jQuery, 后引入 jquery-validate -->
      <script src="./jquery/jquery.min.js"></script>
      <!-- jquery-validate 这个文件依赖的 jquery -->
      <script src="./jquery-validate/jquery.validate.min.js"></script>
      <!-- 引入中文信息提示包, 必须在 jquery-validate 的后面 -->
      <script src="./jquery-validate/localization/messages_zh.min.js"></script>
      <script>
      
        // 选择到你要验证的表单的 form 标签
      //   执行 validate 方法
      //   {} 里面就写我们的验证规则
      $('#login').validate({
      // 你需要的验证规则
      rules: {
      // key 就是你要验证的哪个 input 框的 name 属性
      username: 'required', // 用户名必填
      password: { // 一个字段可以写多个验证方式
        required: true,
        minlength: 6, // 最少是六个
        maxlength: 12, // 最多十二个
      }
      },
      // 你自定义提示的文本内容
      messages: {
      // key 就是你验证的哪个 input 框的 name 属性
      username: '请输入用户名! ^_^',
      password: {
        required: '请输入密码!',
        minlength: '最少要输入 6 个字符噢!'
      }
      },
      // 表单的提交事件
      //    这个函数会在表单验证通过以后执行
      submitHandler: function (form) {
      // form 接收的就是你的 form 标签
      // console.log(form)
      // console.log('表单验证通过了, 我需要使用 ajax 去提交数据了')
      
      // 有一个 jQuery 的方法
      // serialize() 快速获取表单输入的数据
      //  $(form).serialize() 就能拿到这个 form 标签里面的表单数据
      // console.log($(form).serialize())  // username=admin&password=123456
      
      // 发送请求到后端
      $.post('./server/login.php', $(form).serialize(), res => {
        console.log(res)
      }, 'json')
      }
      })
      

      ————————————————
      版权声明:本文为CSDN博主「孔四月」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
      原文链接:https://blog.csdn.net/k464746/article/details/104685150

UI配色方法及避坑指南

雪涛

不管是做 UI 设计还是画插画,有很多同学觉得自己是因为天赋不够所以对色彩的敏感度不够,其实不然。一个可能是大家总结的太少,从来都是凭感觉和运气去配色,但配色都是有讲究的。本文不会给大家重复讲解什么是 rgb,什么是 hsb,什么是 cmyk 或者什么三原色,这些大家都可以从网上直接搜到。我今天要给大家分享的是人们是如何认识色彩,并且在产品设计中使用的。

人类对色彩感知的原理

大家都知道,对于不同的颜色,我们对其的感知是不同的,有人觉得暖色在前,冷色在后。暖色更醒目,冷色不醒目。那这是什么原因呢?首先我们要知道眼睛内存在两种感光细胞:视锥细胞和视杆细胞,视杆细胞能够感知光线强弱但无法感知颜色,而视锥细胞却相反,视锥细胞内还有 3 种对不同频率光敏感的细胞。我们经常会用到视锥细胞,而视杆细胞却用的少,更多的是在黑暗的环境中使用的多。

视锥细胞的三种类型分别是低频、中频和高频视锥细胞,分别对红、绿、蓝三种颜色的光敏感。而且这三个视锥细胞分别也有重合的部分。低频视锥细胞对整个可见光频谱都敏感,它的范围包含的比较广,特别是对于频谱中段的黄色到红色部分更加敏感。但是像高频的紫色几乎只有蓝视锥细胞可以感知。

大家在平时生活中都能看到,在马路上、机动车道上以及一些警示牌都会采用黄色、橙色等标识,因为这些非常醒目。更容易被红视锥细胞感知到,但如果你的标识用的是冷色调那这个交通事故可能要发生的频繁得多。

1. 人对色彩边缘的对比更加敏感

我们来做个实验,如下图,大家觉得在中间的灰色块是纯色还是渐变色,可能很多同学看上去都会觉得是个渐变色,但其实它就是一个纯色,不信的同学可以自己在工具中尝试一下。

但如果你把这个色块拿出来后,不在这个环境中直接进行边缘对比,那就不会出现渐变的情况了。光说原理,我们也来看一下在产品设计中需要注意的地方,因为在 UI 界面设计中我们通常需要把一些图片、卡片叠加放置,这样就会造成边缘视觉的对比,本来不明显的两个元素重叠之后变的很明显,例如一些标签的背景色和页面整体的背景色。

如果你想要让两个颜色接近的元素具有识别度,那么最好将这两个元素进行重叠摆放而不是分开摆放。另外,如果是卡片样式的设计,背景色一定不要过于灰暗也不要过于浅白,过于深的话会让卡片轮廓过于明显而导致整体看上去显脏以及很明显的对比,显得不自然和舒适。如果过于浅的话也会导致信息的不聚焦。

还有,为什么被框起来的文字会看上去更加有点击的欲望其实也是这个道理,因为文字和背景叠加产生的轮廓只是文字的轮廓,在我们的第一印象中只是一种符号。当它被赋予颜色之后,我们才会意识到它需要我们去注意或者可被点击,但依然不够明显,所以为了强化可点击这个感觉,我们才用了线框、背景色、箭头等方式。

色彩在UI设计中的作用

1. 加深品牌印象与品牌感

一般来说,产品都会有一个品牌的主色。而这个品牌的主色也通常会运用在外面的产品界面中,所以例如闲鱼、马蜂窝等,主色都采用了黄色,黄色具有非常活泼、有趣、好玩的特性,无论是线上还是线下都使用了这个品牌黄色,从每一个线上元素的主色,到线下包装的印刷色。

但一定要注意的是,如果品牌的主色偏灰偏暗的话,可能不太适合线上的产品进行通用。例如之前的严选、云集、711便利店、宜家等产品的主色都是偏深和暗的,所以在线上的界面用起来会非常不和谐,和整体偏浅色、轻的风格对比起来太强烈,引起不适。

而且线上觉得还不错的颜色,由于印刷的原理,实物也会更加偏低饱和和偏暗。

2. 引导用户视觉凹增加易读性

我们在《如何有理有据做设计,而不是凭感觉?》里提到了人们如何阅读信息,提到了一个视觉凹的概念。所以在界面中,什么样的地方使用色彩是有讲究的。所以在这里通常会需要使用颜色的地方在于希望引导用户和吸引用户注意的地方才会使用色彩。例如下方产品,使用了高亮色来引导用户视觉。

当然色彩的运用也会将整个页面的层级凸显出来,而不单纯的用中性色来区分层级。

3. 区分信息交互的状态

同样是上两张图,大家可以清晰的看到,美团中的附近热卖好点、满减标签、价格,其实都只具备信息的呈现,但不具备交互的特征和状态。但淘票票中的「4.7万」和「展开」却不一样,「展开」使用了辅助蓝色,这里的展开就具备这个文案所描述的这个控件具备的交互特性──点击后将隐藏的文字展示出来。蓝色一般我们都会使用在某个可点的链接上,当然也会有其他的色彩来表示可点击。

所以不是所有的元素都要赋予颜色,这样会使整个页面非常混乱。

另外,UI 设计中主色除了引导用户的作用外,也可以表示当前正被激活的信息状态。例如爱奇艺 app 中播放详情页面,当前版块标签和正在播放剧集的激活状态。

4. 营造氛围传递热度

色彩除了上方所述的字段中的不同使用,在图片和整体氛围营造中也起了很大的作用,目前很多 2c 的产品往往会在界面氛围的营造中运用一些手段。例如导航栏、底部标签栏上的图标,或者在首页营销版块的瓷片区域都会用品牌色在活动时段内进行氛围打造。

在UI设计中色彩运用的坑与技巧

1. 色彩的正反两面

在色彩的心理学上,大家都知道每个颜色具有一定的性格特征和表达。而且都会有正反两面,可以看下方多种色彩的描述。

然而其实很多的产品使用的色彩和我们所认知的会有一些差别,比如咖啡品牌的主色选择,在我们常规人之中,咖啡应该是褐色、棕色,但是大家看到星巴克、瑞幸、漫咖啡其实都用了和咖啡本质没什么关系的颜色。

在瑞幸刚出来的时候,很多人其实不太习惯把这个蓝色和咖啡结合起来,但是为了塑造品牌差异化,瑞幸一直将「蓝色」作为品牌的主基调,「小蓝杯」这一称呼不但让消费者感到亲切,也在众多的咖啡中有了属于自己的记忆点。在这支广告片中,主基调同样是使用蓝色,不但符合了当下消费者的视觉偏好,也在为用户留下记忆点之后,让用户在看到蓝色时自然而然地想到瑞幸咖啡。

2. 颜色的禁忌用法

但凡各位使用了这样的配色,保证各位过不了试用期,相信我。所以大家千万要避开。

高饱和度的色彩

高饱和度的色彩,会让人产生「幻觉」!让人产生视觉疲劳,例如我将饿了么这个界面的色调调整一下大家看一下,不亮瞎算我输。

灰部使用过多的配色

为什么很多时候我们总觉得界面脏兮兮的。是因为我们在界面或者配色中使用了过多的低饱和度、灰度较多的配色,所以这也是要避免的。

没有规律且过多的配色

让界面或者插画看起来非常混乱。一般来说颜色的使用也需要有侧重点,所以我们常用的方法是6、3、1的色彩配比。

荧光色

荧光色绝对不可以使用在 UI 界面中,尤其是主色。

太轻柔的颜色

在很多 dribbble 的飞机稿中,经常能看到这样的配色和练习。无论是在练习中还是实际项目中,这样的界面也完全无法让用户看到想看的信息,没有重点且轻飘飘的感觉。

现在很火的新拟物化设计

说真的,这样的风格确实耳目一新,但个人觉得可能不会成为主流。因为它就和第五种一样:信息可识别性很差。且不谈色弱的人群,就正常的用户来说大面积的白色+饱和度低的元素结合,感觉就是得了「白内障」。另外我们常说的一点就是所有元素都强调就等于什么都没有强调,这样的风格在每一个元素都具有阴影的情况下都在争先恐后让用户感知,原则是轻量化却又需要那么多阴影,这样就有点自相矛盾的感觉。

为了营造这样的「新拟物」的轻量氛围,还不得不在整个界面中简化大部分元素,能不加文字就不能加文字。有一句话一直非常影响我做设计:「设计是需要被简化的,但是简化的过程一定不简单」。所以不是单纯的简化所有元素为了达到这个风格的目的。

不要将对抗色重叠

例如下方,两种对抗色重叠后会引起视觉闪烁的感觉。

正确的UI配色方法

1. 定义主色

首先我们必须要说,色彩肯定是需要结合产品和用户的定位去指定和提炼的,所以前期会需要去做一些研究,例如用户画像,品牌冲刺或者是情绪板等方法。得到几类「真实的虚拟用户」,从而确定一些主色的方案。然后我们在主色的选择中需要避开上面提到的坑,并且对市面上的 app 进行总结,我们发现大部分的产品色,简单来讲在我们 HSB 模式中取色都在一个固定的范围,就像这样。

在上文中也说到用色比例的 631 法则,所以在选取辅助色的时候我们需要定义好辅助色可以用在什么地方。例如知乎,其实辅助色没有非常明显的一种或者两种,都是多色的辅助色方案,都在一个配色的系统中选取颜色即可。大部分产品目前都是这样的策略,一个主色搭配多个辅色,如果有其他独立的板块可能需要重新定义专属的配色策略。

2. 定义中性色

其次再定义中性色,比如字体和线条以及背景色。字体是为了让信息有对比,显示层级,那么通常给 2-3 种层级即可,至少 2 种,至多 3 种。在选择 3 个层次的中性色文字时,给大家一个建议:标题/正文文字颜色 HSB 的 B 值不要大于 20,备注和次要文字 b 值不要大于 50,默认文字不要大于 80,大家可以去尝试一下,且中性色不得使用纯黑。


文章来源:优设   作者:应俊

从总统级厨师到奥美创始人,他是如何构建广告帝国的?

雪涛

广告圈「门槛低」、「是个人都能做」,这种印象可能来源于,世界上最出名的广告公司之一——奥美的创始人,他是个厨师。除了当过厨师,还做过推销员,调查员,政治秘书,还种过几年地,最后成了 1960 年代,极负盛名

阅读文章 >>

1914 年夏天,一战爆发了。在伦敦郊区的萨里郡,一个商人正脸色凝重坐在椅上发呆。他破产了,战争将一切都化为乌有,这对商人的儿子而言,意味着再也吃不到冰淇淋了。这个孩子刚满 3 岁,名字叫大卫·奥格威。

作为英格兰的名门望族,奥格威一家都不是吃素的。父亲和兄弟是名人,爷爷是富商。所以即使破产了,奥格威也能上贵族学校,先后受教于艾丁堡斐特思公学及牛津大学,成为众人眼中的「明日之星」。

然而他并没有毕业,他用自己的行动证明了自己是个弟弟,两年的大学时光,奥格威逢考必挂,最后被牛津大学扫地出门。他既没有文凭,也没有钱,索性在美琪饭店当起了实习厨师。

凭着天生的聪明才智,奥格威很快在美琪饭店混得风生水起。1932 年,一个月黑风高的晚上,法国总统保罗·杜梅像往常一样,来到了饭店享用晚餐,当吃到奥格威做的一款甜品后,不自觉地发出了由衷的赞叹:「C’est bon!」(法语:好吃死了!)

三周后,杜梅总统就死了,当然这不是因为吃了奥格威的甜点,而是吃了一个苏联人的子弹。

面对闷热的后厨,繁重的工作压力,让奥格威苦不堪言。奥格威选择结束了厨师生涯,回到了英国推销起了炉具,这个炉灶,就是鼎鼎大名的 AGA(雅家)。2015 年 3 月,AGA 曾在北京举办过一场发布会,现场一套蓝色 AGA TC 炉灶售价人民币 28 万元。

每天出入饭店、古堡、修道院的奥格威,业绩月月拿销冠,公司还委托他写了一本销售手册。奥格威当时甚至想过把「如何将炉具卖给盲人主妇」这些细节也写下来,这份推销书后来被《财富》称为「有史以来最好的销售手册」。

1936 年,他的哥哥为他在伦敦一家广告公司谋得实习的机会。此时的奥格威还是个广告菜鸟。他的创作「秘诀」,是从芝加哥订购一份美国剪报,挑选好广告一字不落抄袭,然后提交给他的英国客户。

由于表现出色,公司决定送他到国外学习美国广告技术,为时一年。这一年,他收获颇丰,不仅学业有成,而且邂逅了 18 岁的女学生。二战爆发的那一年,他们喜结连理。

△ 奥格威和他太太合照

1938 年,奥格威移居美国,在盖洛普咨询公司任研究员,为好莱坞制片商做民意调查。天赋异禀的奥格威能在开拍前预测出电影的票房,误差<10%。一时间迪士尼、华纳、米高梅纷纷上门求合作。

△ 在街头做民意调查的奥格威

1939 年 9 月,二战爆发,次年法国沦陷。凭借数据领域的造诣,奥格威受邀加入英国情报机构,出任英国驻美使馆二秘。战后他辞去了公务员工作,做起了农民,农作物是大烟。奥格威甚至迷上了这段采菊东篱下的农耕日子,但他深知自己无法以务农为生。

于是 1948 年,奥格威回到纽约,用 6000 美刀创办了自己的公司,取名「奥美广告」。在麦迪逊大街贴出一个别出心裁的招聘海报,上面传达了三点内容:

  • 公司新近成立,员工需要加班工作,工资则低于一般水平。
  • 招聘精力充沛,有头脑的年轻人。
  • 在 1960 年之前,这必将成为一家大公司。

至此,奥美广告公司正式成立。算上奥格威共两名员工,整天大眼瞪小眼。为了活下去,奥格威接了当时能够接到的所有订单。包括一个毫不知名的小制衣厂哈撒韦。当时他们告诉奥格威,只有 3 万美元预算,却想和知名衬衣品牌竞争。

当时奥格威都快哭了。预算少要求极高,还不因为效果而解约。但谁让他叫大卫呢,过人的天赋让他的广告在全国走红,仅用 3 万美元,让销售额翻了三番。使这家默默无闻了 100 多年的衬衫品牌,一夜之间闻名全国。更令人无法想象的是,这个创意被沿用了 25 年。

广告为产品增添了来自远方的神秘感,激发读者对狂野的无限遐想。「传达一种特别的信息以取悦读者」。这本来是奥格威准备的 18 个方案中被否决的一个,但他想,给其中一只眼睛戴个眼罩也无妨,于是在影棚的路上买了个眼罩交给模特。

随后,劳斯莱斯花了 5 万美元找奥格威做的一支广告再次成为经典,在时速 60 英里时,这辆新款劳斯莱斯车内最大的噪声,来自它的电子钟。不用多说了,时至今日这依然是最有名的汽车广告之一。这些广告让奥美的名声如日中天,赢得客户如探囊取物。

后来广告界盛传,说奥格威是一个奇才,好几家大广告公司都提出收购意向时,奥格威却回绝了。多年后他回忆,如果当时诱他以金钱,他肯定就屈服了,但他们却以为奥格威在乎的是「创作的挑战」。

与其说创作是一种挑战,还不如说是一种依据特定原则的模式生产,他甚至禁止员工使用「创作」形容他们的工作。因为在奥格威看来,好的广告是「99% 的调查研究+ 1% 的灵感」。例如奥格威发现标题加入感情色彩的词可强化广告效果,经过几百个词的测试,「Darling」(亲爱的)一词高居榜首。于是他将它运用到多芬的广告,后来多芬成为了同类产品中最畅销的品牌。不久奥格威表示,他并不知道洗澡时使用电话是危险的。

奥格威出生名门,却家道中落,是牛津的明星,却被扫地出门,他为法国总统下过厨,也给国王当过特工。他对市场一无所知,从未写过一篇文案,直至 38 岁尚未正式涉足广告业,口袋只有区区的 6000 美元原始资金……但 3 年之后,这个一度黯淡的男人已在行业发光发热,犹如创造了一个奇迹。

1963 年,奥格威著书《一个广告人的自白》。可以说奥格威是一个超越了时代的牛人,他里面的一些理论,对我们现在做电商一点都不过时,有兴趣的小伙伴可以买一本看看。

奥格威凭借他独特的人格特征和洒脱的世界观征服了许多人,那么他的魅力到底在哪,不妨让我们走进他的思想世界,亲身领略一番这个奥美开山鼻祖的风采。

1973 年,奥格威正式退休。他在童话般美丽的法国多佛,买下一座 700 年历史的古堡,过起了隐居生活。从那时起,路过的游客们,时常看到这样一幅画面:一个晴天的午后,阳光透过一棵 17 世纪的冬青树,将星星点点遍洒小径。小径的一旁,一个衣衫褴褛的老头儿,正在仔细地修剪玫瑰花枝。老头儿的嘴里碎碎地念叨着:「终于,可以安心做个农民咯~」

在他的广告帝国之中,他的影响力深广依旧,直至 1999 年最终逝去。奥格威的故事到这就结束了,而离新的篇章,奥美中国的故事也并不遥远了。

让我们把时间拨回到 1979 年,彼时随着改革开放的深入,《文汇报》宣布了商业广告的正式回归。奥美广告快速响应政策的变化,于同年推出中国大陆地区的第一支作品——雷达表广告正式出道。如今再提起雷达表,相信很多 60、70 后依然对当年那则「轰动」的老广告印象深刻。

1997 奥美中国在华推出大众桑塔纳,这款车型很快红遍大江南北。当时的广告语「拥有桑塔纳,走遍天下都不怕」使用了近十年。在 1978 年年底,中国改革刚刚拉开崭新的序幕,当时的德国大众是唯一既愿意提供技术,又肯投入资金的汽车公司,可以说大众陪伴中国人从贫穷走向富裕,国人对着大众品牌有着不同的感情。

再把时间轴往后拨一下,来到千禧年的后 4 年,2004 年「我的地盘听我的」成为了年轻人最潮流、最个性的语言之一,奥美为中国移动「动感地带」所做的数字营销战,为奥美中国赢得了第一座戛纳国际创意节狮子奖杯。

作为客户品牌,「动感地带」并不是中国移动的第一个品牌,早在「动感地带」之前,「全球通」和「神州行」两大品牌早已存在,可以说,中国移动当时非常精准地找到了年轻人这个用户群体。在「动感地带」推出的第一年,中国移动就快速发展了 1000 万「动感地带」用户。

在 2011 年,大卫·奥格威迎来百岁诞辰,奥美进驻中国 20 周年,作为创始人的奥格威应该十分欣慰。而在 2012 年奥美中国凭借 「可乐手」在戛纳国际广告节首次斩获奥美亚太区首个「全场大奖」。

这个新颖的平面设计是可口可乐公司「快乐畅开」营销活动的环节。「快乐畅开」旨在为全世界人们的生活带来欢笑和快乐。这个标新立异的设计清晰地传达了分享的概念。整个视觉表达仅仅由两个显而易见的独特元素组成:「动感飘舞的丝带」和「经典曲线瓶」, 它们都是可口可乐全球使用的商标元素。

不得不羡煞旁人的是,这个广告是一个 20 岁仍在设计学校念书的香港设计师完成的。

奥美中国的故事也差不多完结了,最后放一些我收集的奥美广告,或许里面的 idea 会让你拍案叫绝。

由香港奥美公司为肯德基制作的平面广告,利用鸡翅的外形和火焰联系起来,用视觉暗喻突出肯德基鸡翅的热,辣的卖点。

由泰国奥美公司为乐高制作的平面广告,小孩通过玩乐高玩具拼凑自己的梦想。

由巴西奥美公司为 Petz 创建的平面广告,宠物可以成为一个很好的伴侣,去倾听主人的说话。

Amnesty International,德国奥美公司为国际特赦组织制作的平面广告,难民看窗外的景象像在看电视一样,我们可以关掉它,但他们不能。

德国奥美公司为海洋守护者协会制作的平面广告,塑料垃圾正在淹没我们的海洋,他们吃什么你就吃什么。

美国奥美公司为海明威基金会制作的平面广告,再现了书本里的故事,《老人与海》、《死在午后》。

印度奥美公司为曼妥思公司制作的平面广告,恶魔附身都被酸得逃之夭夭。

法国奥美公司为可口可乐公司制作的户外广告,两只手的负空间形成了可口可乐最经典的曲线瓶。

由印度奥美公司为世界自然基金会制作的平面广告,利用树的外轮廓,拼凑出三只可爱的小动物,树木拯救野生动物,野生动物拯救树木。

日本奥美为 ADOT 制作的平面广告,语言可以消灭战争。

泰国奥美公司为 Poly-Brite 制作的印刷广告,高吸水性抹布,强调产品的卖点。

由泰国奥美公司为乐高制作的平面广告,对于任何大小的想象。

奥美中国为 Saky 设计的平面广告,刮掉顽固食物。

越南奥美为世界自然基金会制作的平面广告,犀牛角和人的指甲是完全一样的材料,还想要吗?

由巴西奥美为克拉罗制作的平面广告,只需要一个字母就能造成车祸,请不要开车发信息。


文章来源:优设    作者:研习社

返回、取消与关闭的使用逻辑

雪涛

在页面导航栏中,常会见到返回、取消与关闭三者按钮。许多同学会弄混它们的使用逻辑,所以写一篇小文帮助各位梳理下。

返回和关闭

先抛开图标,我们回到功能本身的含义上看。如果我们不在产品的语境里,就单看「返回」和「关闭」这两个词,你首先会想到什么呢?

当我这么去问自己的时候,脑子里出现的并不只是零碎的词语,而是一些场景和画面。比如我走错路了,需要原路返回;公司复工了,我要返程回去。或者,睡觉时间到了,我该关闭电脑了;饭菜烧好了,我得把油烟机关掉,等等。

如果仔细去想的话就会意识到,语义衍生出来的,都是我们日常生活中的经验和对世界的认知。产品中使用的各种语言,不管是文字也好,或者图标图形也罢,一直都是以我们对它最本能的理解为基础的。所以只要你联想自己对「返回」和「关闭」的看法,就能知道它应该在什么样的产品情境中出现,以及它为什么会出现。

于是,很自然的,我们会把「返回」和「路径」联系在一起,所以「返回」在导航设计中不可或缺。并且「返」也预示着我们会回到之前的路径节点,整个过程是连续性的,不被切断的。而「关闭」就完全不一样了,它一般和我们的动作有关,是一个短暂性的操作,相比返回也显得更为独立。

根据我们对语义的判断,再结合实际产品中「返回」的场景,我们可以概括出「返回」和「关闭」的特征差异。

1. 返回

连续性:按照产品的页面层级顺次跳转。但存在特殊情况,因为有些产品定义的功能出入口是不一致的,在信息架构层级已经做了一定的优化,所以返回不一定会按原来的路径回去,可能会按产品既定的路径。比如网易云音乐歌曲播放页进入直播后返回不是到播放页。

整体性:在产品功能页面关联性较强的功能中,「返回」需要连接各个页面与层级之间的架构关系,因此「返回」作为操作节点,可以帮助产品功能的各个页面之间建立联系,维持产品的整体性。

2. 关闭

非连续性:用于产品中的临时内容或临时动作,比如弹窗或活动页,与上一级页面没有直接关系。

独立性:非产品原生内容或是产品内的独立内容。比如小程序、浏览器标签等。

3. 返回和关闭的使用场景

知道了返回和关闭的特征后,我们可以从两者的使用角度上再去梳理一下。

现在产品中关于返回和关闭有三种状态:

  1. 只有返回
  2. 只有关闭
  3. 返回和关闭同时存在

1 和 2 的情况很好理解,我们只要根据前面各自的特征去看就能够理清场景。

3 的情况会有特殊性,因为它同时具有返回和关闭这两种看起来相矛盾的特性。其实这是由内容决定的,当内容同时具有独立性和整体性时,就需要支持两种操作。如小程序可以作为一个独立功能,但其本身又可以看作是一个完整的小产品,具有自己的页面结构和页面层级。所以小程序对于它所属的产品,我们有关闭的需要,小程序内的页面导航又需要返回来实现。

除此之外,产品可能开始只有返回,后面临时出现关闭按钮,比如微博「疫情地图」中使用「小区疫情查询」和「7×24 小时疫情快讯」后会出现关闭功能(帮助用户快速退出)。

这里我们可以从连续性和非连续性的角度看,产品针对具有复杂层级和内容的页面设计了顺次(返回)和跳页(关闭)的导航方式,其中关闭随实际情境出现。以此为用户提供了更为灵活的导航路径,来同时满足用户逐级深入、连续返回浏览和选择性查看、临时关闭的需求。

取消和关闭

针对于「关闭」,它和「取消」会有重叠的含义,所以有时并不能很好地去区分这两个功能表达的应用场景。于是,我们可以借用之前的方式,先把「取消」单独拿出来理解。

一般来说,「取消」意味着行为过程中,还有后续行为,整个过程没有完成,当下后悔了,因此取消了当前操作。它更倾向于表达我们主动去做了什么改变,然后中途放弃了。

比如,想煮个饭,于是下了米,倒了水,定时,确认(取消),完成(关闭)。

这时候中间如果突然不想煮饭了,在定时之后,就停止当前行为,那就是取消。但点了确认并完成煮饭之后,这个行为就结束了,只能关闭。因此,它们之间就是行为上的差异。

就好比,打开微信公众号文章,内容已经加载出来,行为已经产生并结束,这时候左上角就一定是关闭。而发朋友圈的时候,左上角是取消,那是因为行为过程还在继续,没有发布,所以可以取消。而发布之后,就无法取消,想要关闭,也就只能删除这条朋友圈了。

所以在操作行为中的页面,左上角最好是使用「取消」。

当我们对词的含义有了进一步思考后,就可以去看它们在产品中的表现了。

比如广告的关闭、推荐内容的关闭。都是产品自身提供的内容,用户不想看到就选择关掉了,没有试图去改变什么。

包括内容页面,或者活动页面,被点开,且加载完成呈现出来之后,这个行为就结束了,没有取消的概念,只有关闭。

再比如,选择图片文件时的取消,微信发朋友圈、微博发帖时的取消等等,我们能发现都是用户主动采取了什么措施,但是又后悔了所以选择取消。

或者如游戏设置,就不适合用关闭,会让用户在理解上产在歧义,比如用户设置到一半,不想设置了,那现在关闭的话,设置是生效了么?所以用取消会更合适。

这些时候,不存在关闭的概念,因为没有内容可以关闭,只能是取消当前行为。如果使用关闭,与该场景下的用户行为不符,反而增加了用户对文案的理解成本。

简单来说,取消强调的是放弃改变,关闭强调的就只是抉择。

不过这里也有一个特殊例子,就是,微信公众号文章转发给好友,左上角是关闭,而钉钉里面内容转发给朋友,就是取消。为什么呢?

在一些特殊场景之下,「关闭」是包含「取消」的。

好比刚才煮饭的例子,现在的电饭煲很高级,如果在过程中不想继续了,拔掉电源就是完全关闭了,但同时这个行为也包含了人不想继续煮饭这个行为,想取消掉了,所以这时候关闭是包含取消的。它跟文章加载完成,已经呈现出来,是不一样的。

而上面这个微信与钉钉的例子,就存在这种包含关系。比如,内容已经加载完,要分享给好友,这时候加载出来的好友列表已经出现,只是选择发送给谁的问题,用户可以关闭已经加载完成的好友列表页面,或者理解为用户打算取消当前行为。

不过这样的设计并不建议大家将其定义为关闭,因为毕竟行为还在继续,使用取消反而更容易理解也更符合场景定义。

譬如,PC 的弹窗经常会同时出现叉(指代关闭)和取消,虽然操作的结果都是使弹窗消失,但是用户的操作目标是不一样的,事实上这里提供了两种选择,即我不想做决定,我要关掉弹窗,以及我决定现在不这么做,我要取消这个动作,这里的关闭其实就暗含了取消的动作。

在 PC 端,我们有足够的空间为用户提供不同的选择,给予用户充分的自主控制权,以满足他们对功能的不同期待。而在移动端,我们需要删减或合并功能,所以当用户同时产生重叠的诉求时,我们往往会选择当下最符合用户心境的功能,这是「场景细化」的结果。这也能解释为什么现在很多 PC 产品的弹窗中也只会保留取消,而不提供叉(指代关闭)的选择。因为用户面对功能不知所措、不做决定的情况已经越来越少,更多的用户已经明确地知道自己应该怎么做。

这就是「取消」和「关闭」的差异,以及移动产品对两者的取舍的根本原因。

同样的,有一些页面,取消和关闭都会用叉的图标来表示,只是在不同情境中,这个叉同样可以理解为取消,关闭,以及取消或关闭。差异点跟上述内容相同。

结语

返回、取消和关闭看起来简单,深入分析后又显得复杂,但相对复杂的分析都只是为了能简单地去运用。在这个问题中,每个人都可以从自己日常的经验出发,然后在产品不同的语境里去体会一个词语、一个图标背后隐藏着我们什么样的认知和使用的习惯。

那由这个问题延伸的,其实还有产品的导航方式,页面出入口的设计差异,产品中整体与独立,连续与非连续的内容结构,原生与非原生页面的差异等等。

小问题同样可以见大,但我们也不需要过度思考,本来问题的解读角度就是因人而异的,也无法面面俱到,上面的只是我的理解方式。设计还是需要回归到用户和产品的目标,再去结合场景和产品业务的使用模式才能得出合理有价值的方案。

文章来源:优设    作者:呆呆U理

方正集团濒临破产,以后字体能否免费用?

雪涛

方正集团倒闭?

最近方正集团负债千亿,被银行申请破产重整的消息让众多设计师兴奋不已,心里暗自在想,那方正字库一万多款字体是不是就可以免费使用了?醒一醒,不太可能,身为设计工作者,尊重他人的设计和拥有版权意识是很重要的。

方正字库属于北京北大方正电子有限公司,而这个公司是方正集团的子公司。就算方正集团真的破产倒闭了,根据我国法律,方正字库何去何从也跟这两家公司的法人是否一致有关,如果一致,那么就可能被收购重组,如果不一致,那么就继续独立运营。关键是,无论是什么结果,方正字库里所有的字体都是有版权的,如果随意商用,就会导致侵权,乃至把整个公司都赔进去。

如何避免字体侵权

直接去网页搜索,便有数不清的方正字体侵权案例。大到电影和游戏的宣发,小到淘宝店铺的页面,只要你使用了方正字库的必须购买版权才可商用的字体,都有可能收到来自方正字库的律师函。那么该如何避免字体侵权呢?其实最好的方法就是使用免费可商用的字体,或者乖乖去买下字体的使用权。

一篇文章告诉你,该怎么判别字体是否侵权:

方正免费字体

如果你实在要免费用方正字库的字体的话,那么就选择「方正黑体简体、方正书宋简体、方正仿宋简体、方正楷体简体」这四种字体吧,已经向方正字库授权服务官方求证过,这四款字体可以直接免费商用,不需要书面授权。

免费可商用字体推荐

不过有那么多免费、适用度广、并且可以商用的字体,为什么要执着于方正呢?优设标题黑和优设好身体这两款字体,无论是做 banner、海报还是文字设计都很合适,还没拥有的设计师们快来下载。

优设标题黑:

优设好身体:

还有优设精心为大家挑选整理成的 2020 年免费可商用中文字体最全合集,链接给你们,正好需要的话,就快去下载使用。

字体网站推荐

最后,介绍两个可以查询和下载免费可商用字体的网站。

1. 字由网 

网站链接:https://www.hellofont.cn/home

第一个是字由网,虽然需要下载客户端激活字体进行使用,不过截至今日,字由拥有 511 款免费可商用字体,对比一下乱用字体可能产生的侵权费用和烦恼,还是下载客户端性价比比较高。

网站及使用介绍:

2. 猫啃网

网站链接:http://novicehou.gz01.bdysite.com/

第二个是猫啃网,是免费开源可商用的公益字体网站,截至今日,网站上共有 155 款字体,可供设计师们选择和下载使用。

文章来源:优设   

导航栏设计知识点

雪涛

讲一个老东家的故事。一次产品迭代会上,老板在台上讲到打算重构 C 端产品框架,想重整标签栏的标签设定。可在讲到这一部分的时候卡壳了,迟迟说不出「标签栏」这个控件名,气氛有些尴尬。这时一名产品经理说道:底部导航栏!会议得以继续。

不全错,这么说也算能理解。控件在界面底部,能引导用户切换页面。但如果标签栏把导航栏的名字占了……那原本的导航栏应该叫什么呢?顶部标题栏?那导航栏里的内容控件又应该叫什么?左上角或者右上角的按钮?

接地气的名称让我们一听就懂,直到有一天你打算跳槽,你拿着自己的作品到下家面试,设计总监几个术语啪啪把你问得不知所云。这些「死控件」、「死栏目」在页面上不可或缺,在设计每一个页面时你以为对它们早已了如指掌,偏偏在关键时刻,它们却六亲不认了。

「我又不走形式主义,为什么一定要说专用名词呢?接地气的名称不是挺好吗,沟通。」很简单的道理,如果名词和概念都混淆不清,有没有花功夫在 UI 设计领域进行深度专研也就一目了然了,还何以谈论如何将它们运用自如呢?

这样的经历,让我产生了一个想法。是时候做一些知识内容沉淀与分享了,不能让更多的人走我踩过的坑。第一期我们便来讲一讲导航栏。

导航栏究竟在哪里

导航栏 Navigation Bar,也简称为 Navbar。一定会有不少刚入门的 UI 新人,在诸多的 Bar 控件中,难以区分它所指代的区域。

在 iOS 上,导航栏是指显示在应用程序顶部,位于状态栏下方的容器区域,层级应高于当前页面内容。

在安卓上,Google 公司在 Material Design 中也赋予了它同样的定义,但是却给了它另一个名称,顶部应用栏(Top App Bar)。

△ iOS与安卓的规范与命名区别

请务必要记住:导航栏是用于构架当前屏幕的内容,阐述当前屏幕的状态,并且起到连接父子级页面层次结构的作用。所以回到开头的小故事,为什么标签栏不能叫做底部导航,因为标签栏是构架了多个屏幕之间平级页面的内容切换,和「导航」的定义没有关系。

规范里告诉我们该怎么做 vs 实际项目我们该怎么做

一个基本的导航栏容器一般承载的信息可能会有:标题、导航按钮、内容控件按钮、其他控件(比如搜索栏、分页标签或分页控件等),千万别忘了还有分割线。(比如微信的导航栏)

1. 导航栏标题

时间倒退回 2017 年以前,这时候的移动端规范下的导航栏还是循规蹈矩的,样式单一。但随着 iPhone X 等一系列全面屏手机相继问世后,移动设备在屏幕高度上有了进一步的扩展,界面设计在一屏内的发挥空间也随之增加。iOS11 发布后,大标题导航栏设计风格兴起,随后被引入平台规范。

于是现在 iOS 与 Material Design 在导航栏上也都定义了两种导航栏标题规范,常规标题与大标题。

常规标题是指在高度为 88px(iOS@2x下)的导航容器中,居中放置一个当前页面的标题。标题字号一般为 34px-38px(34px 为 iOS 标准规范,但实际项目中可以尽量在不小于 34px 标准的情况下根据设计需求确定)。

△ 常规导航不同标题字号的案例及视觉效果

大标题是将导航栏高增加到 192px(iOS@2x),保留高度为 88px 的导航容器来承载内容控件按钮,将标题下坠居左。iOS 的标准规范定义大标题的字号为 68px。但由于英文有大小写区分,在视觉上有一定的层次表现,而中文因为缺少一定的层次结构,并且相同字号的中文视觉大小大于英文,所以大多数时候我们在进行大标题设计时,会适当缩小,一般为 56px-64px 居多。

△ 大标题不同标题字号的案例及视觉效果

大标题导航栏的优点毋庸置疑,页面留白更多,呼吸感更强,大气现代、格调更高,因为页面标题巨大,能够帮助用户快速确认当前所处位置。采用统一的大标题,让页面布局风格快速统一。但缺点也显而易见,因为增加了导航栏的高度,导致屏幕利用率降低,一些通过广告变现或更加注重一屏内内容呈现的应用便中和了常规导航与大标题导航的优缺点,进行了风格改进。

△ 改进的大标题案例

那我们如何在常规标题和大标题之间抉择呢?这可不单单是设计风格的问题,还受产品定位与功能的影响。苹果的设计师在 Apple Music 中实验并验证了一条结论——在内容非常丰富、层级结构较深的产品当中,大标题能够帮用户快速确认自己的位置。

所以我理解的适合使用大标题风格的产品一定是:突出内容呈现而不是功能繁琐的;产品定位更偏向于现代或文艺艺术的;需要快速统一界面风格的。而层级结构需不需要很深,这并不一定,我反而觉得功能越单一、产品体量级越轻的应用,越适合大标题。

所以如此看来,国内使用大标题成功的案例就为数不多了,这可能与中文字体还有国内 app 产品功能都比较繁琐的原因有关,真正做到了使用大标题快速帮助用户确认自己位置,并且结合了产品特性与风格的,我认为人人都是产品经理的移动端在这方面做得非常棒。

2. 导航按钮及内容控件按钮

iOS 规定导航按钮位置仅能用于放置返回按钮,可以添加一个层级的面包屑,帮助用户有效地明确当前页面层级;Material Design 中,不仅可以放置返回按钮,还另有作用,菜单图标-用于打开导航抽屉或者关闭图标-关闭工具栏。

△ iOS与安卓的导航按钮区域区别

这一点与 iOS 的定义有着天壤之别,iOS 非常明确地赋予了工具栏的定义,并且将导航栏和工具栏(Toolbars)彻底地分离开,典型案例就是 Safari。

△ iOS明确地将导航栏与工具栏分离开

在内容控件上 iOS 与 Material Design 也大相径庭,Material Design 不去限制你的内容控件多少,因为它提供了溢出菜单,并可以根据屏宽的变化,自适应释出和收纳溢出菜单中的控件。

而 iOS 则规定我们,要给内容控件按钮足够多的空间,必要的时候,隐藏导航栏标题也未尝不可。

那么真实的项目中,我们往往为了快速落地,会存在一稿适配双平台的情况。这时候我们应该遵从哪一个平台的规范呢?答案是:许多大厂的做法已经向我们验证,规范不分家。

在 iOS 诸多的应用中溢出菜单早已普及,尽管这是 Material Design 提出的设计理念。

△ Material Design的溢出菜单也被运用在iOS端

虽然国内遵从 Material Design 进行 Android 应用设计的情况相对较少,但它提供的设计理念与方案却并不局限在安卓平台。

3. 分割线

分割线只是一种体现形式,我想要表达的是,别忘记区分导航栏与内容界面的视觉层级关系。Matetial Design 提醒我们,顶部应用栏可以与内容位于同一高度,但滚动时,请增加导航栏的视觉高度,让内容在其后方滚动。而 iOS 则默认采用了背景模糊的方式区分了导航栏与内容区域的层级关系。

△ 区分导航栏与内容区域的层级关系

缺少视觉分割会让用户分不清导航栏与内容界面,它们看起来会更像一个平级。对用户视觉区分内容主次其实是极不友好的。

4. 其他控件

关于其他控件,iOS 只在规范中提及到了分页控件。苹果设计师考虑到部分场景在当前页面中还存在信息层级结构划分,此时建议可以在导航栏中使用分段控件。

但国内的应用程序早已将导航栏容器的作用发挥到,基于导航栏层级始终高于内容区域的特性,我们通常可以将分段控件、分页标签、搜索栏等等用户可能随时使用的工具放在导航栏中。

△ 导航栏通常会承载的其他控件

总结

导航栏是几乎每一个界面都必定存在的控件,正因为无法轻易删减,逃不掉就必须用好它,不然很容易沦为页面的减分项。

设计好导航栏不仅仅是视觉上的工作,表现的方式、承载的按钮与组件、滚屏时的组合操作还能给用户带来极大的体验增益。

文章来源:优设    作者:

前端基础-HTML文字滚动

seo达人

1.文字滚动

<html>

<head>

<title>我的第一个页面</title>

</head>

<body>

<marquee behavior="scroll" direction="up" height="30" style="overflow:hidden;" scrollamount="1" width="300" onMouseOver="stop()" onMouseOut="start()">

雷电黄色预警!<br />

大雨黄色预警!<br />

</marquee>

</body>

</html>



direction:方向



up:上 down:下 left:左 right:右



scrollamount:滚动速度-----------------scroll:滚动 amount:数值



width:宽度 height:高度



onmouseover:当鼠标移上去



onmouseout:当鼠标离开



stop():停止



start():开始



behavior:



scroll 循环滚动



alternate 来回滚动



slide 滚动一次停止




简单的验证跳转

seo达人

一.有关于内置对象的作用域

主要说明2个对象,request,session

1、request 对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。

request只在2个页面之间传递,每一次新的请求都会新建一个request对象,也就是说可能会request对象不一致导致空指针异常。

2、session 对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

session对象在整个会话只有一个,也就是说session对象的数据会一直保留直到主动进行数据更改。



二.表单提交

在index.jsp中使用form进行数据的提交,action的目标是check.jsp,method是post



三.验证跳转

当form提交信息后交给check.jsp验证,使用getParameter来得到form的信息,并使用setAttribute保存。在check.jsp中判断账号密码是否正确后,使用



<jsp:forward page=".jsp"></jsp:forward>

1

进行跳转,
.jsp是想要跳转的页面路径。



四.详细代码

index.jsp



<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

  <body>



   <form action="check.jsp" method="post">

请输入用户名:

<input type = "text" name = "username"><br/>

请输入密码:

<input type = "password" name = "passwd"><br/>

<input type="submit" name="submit" value="登录">

</form>

 

  </body>

</html>





check.jsp



<%@ page language="java" import="java.util.
" pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>验证</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

  <body>

   

<%

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

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

  request.setAttribute("username", username);

  request.setAttribute("passwd", passwd);

 

  if(username.equals("admin")&&passwd.equals("123")){

%>

<jsp:forward page="succeed.jsp"></jsp:forward> 

<%}else{ %>

<jsp:forward page="failed.jsp"></jsp:forward> 

<%} %>

  </body>

</html>



succeed.jsp



<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆成功</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

<body>

<% 

String username = (String)request.getAttribute("username");

String passwd = (String)request.getAttribute("passwd");



%>

<%=username %>登陆成功



</body>

</html>



failed.jsp



<%@ page language="java" import="java.util.
" pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆失败</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

<body>

<% 

String username = (String)request.getAttribute("username");

String passwd = (String)request.getAttribute("passwd");



%>

<%=username %>登陆失败

</body>

</html>



五.注意事项

在jsp中使用form提交表单不能直接进行跳转,否则操作不慎就容易出现空指针异常,建议交由单独的跳转页面处理


日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档