天就來做一款nav炫酷的下拉菜單效果,適合在PC端和移動端使用,運用到CSS3的動畫和過渡屬性,感興趣的朋友可以看看!
實現(xiàn)效果如下:
鼠標移上“菜單”兩個字時,二級的下拉菜單像百葉窗一樣打開,鼠標移走后也會收縮隱藏起來!
實現(xiàn)代碼
html結(jié)構(gòu):
css樣式:
在移動端頁面中,由于屏幕空間有限,導航條扮演著非常重要的角色,提供了快速導航到不同頁面或功能的方式。用戶也通常會在導航條中尋找他們感興趣的內(nèi)容,因此導航條的曝光率較高。在這樣的背景下,提供一個動態(tài)靈活的導航條,為產(chǎn)品賦能,變得尤其重要。
拿iOS原生導航條為例,導航條作為頁面進出棧的根視圖連接器,以及生命周期的管理器。尤其是在作為webView Controller的父容器的時候,面對webview中h5頁面靈活的的路由屬性,以及一些難料的異常情況,原生很難也不便于頻繁操作根試圖容器,因此也產(chǎn)生了一些性能差、體驗差、開發(fā)成本高、測試場景難覆蓋等問題。安卓也有類似情況。
?ssr預渲染時,無法對原生導航條進行預加載。對于百億,便宜包郵等使用ssr預渲染的頻道,因為原生導航欄無法進行預加載,導致上屏較慢等問題。
?原生導航條生命周期耦合。原生導航條作為webviewController的根容器,一旦操作時機不當,很可能影響到線上頁面,而且最大的問題在于這種場景測試很難覆蓋。比如:window.href.url使用這種方式更新當前頁面時,由于不同頻道操作同一根導航條,會引發(fā)不可預知的問題;
?場景有限。站外場景無法使用原生導航條,一些業(yè)務方往往需要單獨處理站內(nèi)外,造成開發(fā)資源浪費。
?webview初始化時會預置一個默認的導航條,然后根據(jù)前端配置,再去設置導航條的不同樣式,無法避免的存在一個過渡期,體驗較差。
?window.location.reload()刷新當前頁面的時候,即便是在js中隱藏了導航條,webview為了兼容一個線上問題,執(zhí)行reload時此時會先展示原生導航條,直到執(zhí)行了js的隱藏邏輯,才會被隱藏,體驗較差。
?無法擴展交互動效。得益于移動端頁面中,導航條得天獨厚的位置,產(chǎn)品往往希望有更生動的交互性,來提高曝光、粘性、活動觸達率等。比如導航欄上掛載搜索框、以及吸頂、延伸動畫、沉浸式、炫酷的營銷icon等等。遺憾的是原生系統(tǒng)導航條不能全部支持,其實無論從視圖層級上來說,還是從導航條職責上來說,apple并不希望過多操作導航欄上的元素。也就造成了高曝光位置的資源浪費。
?因為要依賴原生JS橋,就一定會存在版本限制問題。造成需求迭代慢,甚至隨著時間的推移,版本卡口原因無跡可尋,代碼調(diào)整戰(zhàn)戰(zhàn)兢兢,版本審核慢、周期長等問題。
基于原生導航條現(xiàn)狀,百億補貼頻道沉淀出了通用H5導航條組件@pango/navigation-bar,具有以下優(yōu)勢:
?支持ssr預渲染,上屏較快。
?人力節(jié)省百分之90%以上,以plus 95折為例,對接只需0.5/人日。
?無場景限制??捎糜谡緝?nèi)外,ssr以及csr場景,無需站內(nèi)外多次開發(fā)。
?可配置。 @pango/navigation-bar使用config的形式配置item,這么做的好處是一旦業(yè)務需求改動,只需調(diào)整配置,無需調(diào)整組件邏輯,極大降低開發(fā)和測試成本。另外如果你使用主站的webview并且配置了config,那么只需要簡單的改動config,代碼遷移成本低。
?該組件發(fā)布在JNPM上,大小只有4.1K,接入簡單。
?導航條在頻道內(nèi)和其他普通樓層無異,生命周期隔離清晰,不會影響別的頁面,測試成本低。
?單向數(shù)據(jù)流設計,外部數(shù)據(jù)變化,組件UI及時響應,不存在原生的操作窗口問題,開發(fā)體驗佳;
?生命周期和其他樓層保持同步,規(guī)避了原生容器和H5頁面天然的生命周期無法同步的問題,也就不存在兩者之間的過渡問題,體驗佳。
?采用左、中、右、狀態(tài)欄、導航欄分層設計的模式,支持傳入React.ReactElement,比原生定制性更強,可靈活定制目前站內(nèi)絕大部分導航條樣式以及交互動畫,合理高效利用導航條資源;
?參考原生導航欄異形屏適配方案,參考原生絕對布局思路,完美適配折疊屏、異形屏。
?iOS9 - 最新 、Android5 - 最新均兼容性良好,未發(fā)現(xiàn)線上兼容異常。
純手工打造,未使用第三方庫,不會對宿主造成依賴沖突,隨時改動隨時發(fā)布不存在版本控制,最大程度的降低和隔斷對原生容器的版本依賴。
原生導航條作為根試圖容器,容器內(nèi)子視圖異常不會影響根試圖的展示,所以不用特殊處理html下載失敗,js執(zhí)行異常,服務掛掉等異常情況。但是H5導航條遇到這些異常情況,也要保證用戶可以點擊返回按鈕返回上一頁。
目前方案已和通天塔以及hybrid團隊打通,方案如下:
異常場景1:業(yè)務js執(zhí)行異常。
? @pango/navigation-bar組件使用a標簽渲染返回按鈕,保證js執(zhí)行異常時依然展示返回按鈕,并且能正常響應返回事件。
?業(yè)務展示兜底錯誤頁時,會使用導航條兜底數(shù)據(jù)渲染導航條確??煞祷厣弦患墶?/span>
異常場景2:webview加載html失敗。
為了消除上面提到的過渡問題,業(yè)務鏈接中新增了qurey參數(shù)hideNavi=1 ,原生webview會通過該字段在webview出現(xiàn)之前隱藏導航條。但是因此也引發(fā)了一個風險:html加載失敗時,會造成無頭的問題。因此需要webview配合改造,一旦監(jiān)測到html加載失敗,原生webview要展示原生導航條。
異常場景3:通天塔服務異常。
同樣是場景2中的問題,需要通天塔配合改造通天塔服務異常的場景:依據(jù)鏈接中hideNavi字段添加返回按鈕或者通知webview展示默認導航條。
觀察多個競品以及兄弟頻道,發(fā)現(xiàn)在上述的異常場景2、3下,均未做特別處理,展示無頭錯誤頁。如果此時原生禁用了右滑返回手勢,頁面將無法返回上一級,這無異是一個非常嚴重的缺陷(事實上有些競品頁面以及我們某些頻道確實無法返回上一級)。
目前使用該組件的項目:百億補貼、月黑風高、PLUS95折。
參考原生navigationBar的設計思路,把整個導航欄分為左、右、中三個區(qū)域,左、右區(qū)域根據(jù)內(nèi)容自適應寬度,剩余空間為中間區(qū)域。左右區(qū)域接受items數(shù)組,可根據(jù)item接口協(xié)議設置左右的items,協(xié)議可自定義圖片、尺寸、事件、間距、下拉菜單、是否動畫響應等,已默認包含了關(guān)注、返回、更多、頻道logo等常用元素,當然如有需要也可以自定義一個React.ReactElement。中間區(qū)域只接受React.ReactElement,你可以自由定制元素,傳入navigation-bar即可,一張圖片一段文字,或者是一個搜索框……不管是伸縮或者是上滑吸頂,都可自定義。
該組件發(fā)布在JNPM上,使用react + ts開發(fā),大小只有4.1K。
文件結(jié)構(gòu):
npm i @pango/navigation-bar --registry=http://registry.m.jd.com
你可以自由配置items除了"follow", "more","back","logo",這些已知的元素外還可以設置type:"common",是一個通用類型的item;
scrollCallBack會回調(diào)上滑比例,可根據(jù)該比例做交互動畫;
import {
BACK_ICON,
FEEDBACK_ICON,
FEEDBACK_URL,
INavigationParams,
MORE_ICON,
RULE_ICON,
SHARE_ICON,
} from "@pango/navigation-bar";
setH5NavigationButton = (headerData) => {
const extend = headerData?.navigationBar?.extend;
const followInfo = headerData?.navigationBar?.followInfo;
const follow = {
type: "follow",
collectionId: String(followInfo?.themeId),
gapWidth: 12,
width: 55,
height: 22,
};
const moreItem = {
type: "more",
menuBackgroundColor: "white",
img: MORE_ICON,
title: "更多",
menuList: [],
};
moreItem.menuList.push({
icon: RULE_ICON,
title: "規(guī)則頁",
menuEventData: extend?.guideUrl,
});
moreItem.menuList.push({
icon: SHARE_ICON,
title: "分享",
type: "share",
menuEventData: extend?.share,
});
const backItem = {
type: "back",
img: BACK_ICON,
canClick: !margicWindow,
title: "返回",
};
const backLogo = {
type: "logo",
img: DEFAULT_LOGO,
isAnimation: true,
gapWidth: 5,
width: 176,
height: 34
};
const navBarParams: INavigationParams = {
leftItems: [],
rightItems: [],
backgroundColor: "#FD4D00",
navHeight: this.status.navHeight,
};
navBarParams.leftItems.push(backItem, backLogo);
navBarParams.rightItems.push(moreItem, follow);
navBarParams.titleImgItem = TitleSearch({});
navBarParams.scrollCallBack = (scale) => {
this.setStatus({
navigationBarParams: Object.assign(this.status.navigationBarParams, {
titleImgItem: TitleSearch({ isCollapse: scale === 1 })
})
});
}
return navBarParams;
};
特別注意titleImgItem,這個屬性是導航條中間區(qū)域的展示內(nèi)容,TitleSearch是百億補貼的搜索框,你可以參考該元素自定義中間區(qū)域。
?title-search-view.tsx?
?title-search-view.scss?
import { INavigationParams, NavigationBar } from "@pango/navigation-bar";
import "@pango/navigation-bar/lib/navigation-bar.scss";
css
.nav-bar {
width: 750px;
z-index: 1;
top: 0px;
}
<NavigationBar
className="nav-bar"
params={data.navParams}
barHeight={200} //自定義導航欄高度
event={do somethings}
/>
Q:若原生導航條隱藏,此時異常怎么辦?
異常分為以下3類:
異常場景1:業(yè)務js執(zhí)行異常。
? @pango/navigation-bar組件使用a標簽渲染返回按鈕,保證js執(zhí)行異常時依然展示該標簽,并且能正常相應出棧事件。
?業(yè)務展示兜底錯誤頁時,會使用導航條兜底數(shù)據(jù)渲染導航條。
異常場景2:webview加載html失敗。
為了消除上面提到的過渡問題,業(yè)務鏈接中新增了qurey參數(shù)hideNavi=1 ,原生webview會通過該字段在webview出現(xiàn)之前隱藏導航條。但是因此也引發(fā)了一個風險:html加載失敗時,會造成無頭的問題。因此需要webview配合改造,一旦監(jiān)測到html加載失敗,原生webview要展示原生導航條。
異常場景3:通天塔服務異常。
同樣是場景2中的問題,需要通天塔配合改造通天塔服務異常的場景:依據(jù)鏈接中hideNavi字段添加返回按鈕或者通知webview展示默認導航條。
若發(fā)現(xiàn)其他異常,麻煩提醒我。
Q:折疊屏怎么適配?
折疊屏適配一直是前端適配的噩夢,噩夢的根本原因在于:寬度于高度的比例非常值,前端布局是往往會把px轉(zhuǎn)換成vw,因此造成了異形屏適配難的問題。
?參考原生系統(tǒng)導航欄的絕對布局方案:@pango/navigation-bar把導航條拆分為狀態(tài)欄和導航欄上下兩部分, 導航條寬度屏幕自適應,導航條高度跟隨設備變化,并采用大寫的PX單位來固定元素尺寸。根據(jù)協(xié)議item寬高、間距仍可自定義,但是大寫的PX保證了item不會隨著屏幕寬度而異常變化。
navigation-bar {
width: 750px; // 會轉(zhuǎn)換成vw
height: 44PX; // 不會轉(zhuǎn)換成vw
display: flex;
position: absolute;
.left-items-bg {
margin-left: 16PX; // 不會轉(zhuǎn)換成vw
height: 22PX;
margin-top: 11PX;
width: fit-content;
display: flex;
align-items: center;
justify-content: center;
}
}
Q:原生導航條優(yōu)化?
現(xiàn)狀中的幾個異常場景,仍需要webview配合一起整改,所以目前整改方案為:
業(yè)務鏈接中新增qurey參數(shù)hideNavi=1,此時 webview通過該字段在webview 出現(xiàn)之前隱藏導航條。由webview負責整改,跟版12.1.4。
經(jīng)安全部門審核之后,會向外開源。
?導航條在移動端頁面中的重要性無需多言,我們最終的目的是面向全集團,和通天塔以及hybrid團隊,一起打造一根規(guī)范通用的H5導航欄,如果你在使用過程中發(fā)現(xiàn)一些我們沒有考慮到的異常場景或者設計規(guī)范,請與我聯(lián)系,我們共同完善。
?目前該組件下拉刷新還是要依賴原生的下拉刷新事件,后期會定制H5自己的下拉刷新。
?一個規(guī)范的UI組件應該是一個有嚴格UI設計規(guī)范的,比如間距,字體大小、圖片規(guī)范等。但是一期的設計中我們?yōu)榱遂`活,通過協(xié)議把UI把控留給了用戶,也希望后面的迭代開發(fā)中融入更多規(guī)范的設計語言。
一個輕量級的tabs菜單組件,支持一二級菜單,聯(lián)動切場等功能,常用于商品分類展示。
作者:京東零售 張松超
來源:京東云開發(fā)者社區(qū) 轉(zhuǎn)載請注明來源
在切頁面的過程中,我們不得不將頁面寫的死死的,精確到每一個px,但帶來的弊端也是很明顯,甚至可以說是致命的。
為了讓PC頁面能夠真正自適應縮放,即使是用戶用手機瀏覽,也能保證其鋪滿整個屏幕,我們需要提出一個針對該問題的解決方案,這也是本文需要講的事情。
@-v-@
1. 為什么要讓頁面自動伸縮
上面這張圖片來自百度統(tǒng)計,從中我們可以看到:
近3個月以來,PC上,1920x1080分辨率的顯示器使用率最多,其次就是1366x768的分辨率了。
1366x768分辨率的顯示器,應當是裝在比較老的筆記本或特別舊的臺式機上的,主要還是筆記本占多數(shù)。這些顯示器的主要用戶群,應該是學生。
1920x1080分辨率的顯示器,應當是裝在比較新的筆記本或一般的臺式機上的。其中,臺式機應當占多數(shù)。它們的主要用戶群,應該是那些比較新潮的年輕人、網(wǎng)咖、社會工作人員等。
從這兒分析啊,我們就可以知道,1920x1080絕對是我們值得參考的一個屏幕尺寸。這個尺寸,在以后也會是主流。
為什么呢?
我們這樣來分析一下:
用于影院的大顯示器和家用的電視機的分辨率,肯定是越大越好,但并不是所有人都愿用money來買這種東西。最最主要的是,這種設備,追求的就是兩個大字,一是分辨率要大,二是尺寸要大。但很可惜,影院的大顯示器和家用的電視機是不太可能成為網(wǎng)頁中訪問量較高的那一部分的,至少當前不行。
你可能會想,尺寸小一點,分辨率高一點,豈不更好?
其實不是這樣的。如果有一個23.8英寸的顯示器,它的分辨率達到了4k,那么,我們是無法直接“正視”它的。至少對于我們這些普通人來說,是不能承受的。上面的字會小到讓你無法直視的地步。想一想,16px的字體,在一個4k分辨率,但僅23.8英寸的屏幕上呈現(xiàn)時的情況,你就知道了。
若要說具體點,就是當你用手機去訪問Github頁面時,不要進行縮放,直接觀看上面的文字,所產(chǎn)生的感受。(不建議你嘗試這樣做,幸好現(xiàn)在的手機屏幕一般都還不錯,否則你真的會瞎眼的o-v-^,如果非要試一試,先滴幾滴眼藥水吧?。?/p>
現(xiàn)在很多網(wǎng)站為了兼容這兩個用戶量最多的PC設備屏幕以及分辨率在它們之間的那些PC設備屏幕,將設計稿定成總寬1600px,內(nèi)容區(qū)域?qū)?200px的大小,就是為了保證絕大部分PC屏幕設備可以在不需要伸縮的情況下瀏覽,但這對于1920x1080分辨率設備的用戶來說,就不太友好了,因為這樣會留下很多的空白,視覺上體驗很不好。
為了解決這個問題,有些網(wǎng)站會使用多個媒體查詢來做不同分辨率的顯示器樣式匹配,就如同下面這樣:
/* 為適配手機尺寸而引入 */ @media only screen and (max-width: 240px) { ... } @media only screen and (min-width: 241px) and (max-width: 360px) { ... } @media only screen and (min-width: 361px) and (max-width: 480px) { ... } @media only screen and (min-width: 481px) and (max-width: 799px) { ... } @media only screen and (min-width: 800px) and (max-width: 1199px) { ... } /* 為適配PC尺寸而引入 */ @media only screen and (min-width: 1200px) and (max-width: 1600px) { ... } @media only screen and (min-width: 1601px) and (max-width: 2048px) { ... } @media only screen and (min-width: 2049px) and (max-width: 5000px) { ... } /** * 還可以增加一個媒體查詢項,即設備的橫豎屏狀態(tài) * 該狀態(tài)在下面會用到,而且是大有用處 * * (orientation : landscape) 代表設備豎屏時,書寫方式為: * @media only screen and (orientation : landscape) { ... } * * (orientation : portrait) 代表設備橫屏時,書寫方式為 * @media only screen and (orientation : portrait) { ... } */
<!-- 為適配手機尺寸而引入 --> <link rel="stylesheet" media="only screen and (max-width: 240px)" href="style-0-240.css"> <link rel="stylesheet" media="only screen and (min-width: 241px) and (max-width: 360px)" href="style-241-360.css"> <link rel="stylesheet" media="only screen and (min-width: 361px) and (max-width: 480px)" href="style-361-480.css"> <link rel="stylesheet" media="only screen and (min-width: 481px) and (max-width: 799px)" href="style-481-799.css"> <link rel="stylesheet" media="only screen and (min-width: 800px) and (max-width: 1199px)" href="style-800-1199.css"> <!-- 為適配PC尺寸而引入 --> <link rel="stylesheet" media="only screen and (min-width: 1200px) and (max-width: 1600px)" href="style-1200-1600.css"> <link rel="stylesheet" media="only screen and (min-width: 1601px) and (max-width: 2048px)" href="style-1601-2048.css"> <link rel="stylesheet" media="only screen and (min-width: 2049px) and (max-width: 5000px)" href="style-2049-5000.css">
當你看到這么大一長串媒體查詢的時候,是不是感覺挺煩的?
而且,你以為將頁面定死了之后,應用媒體查詢加載不同的css文件,或在同一文件中使用多個媒體查詢,頁面就一定可以適應所有的屏幕,但很可惜的是,事情并沒有你想的那么簡單。看下圖:
這是在1920x1080屏幕下瀏覽百度的頁面
這是在1366x768屏幕下瀏覽百度的頁面
百度使用的就是典型的1200px設計方式,像素是直接寫死了的。這種方式,其實也是現(xiàn)在大家普遍使用的方式,好處就是切圖方便直接,而且也利于更改,可以進行組件化開發(fā),是多少px就絕對不會偏差。但壞處是,對大屏幕不友好,會存在很多留白。
2. 一次切圖,到處運行的方案
我苦思冥想,怎樣才能使得“ 一次切圖,到處運行”?即使是碰到手機端訪問這個本屬于PC的頁面,我也不懼。
這真的是一個值得思考的問題。
我想到了兩種方式來解決這個問題,但都比較痛苦,因為它們都需要瀏覽器支持js腳本,如果用戶關(guān)閉了瀏覽器端js的渲染,就會出問題。
幸好,大部分用戶還是挺“講道理”的,不會無緣無故關(guān)閉這個功能。
接下來,我就來說說我想到的這兩個方案。
2.1 加載后,動態(tài)修改px
我們可以寫一個函數(shù),這個函數(shù)需要一個參考像素大小,還需要接受一個dom,用于指定對誰進行動態(tài)修改。
其次,我們在頁面加載完成后,運行一次這個函數(shù),并把這個函數(shù)添加到,當頁面大小更改時觸發(fā)的事件回調(diào)上。
接下來,最重要的就是,編寫這個函數(shù)了。它的運行過程是:
遍歷dom下的所有CssStyle中的屬性,以及dom下其它后代結(jié)點的中的CssStyle屬性,只要是那些有px長度值的屬性,統(tǒng)統(tǒng)都根據(jù)參考像素的大小,來更新。
這應該算是一種很笨,而且實現(xiàn)起來很難的方法。
2.2 用rem和em替換px值
這種方式應該算是最好的一種方式了,不用什么其他復雜的實現(xiàn)過程,只需要一段小小的js就能搞定一切。
不過呢,也會有問題的,那就是寫css的時候,需要弄清楚,什么時候該用rem,什么時候該用em。
一般來說,對一個組件的內(nèi)部,應該主要使用em,并且應當給組件容器的font-size,顯式指定一下對應于html標簽的font-size的大小。其他那些布局容器都使用rem或百分比作為單位。
可能我說的有點復雜,再簡單點說吧:
組件內(nèi)部使用em作為主要單位,盡可能少地使用px
組件容器的font-size使用rem作為單位,以指定組件的實際大小
布局容器的寬、高等布局屬性,全部使用rem作為單位
2.3 將來的布局新方式—-vw
如果沒辦法使用js,那么,我們可能就只能使用vw這個絕招了。
在網(wǎng)頁設計過程中,我發(fā)現(xiàn),其實所有的頁面布局容器,都跟一個量有關(guān),那就是視寬。
這兒的視寬并不是設備的寬度,而是指瀏覽器的視窗寬度。萬幸,有一個尺寸單位,可以來衡量瀏覽器的視窗寬度,這就是vw。
vw、vh、vmin、vmax都是視口相對長度單位(Viewport-relative Length Units),其中最有用處的是vw。
vw是一個相對于視口寬度的單位。瀏覽器視窗被分成100份,1vw就代表其中的一份,再簡單點說,就是 (1vw === 1% * 瀏覽器視窗寬度)
我們可以在開發(fā)過程中,使用vw替代掉rem,這樣,不需要js就可以讓頁面自適應縮放。
這時,我們就可以這樣做:
組件內(nèi)部使用em作為主要單位,盡可能少地使用px
組件容器的font-size使用vw作為單位,以指定組件的實際大小
布局容器的寬、高等布局屬性,全部使用vw作為單位
但是呢,最最讓人絕望的是…看下圖:
IE7和IE8暫時是消除不了的,這也就阻礙了我們使用vw單位,而且更重要的是,vw在安卓4.3以下都不行,如果我們一意孤行,使用它的話,帶來的災難就是,很大一部分手機會被網(wǎng)頁“淘汰”掉。
這一張圖,來自css88的vw兼容性信息截圖
天吶,vw是不是很“危險”?
沒錯,我們可以這樣認為: vw === 暫時性的禁區(qū)
,為了避免后期修改代碼,我們還是只能選擇使用rem,這個vw倒是將來切圖的一個利器,可以先備著。
3. 將第二種方案實現(xiàn)一下
廢話說了一大堆,情懷也聊的差不多了,接下來,我們來做一個使用 rem
+ auto flexible
搞定的html頁面吧。
這一次,我選擇使用我自己的首頁來說明一下它的切圖流程。
你可以去我的首頁地址試一下效果, 鏈接 => freeedit.cn
親請用不是Chrome的瀏覽器,打開這個鏈接,(如果是IE,請確保瀏覽器在IE10以上的模式下運行),然后把窗口大小進行縮放,看頁面是否有問題。如果存在問題,請給我在我的個人網(wǎng)站倉庫下留個issue,謝謝 ^-^。
3.1 準備作品的目錄
新建一個文件夾,取名叫pc-auto-flexible
在該文件夾中,新建以下文件及文件夾
index.html
css\
js\
lib\
img\
在css文件夾下新建一個名叫style.css
的文件
在js文件夾下新建一個名叫script.es5.js
的文件
在lib文件夾下新建一個名叫auto-flexible.js
的文件
然后,我們就來直接動手擼吧
3.2 準備好auto-flexible.js的內(nèi)容
首先,我們肯定需要添加事件,所以需要一個門面
來包裝一下這個添加事件的功能,保證在任何瀏覽器上都能添加事件。
其實這些代碼,相信大家都已經(jīng)寫過很多遍了,這兒就直接給代碼了,沒有什么好說的,真正重要的,是接下來的代碼。
function addEvent(el, type, fn, isBubble) { if (el) { if (window.addEventListener) el.addEventListener(type, fn, isBubble); else if (window.attachEvent) el.attachEvent('on' + type, fn, isBubble); else { var onEv = 'on' + type; var onFn = onEv + 'Fn'; var onBu = onEv + 'Bu'; el[onBu] = isBubble; if (!el[onFn]) { el[onFn] = []; el[onFn].push(fn); el[onEv] = function (e) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = el[onFn][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { ev = _step.value; ev(e); if (!isBubble) stopEvent(e); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } }; } else { el[onFn].push(fn); } } } }
接下來的這個代碼是auto-flexible
實現(xiàn)的關(guān)鍵,它并非是我寫的,我只是給它潤了潤色,原始的實現(xiàn)代碼是來自網(wǎng)絡上的一篇文章,具體在哪里,我已經(jīng)找不到了(作者,請原諒我 -。o-
)。
(function (doc, win) { var docEl = doc.documentElement; var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; var recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; docEl.style.fontSize = 100 * (clientWidth / 1366) + 'px'; }; docEl.style.textSizeAdjust = 'auto'; addEvent(win, resizeEvt, recalc, false); addEvent(doc, 'DOMContentLoaded', recalc, false); })(document, window);
在閱讀上面這段代碼的時候,我們先來看看DOM文檔的加載步驟:
首先解析HTML結(jié)構(gòu)
然后加載外部腳本和樣式表文件
接著解析并執(zhí)行腳本代碼
DOM樹構(gòu)建完成 => DOMContentLoaded
加載圖片等外部文件
頁面加載完畢 => load
document.documentElement
的DOMContentLoaded事件
在第4步發(fā)生,即等DOM樹加載完成后,立即更新其style.fontSize
屬性。
其實document.documentElement
對應的就是html
標簽元素,在XML中就是文檔根節(jié)點。
在window
上面添加orientationchange
或resize
事件,是為了當屏幕方向更改,或者瀏覽器寬度被更改時,html
標簽的style.fontSize
屬性就會被recalc函數(shù)計算后的值替換掉。
docEl.style.textSizeAdjust = 'auto';
是用來保證在老版本的Chrome瀏覽器下,字體能夠被縮放。
為什么在上面,我會專門說明,不用Chrome瀏覽器打開,就是因為在新版本的Chrome瀏覽器下,文字是不能小于12px的,即使是將html
標簽的style.textSizeAdjust
樣式屬性設為auto
,也一點用都沒有。
這是為什么呢?一直對我們開發(fā)人員很有好的Chrome瀏覽器,為什么會搞這么一手呢?
還記得最上面提到的那個小尺寸高分辨率屏幕的問題么?
Chrome瀏覽器畢竟需要考慮用戶的感受,它設置字體不能小于12px,就是因為字體一般是16px-16px的矩陣,設置字體為12px、14px、16px這種偶數(shù)型的,能更利于字體的渲染速度和渲染效果。而且12px的的確確算是比較小的字體了,再小的話,就會影響到用戶的閱讀了,為了避免瞎眼
,Chrome就直接給我們丟來了一個根本無法解決的題。
docEl.style.fontSize = 100 * (clientWidth / 1366) + 'px';
是這段代碼中,最最主要的功能實現(xiàn)。
1366
代表使用1366x768的屏幕作為設計參考,來進行頁面的切圖工作。
100
代筆在1366x768的屏幕下,html的font-size為100px,這樣方便于我們在切圖過程中進行計算。
當我們拿著一張標準的1600px-1200px的設計稿時,我們就可以直接用1200px === 12rem
來表示主體內(nèi)容的容器寬度。
其實本來可以這樣的: docEl.style.fontSize = clientWidth / 100 + 'px';
簡單粗暴,直接將頁面的寬度分成100分,rem就有了和vw一樣的能力。
但是這并不方便于計算,所以我將其改成了在1366x768的屏幕下100px === 1rem
的形式。
為什么沒有使用1920x1080分辨率來作為設計參考呢?這是為了設計的美觀性和便捷性。
在1920x1080分辨率下設計網(wǎng)站樣式,不利于我們掌控文字的大小。1366x768分辨率下,我們可以直接使用16px的字體,這個字體不會顯得太大,也不會顯得太小,正好合適。
上面的兩段代碼,都應放在auto-flexible.js文件下。
如果復制存在問題,可以去https://github.com/freeedit/lib-mini-libs-collection/blob/master/auto-flexible.js上面復制一下代碼
3.3 準備好其它文件的內(nèi)容
剛才建了一堆的文件,其實只是為了讓你了解一下這個例子的結(jié)構(gòu),和auto-flexible的實現(xiàn)方法。
我們現(xiàn)在就去https://github.com/freeedit/learn-pc-auto-flexible上面,將這個庫克隆至本地,然后從中取出new-project文件夾下的所有文件和文件夾,放置在pc-auto-flexible文件夾中,最后選擇“是”,將其全部覆蓋。
3.4 編寫HTML代碼
建議在書寫的過程中,使用browser-over打開瀏覽器來實時預覽該效果
打開index.html文件,編寫頁面整體的結(jié)構(gòu)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="./lib/auto-flexible.js"></script> <!-- <link rel="apple-touch-icon" href="./img/favicon.png"> --> <link rel="Shortcut Icon" href="./img/favicon.ico" type="image/x-icon"> <title>易杭網(wǎng) | 首頁</title> <!-- <link rel="stylesheet" href="./lib/normalize.css"> --> <link rel="stylesheet" href="./css/style.css"> <!-- <script src="./lib/prefixfree.min.js"></script> --> </head> <body> <div class="yh-container no-scroll"> <!-- 頁面最上面的浮動層所在地 --> </div> <script src="./js/script.es5.js"></script> </body> </html>
編寫頁面最上面的浮動層
<div class="yh-over__icon-container"> <img src="./img/yh-icon.svg" alt="" class="yh-over__icon"> </div> <div class="yh-over posa-full"> <img src="./img/yh-name.svg" alt="" class="yh-over__bg posa-center"> </div> <!-- 頁面的主體容器所在地 -->
編寫頁面的主體容器
<div class="yh-page no-scroll" oncontextmenu="return false;" ondragstart="return false" onselectstart="return false" onselect="document.selection.empty();"> <div class="yh-page__bd posa-center clearfix"> <!-- 頁面的主體所在地 --> </div> <div class="yh-page__over-layer posa-center"></div> <img src="./img/1366x768-1.jpg" alt="" class="yh-page__bg posa-center"> </div>
編寫頁面的主體
<!-- 最左側(cè)的展示區(qū)域 --> <div class="yh-display no-scroll flex-cont-center"> <img src="./img/24x24-1.png" alt="" class="yh-display__animation-controller"> <img src="./img/35x25-1.png" alt="" class="yh-display__seal"> <img src="./img/100x240-1.png" alt="" class="yh-display__art-font posa-center"> <div class="yh-display__over-layer posa-full"></div> <img src="./img/240x400-1.jpg" alt="" class="yh-display__animation"> </div> <!-- 中間的個人鏈接區(qū)域 --> <div class="yh-about"> <a class="yh-about__who-am-i no-scroll flex-cont-center"> <span class="yh-about__desc">WHO AM I</span> </a> <a href="javascript:;" class="yh-about__what-i-do no-scroll flex-cont-center"> <span class="yh-about__desc">WHAT I DO</span> </a> <a href="javascript:;" class="yh-about__what-i-use no-scroll flex-cont-center"> <span class="yh-about__desc">WHAT I USE</span> </a> <a href="javascript:;" class="yh-about__other no-scroll flex-cont-center"> <span class="yh-about__desc">OTHER INFO</span> </a> </div> <!-- 右邊的四大區(qū)塊 --> <div class="yh-domains"> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">0</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭博客</div> <a class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭博客</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 地震高崗,<br/>一派溪山千古秀。<br/> 門朝大海,<br/>三河合水萬年流。 </strong> <img src="./img/40x40-1.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-1.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭倉庫</div> <a class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭倉庫</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 竹杖芒鞋輕勝馬,<br/> 誰怕?<br/> 一蓑煙雨任平生。 </strong> <img src="./img/40x40-2.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-2.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭動態(tài)</div> <a href="javascript:;" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭動態(tài)</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 人生若只如初見,<br/> 何事秋風悲畫扇。 </strong> <img src="./img/40x40-3.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-3.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭導航</div> <a href="javascript:;" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭導航</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 俏也不爭春,<br/> 只把春來報。<br/> 待到山花爛漫時,<br/> 她在叢中笑。 </strong> <img src="./img/40x40-4.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-4.jpg" alt="" class="yh-domain__bg"> </div> </div> <!-- 最下面的備案信息 --> <div class="yh-beian-info posa-horizontal-center"> <a >蜀ICP備16016576號-1 <strong>[易杭網(wǎng)]</strong></a> <a >http://www.beianbeian.com/search/<strong>freeedit.cn</strong></a> </div>
當你書寫完成該html代碼的時候,就可以試一試會不會出現(xiàn)和www.freeedit.cn首頁一樣的效果。
3.5 使用px2rem搞定css中的px
在style.css文件中,我們可以看到,里面使用的全是以px為單位的布局方式,我們需要將其轉(zhuǎn)換為rem。
在命令提示符中,使用npm安裝一個名叫px2rem的包,它可以幫助我們用命令行的方式生成新文件。
在命令提示符中,切換到css文件夾下,使用以下命令生成新文件
$ px2rem -u 100 *.css -o ./
最后改一下<link rel="stylesheet" href="./css/style.css">
中的href值為./css/style.debug.css
運行一下index.html文件 看看是否可以自動伸縮了。
4 總結(jié)
最好的方式是自己約束自己,一開始就以rem和em為主進行切圖,遵循的規(guī)則是:
組件內(nèi)部使用em作為主要單位,盡可能少地使用px
組件容器的font-size使用rem作為單位,以指定組件的實際大小
布局容器的寬、高等布局屬性,全部使用rem作為單位
在最開始切圖的時候,也可以使用px來搞定頁面,然后再用px2rem轉(zhuǎn)一下文件。
這種方式會存在問題,比如較窄的邊框和較小的陰影效果等,都可能因為長度值出現(xiàn)小數(shù)點,而使線條變得模糊,盡管肉眼可能看不到。
以上就是本文的全部內(nèi)容,不知道這個技能,對于你而言,是不是有用的。
如果你認同本文的某些觀點,并且挺喜歡我滴~,請給我的倉庫點個贊好么 (o_o)
本文使用的代碼: https://github.com/freeedit/learn-pc-auto-flexible
如果你能follow我一下,就更好了。 a li ga do ^&-&^
我的Github
最后的最后,我想和大家一起來寫ES的知識總結(jié),不知道你能否給我個膝蓋。
詳情傳送地 => -^-^-
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。