jQuery超詳細總結
文章目錄
jQuery超詳細總結
一 選擇器
特殊選擇器
二 篩選器
用在 jQuery 選擇的元素后面
都是方法,對選擇出來的元素進行二次篩選
三 文本操作
總結
四 元素類名操作
五 元素屬性操作
在 H5 的標準下, 給了一個定義, 當你需要寫自定義屬性的時候,最好寫成 data-xxx="值",當大家看到 data-xxx 的時候, 就知道這是一個自定義屬性
六 元素樣式操作
七 綁定事件
on()
方法是專門用來綁定事件one()
方法是專門用來綁定一個只能執行一次的方法off()
方法是專門用來解綁一個元素的事件的trigger()
方法是專門用來觸發事件的方法hover()
常用事件
offset()
position()
scrollTop()
scrollLeft()
ready()
事件each()
方法jQuery 發送一個 GET 請求
jQuery 發送一個 POST 請求
jQuery 的 $.ajax 方法
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 幫你解析響應體
$.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: '
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') } })————————————————
不管是做 UI 設計還是畫插畫,有很多同學覺得自己是因為天賦不夠所以對色彩的敏感度不夠,其實不然。一個可能是大家總結的太少,從來都是憑感覺和運氣去配色,但配色都是有講究的。本文不會給大家重復講解什么是 rgb,什么是 hsb,什么是 cmyk 或者什么三原色,這些大家都可以從網上直接搜到。我今天要給大家分享的是人們是如何認識色彩,并且在產品設計中使用的。
大家都知道,對于不同的顏色,我們對其的感知是不同的,有人覺得暖色在前,冷色在后。暖色更醒目,冷色不醒目。那這是什么原因呢?首先我們要知道眼睛內存在兩種感光細胞:視錐細胞和視桿細胞,視桿細胞能夠感知光線強弱但無法感知顏色,而視錐細胞卻相反,視錐細胞內還有 3 種對不同頻率光敏感的細胞。我們經常會用到視錐細胞,而視桿細胞卻用的少,更多的是在黑暗的環境中使用的多。
視錐細胞的三種類型分別是低頻、中頻和高頻視錐細胞,分別對紅、綠、藍三種顏色的光敏感。而且這三個視錐細胞分別也有重合的部分。低頻視錐細胞對整個可見光頻譜都敏感,它的范圍包含的比較廣,特別是對于頻譜中段的黃色到紅色部分更加敏感。但是像高頻的紫色幾乎只有藍視錐細胞可以感知。
大家在平時生活中都能看到,在馬路上、機動車道上以及一些警示牌都會采用黃色、橙色等標識,因為這些非常醒目。更容易被紅視錐細胞感知到,但如果你的標識用的是冷色調那這個交通事故可能要發生的頻繁得多。
1. 人對色彩邊緣的對比更加敏感
我們來做個實驗,如下圖,大家覺得在中間的灰色塊是純色還是漸變色,可能很多同學看上去都會覺得是個漸變色,但其實它就是一個純色,不信的同學可以自己在工具中嘗試一下。
但如果你把這個色塊拿出來后,不在這個環境中直接進行邊緣對比,那就不會出現漸變的情況了。光說原理,我們也來看一下在產品設計中需要注意的地方,因為在 UI 界面設計中我們通常需要把一些圖片、卡片疊加放置,這樣就會造成邊緣視覺的對比,本來不明顯的兩個元素重疊之后變的很明顯,例如一些標簽的背景色和頁面整體的背景色。
如果你想要讓兩個顏色接近的元素具有識別度,那么最好將這兩個元素進行重疊擺放而不是分開擺放。另外,如果是卡片樣式的設計,背景色一定不要過于灰暗也不要過于淺白,過于深的話會讓卡片輪廓過于明顯而導致整體看上去顯臟以及很明顯的對比,顯得不自然和舒適。如果過于淺的話也會導致信息的不聚焦。
還有,為什么被框起來的文字會看上去更加有點擊的欲望其實也是這個道理,因為文字和背景疊加產生的輪廓只是文字的輪廓,在我們的第一印象中只是一種符號。當它被賦予顏色之后,我們才會意識到它需要我們去注意或者可被點擊,但依然不夠明顯,所以為了強化可點擊這個感覺,我們才用了線框、背景色、箭頭等方式。
1. 加深品牌印象與品牌感
一般來說,產品都會有一個品牌的主色。而這個品牌的主色也通常會運用在外面的產品界面中,所以例如閑魚、馬蜂窩等,主色都采用了黃色,黃色具有非?;顫姟⒂腥?、好玩的特性,無論是線上還是線下都使用了這個品牌黃色,從每一個線上元素的主色,到線下包裝的印刷色。
但一定要注意的是,如果品牌的主色偏灰偏暗的話,可能不太適合線上的產品進行通用。例如之前的嚴選、云集、711便利店、宜家等產品的主色都是偏深和暗的,所以在線上的界面用起來會非常不和諧,和整體偏淺色、輕的風格對比起來太強烈,引起不適。
而且線上覺得還不錯的顏色,由于印刷的原理,實物也會更加偏低飽和和偏暗。
2. 引導用戶視覺凹增加易讀性
我們在《如何有理有據做設計,而不是憑感覺?》里提到了人們如何閱讀信息,提到了一個視覺凹的概念。所以在界面中,什么樣的地方使用色彩是有講究的。所以在這里通常會需要使用顏色的地方在于希望引導用戶和吸引用戶注意的地方才會使用色彩。例如下方產品,使用了高亮色來引導用戶視覺。
當然色彩的運用也會將整個頁面的層級凸顯出來,而不單純的用中性色來區分層級。
3. 區分信息交互的狀態
同樣是上兩張圖,大家可以清晰的看到,美團中的附近熱賣好點、滿減標簽、價格,其實都只具備信息的呈現,但不具備交互的特征和狀態。但淘票票中的「4.7萬」和「展開」卻不一樣,「展開」使用了輔助藍色,這里的展開就具備這個文案所描述的這個控件具備的交互特性──點擊后將隱藏的文字展示出來。藍色一般我們都會使用在某個可點的鏈接上,當然也會有其他的色彩來表示可點擊。
所以不是所有的元素都要賦予顏色,這樣會使整個頁面非?;靵y。
另外,UI 設計中主色除了引導用戶的作用外,也可以表示當前正被激活的信息狀態。例如愛奇藝 app 中播放詳情頁面,當前版塊標簽和正在播放劇集的激活狀態。
4. 營造氛圍傳遞熱度
色彩除了上方所述的字段中的不同使用,在圖片和整體氛圍營造中也起了很大的作用,目前很多 2c 的產品往往會在界面氛圍的營造中運用一些手段。例如導航欄、底部標簽欄上的圖標,或者在首頁營銷版塊的瓷片區域都會用品牌色在活動時段內進行氛圍打造。
在色彩的心理學上,大家都知道每個顏色具有一定的性格特征和表達。而且都會有正反兩面,可以看下方多種色彩的描述。
然而其實很多的產品使用的色彩和我們所認知的會有一些差別,比如咖啡品牌的主色選擇,在我們常規人之中,咖啡應該是褐色、棕色,但是大家看到星巴克、瑞幸、漫咖啡其實都用了和咖啡本質沒什么關系的顏色。
在瑞幸剛出來的時候,很多人其實不太習慣把這個藍色和咖啡結合起來,但是為了塑造品牌差異化,瑞幸一直將「藍色」作為品牌的主基調,「小藍杯」這一稱呼不但讓消費者感到親切,也在眾多的咖啡中有了屬于自己的記憶點。在這支廣告片中,主基調同樣是使用藍色,不但符合了當下消費者的視覺偏好,也在為用戶留下記憶點之后,讓用戶在看到藍色時自然而然地想到瑞幸咖啡。
但凡各位使用了這樣的配色,保證各位過不了試用期,相信我。所以大家千萬要避開。
高飽和度的色彩
高飽和度的色彩,會讓人產生「幻覺」!讓人產生視覺疲勞,例如我將餓了么這個界面的色調調整一下大家看一下,不亮瞎算我輸。
灰部使用過多的配色
為什么很多時候我們總覺得界面臟兮兮的。是因為我們在界面或者配色中使用了過多的低飽和度、灰度較多的配色,所以這也是要避免的。
沒有規律且過多的配色
讓界面或者插畫看起來非?;靵y。一般來說顏色的使用也需要有側重點,所以我們常用的方法是6、3、1的色彩配比。
熒光色
熒光色絕對不可以使用在 UI 界面中,尤其是主色。
太輕柔的顏色
在很多 dribbble 的飛機稿中,經常能看到這樣的配色和練習。無論是在練習中還是實際項目中,這樣的界面也完全無法讓用戶看到想看的信息,沒有重點且輕飄飄的感覺。
現在很火的新擬物化設計
說真的,這樣的風格確實耳目一新,但個人覺得可能不會成為主流。因為它就和第五種一樣:信息可識別性很差。且不談色弱的人群,就正常的用戶來說大面積的白色+飽和度低的元素結合,感覺就是得了「白內障」。另外我們常說的一點就是所有元素都強調就等于什么都沒有強調,這樣的風格在每一個元素都具有陰影的情況下都在爭先恐后讓用戶感知,原則是輕量化卻又需要那么多陰影,這樣就有點自相矛盾的感覺。
為了營造這樣的「新擬物」的輕量氛圍,還不得不在整個界面中簡化大部分元素,能不加文字就不能加文字。有一句話一直非常影響我做設計:「設計是需要被簡化的,但是簡化的過程一定不簡單」。所以不是單純的簡化所有元素為了達到這個風格的目的。
不要將對抗色重疊
例如下方,兩種對抗色重疊后會引起視覺閃爍的感覺。
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 美刀創辦了自己的公司,取名「奧美廣告」。在麥迪遜大街貼出一個別出心裁的招聘海報,上面傳達了三點內容:
至此,奧美廣告公司正式成立。算上奧格威共兩名員工,整天大眼瞪小眼。為了活下去,奧格威接了當時能夠接到的所有訂單。包括一個毫不知名的小制衣廠哈撒韋。當時他們告訴奧格威,只有 3 萬美元預算,卻想和知名襯衣品牌競爭。
當時奧格威都快哭了。預算少要求極高,還不因為效果而解約。但誰讓他叫大衛呢,過人的天賦讓他的廣告在全國走紅,僅用 3 萬美元,讓銷售額翻了三番。使這家默默無聞了 100 多年的襯衫品牌,一夜之間聞名全國。更令人無法想象的是,這個創意被沿用了 25 年。
廣告為產品增添了來自遠方的神秘感,激發讀者對狂野的無限遐想?!競鬟_一種特別的信息以取悅讀者」。這本來是奧格威準備的 18 個方案中被否決的一個,但他想,給其中一只眼睛戴個眼罩也無妨,于是在影棚的路上買了個眼罩交給模特。
隨后,勞斯萊斯花了 5 萬美元找奧格威做的一支廣告再次成為經典,在時速 60 英里時,這輛新款勞斯萊斯車內最大的噪聲,來自它的電子鐘。不用多說了,時至今日這依然是最有名的汽車廣告之一。這些廣告讓奧美的名聲如日中天,贏得客戶如探囊取物。
后來廣告界盛傳,說奧格威是一個奇才,好幾家大廣告公司都提出收購意向時,奧格威卻回絕了。多年后他回憶,如果當時誘他以金錢,他肯定就屈服了,但他們卻以為奧格威在乎的是「創作的挑戰」。
與其說創作是一種挑戰,還不如說是一種依據特定原則的模式生產,他甚至禁止員工使用「創作」形容他們的工作。因為在奧格威看來,好的廣告是「99% 的調查研究+ 1% 的靈感」。例如奧格威發現標題加入感情色彩的詞可強化廣告效果,經過幾百個詞的測試,「Darling」(親愛的)一詞高居榜首。于是他將它運用到多芬的廣告,后來多芬成為了同類產品中最暢銷的品牌。不久奧格威表示,他并不知道洗澡時使用電話是危險的。
奧格威出生名門,卻家道中落,是牛津的明星,卻被掃地出門,他為法國總統下過廚,也給國王當過特工。他對市場一無所知,從未寫過一篇文案,直至 38 歲尚未正式涉足廣告業,口袋只有區區的 6000 美元原始資金……但 3 年之后,這個一度黯淡的男人已在行業發光發熱,猶如創造了一個奇跡。
1963 年,奧格威著書《一個廣告人的自白》??梢哉f奧格威是一個超越了時代的牛人,他里面的一些理論,對我們現在做電商一點都不過時,有興趣的小伙伴可以買一本看看。
奧格威憑借他獨特的人格特征和灑脫的世界觀征服了許多人,那么他的魅力到底在哪,不妨讓我們走進他的思想世界,親身領略一番這個奧美開山鼻祖的風采。
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 的情況會有特殊性,因為它同時具有返回和關閉這兩種看起來相矛盾的特性。其實這是由內容決定的,當內容同時具有獨立性和整體性時,就需要支持兩種操作。如小程序可以作為一個獨立功能,但其本身又可以看作是一個完整的小產品,具有自己的頁面結構和頁面層級。所以小程序對于它所屬的產品,我們有關閉的需要,小程序內的頁面導航又需要返回來實現。
除此之外,產品可能開始只有返回,后面臨時出現關閉按鈕,比如微博「疫情地圖」中使用「小區疫情查詢」和「7×24 小時疫情快訊」后會出現關閉功能(幫助用戶快速退出)。
這里我們可以從連續性和非連續性的角度看,產品針對具有復雜層級和內容的頁面設計了順次(返回)和跳頁(關閉)的導航方式,其中關閉隨實際情境出現。以此為用戶提供了更為靈活的導航路徑,來同時滿足用戶逐級深入、連續返回瀏覽和選擇性查看、臨時關閉的需求。
針對于「關閉」,它和「取消」會有重疊的含義,所以有時并不能很好地去區分這兩個功能表達的應用場景。于是,我們可以借用之前的方式,先把「取消」單獨拿出來理解。
一般來說,「取消」意味著行為過程中,還有后續行為,整個過程沒有完成,當下后悔了,因此取消了當前操作。它更傾向于表達我們主動去做了什么改變,然后中途放棄了。
比如,想煮個飯,于是下了米,倒了水,定時,確認(取消),完成(關閉)。
這時候中間如果突然不想煮飯了,在定時之后,就停止當前行為,那就是取消。但點了確認并完成煮飯之后,這個行為就結束了,只能關閉。因此,它們之間就是行為上的差異。
就好比,打開微信公眾號文章,內容已經加載出來,行為已經產生并結束,這時候左上角就一定是關閉。而發朋友圈的時候,左上角是取消,那是因為行為過程還在繼續,沒有發布,所以可以取消。而發布之后,就無法取消,想要關閉,也就只能刪除這條朋友圈了。
所以在操作行為中的頁面,左上角最好是使用「取消」。
當我們對詞的含義有了進一步思考后,就可以去看它們在產品中的表現了。
比如廣告的關閉、推薦內容的關閉。都是產品自身提供的內容,用戶不想看到就選擇關掉了,沒有試圖去改變什么。
包括內容頁面,或者活動頁面,被點開,且加載完成呈現出來之后,這個行為就結束了,沒有取消的概念,只有關閉。
再比如,選擇圖片文件時的取消,微信發朋友圈、微博發帖時的取消等等,我們能發現都是用戶主動采取了什么措施,但是又后悔了所以選擇取消。
或者如游戲設置,就不適合用關閉,會讓用戶在理解上產在歧義,比如用戶設置到一半,不想設置了,那現在關閉的話,設置是生效了么?所以用取消會更合適。
這些時候,不存在關閉的概念,因為沒有內容可以關閉,只能是取消當前行為。如果使用關閉,與該場景下的用戶行為不符,反而增加了用戶對文案的理解成本。
簡單來說,取消強調的是放棄改變,關閉強調的就只是抉擇。
不過這里也有一個特殊例子,就是,微信公眾號文章轉發給好友,左上角是關閉,而釘釘里面內容轉發給朋友,就是取消。為什么呢?
在一些特殊場景之下,「關閉」是包含「取消」的。
好比剛才煮飯的例子,現在的電飯煲很高級,如果在過程中不想繼續了,拔掉電源就是完全關閉了,但同時這個行為也包含了人不想繼續煮飯這個行為,想取消掉了,所以這時候關閉是包含取消的。它跟文章加載完成,已經呈現出來,是不一樣的。
而上面這個微信與釘釘的例子,就存在這種包含關系。比如,內容已經加載完,要分享給好友,這時候加載出來的好友列表已經出現,只是選擇發送給誰的問題,用戶可以關閉已經加載完成的好友列表頁面,或者理解為用戶打算取消當前行為。
不過這樣的設計并不建議大家將其定義為關閉,因為畢竟行為還在繼續,使用取消反而更容易理解也更符合場景定義。
譬如,PC 的彈窗經常會同時出現叉(指代關閉)和取消,雖然操作的結果都是使彈窗消失,但是用戶的操作目標是不一樣的,事實上這里提供了兩種選擇,即我不想做決定,我要關掉彈窗,以及我決定現在不這么做,我要取消這個動作,這里的關閉其實就暗含了取消的動作。
在 PC 端,我們有足夠的空間為用戶提供不同的選擇,給予用戶充分的自主控制權,以滿足他們對功能的不同期待。而在移動端,我們需要刪減或合并功能,所以當用戶同時產生重疊的訴求時,我們往往會選擇當下最符合用戶心境的功能,這是「場景細化」的結果。這也能解釋為什么現在很多 PC 產品的彈窗中也只會保留取消,而不提供叉(指代關閉)的選擇。因為用戶面對功能不知所措、不做決定的情況已經越來越少,更多的用戶已經明確地知道自己應該怎么做。
這就是「取消」和「關閉」的差異,以及移動產品對兩者的取舍的根本原因。
同樣的,有一些頁面,取消和關閉都會用叉的圖標來表示,只是在不同情境中,這個叉同樣可以理解為取消,關閉,以及取消或關閉。差異點跟上述內容相同。
返回、取消和關閉看起來簡單,深入分析后又顯得復雜,但相對復雜的分析都只是為了能簡單地去運用。在這個問題中,每個人都可以從自己日常的經驗出發,然后在產品不同的語境里去體會一個詞語、一個圖標背后隱藏著我們什么樣的認知和使用的習慣。
那由這個問題延伸的,其實還有產品的導航方式,頁面出入口的設計差異,產品中整體與獨立,連續與非連續的內容結構,原生與非原生頁面的差異等等。
小問題同樣可以見大,但我們也不需要過度思考,本來問題的解讀角度就是因人而異的,也無法面面俱到,上面的只是我的理解方式。設計還是需要回歸到用戶和產品的目標,再去結合場景和產品業務的使用模式才能得出合理有價值的方案。
文章來源:優設 作者:呆呆U理
最近方正集團負債千億,被銀行申請破產重整的消息讓眾多設計師興奮不已,心里暗自在想,那方正字庫一萬多款字體是不是就可以免費使用了?醒一醒,不太可能,身為設計工作者,尊重他人的設計和擁有版權意識是很重要的。
方正字庫屬于北京北大方正電子有限公司,而這個公司是方正集團的子公司。就算方正集團真的破產倒閉了,根據我國法律,方正字庫何去何從也跟這兩家公司的法人是否一致有關,如果一致,那么就可能被收購重組,如果不一致,那么就繼續獨立運營。關鍵是,無論是什么結果,方正字庫里所有的字體都是有版權的,如果隨意商用,就會導致侵權,乃至把整個公司都賠進去。
直接去網頁搜索,便有數不清的方正字體侵權案例。大到電影和游戲的宣發,小到淘寶店鋪的頁面,只要你使用了方正字庫的必須購買版權才可商用的字體,都有可能收到來自方正字庫的律師函。那么該如何避免字體侵權呢?其實最好的方法就是使用免費可商用的字體,或者乖乖去買下字體的使用權。
一篇文章告訴你,該怎么判別字體是否侵權:
如果你實在要免費用方正字庫的字體的話,那么就選擇「方正黑體簡體、方正書宋簡體、方正仿宋簡體、方正楷體簡體」這四種字體吧,已經向方正字庫授權服務官方求證過,這四款字體可以直接免費商用,不需要書面授權。
不過有那么多免費、適用度廣、并且可以商用的字體,為什么要執著于方正呢?優設標題黑和優設好身體這兩款字體,無論是做 banner、海報還是文字設計都很合適,還沒擁有的設計師們快來下載。
優設標題黑:
優設好身體:
還有優設精心為大家挑選整理成的 2020 年免費可商用中文字體最全合集,鏈接給你們,正好需要的話,就快去下載使用。
最后,介紹兩個可以查詢和下載免費可商用字體的網站。
1. 字由網
網站鏈接:https://www.hellofont.cn/home
第一個是字由網,雖然需要下載客戶端激活字體進行使用,不過截至今日,字由擁有 511 款免費可商用字體,對比一下亂用字體可能產生的侵權費用和煩惱,還是下載客戶端性價比比較高。
網站及使用介紹:
2. 貓啃網
網站鏈接:http://novicehou.gz01.bdysite.com/
第二個是貓啃網,是免費開源可商用的公益字體網站,截至今日,網站上共有 155 款字體,可供設計師們選擇和下載使用。
文章來源:優設
講一個老東家的故事。一次產品迭代會上,老板在臺上講到打算重構 C 端產品框架,想重整標簽欄的標簽設定??稍谥v到這一部分的時候卡殼了,遲遲說不出「標簽欄」這個控件名,氣氛有些尷尬。這時一名產品經理說道:底部導航欄!會議得以繼續。
不全錯,這么說也算能理解??丶诮缑娴撞浚芤龑в脩羟袚Q頁面。但如果標簽欄把導航欄的名字占了……那原本的導航欄應該叫什么呢?頂部標題欄?那導航欄里的內容控件又應該叫什么?左上角或者右上角的按鈕?
接地氣的名稱讓我們一聽就懂,直到有一天你打算跳槽,你拿著自己的作品到下家面試,設計總監幾個術語啪啪把你問得不知所云。這些「死控件」、「死欄目」在頁面上不可或缺,在設計每一個頁面時你以為對它們早已了如指掌,偏偏在關鍵時刻,它們卻六親不認了。
「我又不走形式主義,為什么一定要說專用名詞呢?接地氣的名稱不是挺好嗎,溝通?!购芎唵蔚牡览恚绻~和概念都混淆不清,有沒有花功夫在 UI 設計領域進行深度專研也就一目了然了,還何以談論如何將它們運用自如呢?
這樣的經歷,讓我產生了一個想法。是時候做一些知識內容沉淀與分享了,不能讓更多的人走我踩過的坑。第一期我們便來講一講導航欄。
導航欄 Navigation Bar,也簡稱為 Navbar。一定會有不少剛入門的 UI 新人,在諸多的 Bar 控件中,難以區分它所指代的區域。
在 iOS 上,導航欄是指顯示在應用程序頂部,位于狀態欄下方的容器區域,層級應高于當前頁面內容。
在安卓上,Google 公司在 Material Design 中也賦予了它同樣的定義,但是卻給了它另一個名稱,頂部應用欄(Top App Bar)。
△ iOS與安卓的規范與命名區別
請務必要記?。簩Ш綑谑怯糜跇嫾墚斍捌聊坏膬热?,闡述當前屏幕的狀態,并且起到連接父子級頁面層次結構的作用。所以回到開頭的小故事,為什么標簽欄不能叫做底部導航,因為標簽欄是構架了多個屏幕之間平級頁面的內容切換,和「導航」的定義沒有關系。
一個基本的導航欄容器一般承載的信息可能會有:標題、導航按鈕、內容控件按鈕、其他控件(比如搜索欄、分頁標簽或分頁控件等),千萬別忘了還有分割線。(比如微信的導航欄)
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 只在規范中提及到了分頁控件。蘋果設計師考慮到部分場景在當前頁面中還存在信息層級結構劃分,此時建議可以在導航欄中使用分段控件。
但國內的應用程序早已將導航欄容器的作用發揮到,基于導航欄層級始終高于內容區域的特性,我們通常可以將分段控件、分頁標簽、搜索欄等等用戶可能隨時使用的工具放在導航欄中。
△ 導航欄通常會承載的其他控件
導航欄是幾乎每一個界面都必定存在的控件,正因為無法輕易刪減,逃不掉就必須用好它,不然很容易淪為頁面的減分項。
設計好導航欄不僅僅是視覺上的工作,表現的方式、承載的按鈕與組件、滾屏時的組合操作還能給用戶帶來極大的體驗增益。
文章來源:優設 作者:
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 滾動一次停止
一.有關于內置對象的作用域
主要說明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提交表單不能直接進行跳轉,否則操作不慎就容易出現空指針異常,建議交由單獨的跳轉頁面處理
下面這段代碼是實現簡單的導航效果:
在這里插入代碼片<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
*{
margin:0px;
padding:0px;
list-style:none;
}
.nav{
width:700px;
margin:100px auto;
}
.nav ul li{
float:left;
margin-right:5px;
}
.nav ul li a{
width:100px;
height:30px;
color:#fff;
display:block;
line-height:30px;
margin-right:5px;
text-decoration:none;
background:red;
text-align:center;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.nav ul li a:hover{
background:yellow;
color:blue;
text-decoration:underline;
}
</style>
</head>
<body>
<div class="nav">
<ul class="clearfix">
<li><a href="#">導航</a></li>
<li><a href="#">導航</a></li>
<li><a href="#">導航</a></li>
<li><a href="#">導航</a></li>
<li><a href="#">導航</a></li>
</ul>
</div>
</body>
</html>
實現效果如圖:
容易犯錯的地方:剛開始我把display:block;屬性寫在最前面,結果一直出不來,后來發現display屬性應該放在height和width屬性后面
我還學到一個知識點:關于父元素塌陷問題:
在文檔流中,父元素的高度默認是被子元素撐開的,也就是說父元素多高,子元素就多高
但是為子元素設置浮動以后,子元素就會完全脫離文檔流,此時將會導致子元素無法撐起父元素的高度,導致父元素的高度塌陷
由于父元素的高速塌陷了,則父元素下所有的元素都會向上移動,這樣會導致頁面布局混亂
所以我們在開發中一定要避免出席那高度塌陷的問題,這時候我們可以將父元素的高度寫死,這樣可避免塌陷的問題出現,但是一當高度寫死,父元素的高度將不能自動適應子元素的高度,所以這種方式是不推薦使用的
1
解決的方案:
根據W3C標準,在頁面中元素有一個隱含的屬性叫做Block Formatting Context
方案一:*(設置zoom為1和overflow為hidden)
當開啟元素的BFC后,元素會有以下特性:
父元素的垂直外邊距不會和子元素重疊
開啟BFC的元素不會被浮動元素所覆蓋
開啟BFC的元素可以包含浮動的子元素
那如何開啟元素的BFC呢?
設置元素浮動
設置元素的絕對定位
設置元素為inline-block(但是設置inline-block可以解決問題,但是會導致寬度丟失,所以不推薦使用這種方式)
將元素的overflow設置為一個非visible的值(推薦方式:將overflow:hidden這個是副作用最小的開啟BFC方式,所以可以這么說,以后若是再塌陷,就給父元素加上overflow:hidden屬性)
但需要注意的是:
在IE6以及以下的瀏覽器中并不支持BFC,所以使用這種方式并不能兼容IE6,在IE6中雖然沒有BFC,但有另一個隱藏屬性叫做hasLayout該屬性作用和和BFC類似。但在IE6瀏覽器可以通過開hasLayout來解決問題
開啟方式很多,我們可以直接用一種副作用最小的直接將元素的zoom設置為1,比如父元素是box1,我們可以在父元素中加上zoom:1;
在這里解釋一下zoom表示放大的意思,后邊跟著一個數值,寫幾就可以將元素放大幾倍,所以zoom:1表示不放大元素,但是可以通過該樣式可以開啟hasLayout.
但需要注意的是zoom屬性放IE6可以,別的瀏覽器比如Chrome就不行
****所以重頭戲來了:若我們想要兼容所有瀏覽器?
1.引入
三種引用方式
第一種 npm安裝
項目根目錄命令行執行
npm install uni-simple-router
1
第二種 插件市場(使用HBuilderX導入插件)
第三種 ZIP下載 解壓
2.項目中引入
import Vue from 'vue'
import {RouterMount} from 'uni-simple-router';
import Router from './router'
Vue.use(Router)
//...后續代碼
引入之后就開始我們的正式使用。
第一步先在項目的根目錄下創建一個router文件夾。
格式為:
router
|---modules
|---index.js
|---index.js
router中的modules文件夾是用來放路由表模板的。modules中的index.js內容為
const files = require.context('.', false, /.js$/)
const modules = []
files.keys().forEach(key => {
if (key === './index.js') return
const item = files(key).default
modules.push(...item)
})
export default modules
這個文件用來把同目錄下的js文件讀取并整合所有路由。
在這里創建的js文件代碼示例:
const home = [
{
//注意:path必須跟pages.json中的地址對應,最前面別忘了加'/'哦
path: '/pages/home/index',
aliasPath:'/', //對于h5端你必須在首頁加上aliasPath并設置為/
name: 'index',
meta: {
title: '首頁',
},
},
{
path: '/pages/home/list',
name: 'list',
meta: {
title: '列表',
},
},
]
export default home
第二步配置router下的index.js
import modules from './modules'
import Vue from 'vue'
//這里僅示范npm安裝方式的引入,其它方式引入請看最上面【安裝】部分
import Router from 'uni-simple-router'
Vue.use(Router)
//初始化
const router = new Router({
routes: [...modules]//路由表
});
//全局路由前置守衛
router.beforeEach((to, from, next) => {
next()
})
// 全局路由后置守衛
router.afterEach((to, from) => {
})
export default router;
第三步 就是配置main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import { RouterMount } from 'uni-simple-router'
App.mpType = 'app'
const app = new Vue({
...App
})
//v1.3.5起 H5端 你應該去除原有的app.$mount();使用路由自帶的渲染方式
// #ifdef H5
RouterMount(app,'#app');
// #endif
// #ifndef H5
app.$mount(); //為了兼容小程序及app端必須這樣寫才有效果
// #endif
這樣你的路由就配置好了。
如果不想繁瑣的配置modules下的文件,可以用webpack自動構建路由表
安裝
npm install uni-read-pages
1
配置 vue.config.js (可能需要手動創建)
const TransformPages = require('uni-read-pages')
const tfPages = new TransformPages({
//如果你需要獲取更多參數,那么請配置參數!
includes:['path','name','meta']
})
module.exports = {
configureWebpack: {
plugins: [
new tfPages.webpack.DefinePlugin({
ROUTES: JSON.stringify(tfPages.routes)
})
]
}
}
然后去pages.json里面更改配置,加入所需要的內容
最后配置路由表
import Vue from 'vue'
//這里僅示范npm安裝方式的引入,其它方式引入請看最上面【安裝】部分
import Router from 'uni-simple-router'
Vue.use(Router)
//初始化
const router = new Router({
routes:ROUTES //路由表
});
//全局路由前置守衛
router.beforeEach((to, from, next) => {
next()
})
// 全局路由后置守衛
router.afterEach((to, from) => {
})
export default router;
藍藍設計的小編 http://www.syprn.cn