整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          css實現(xiàn)nav菜單動畫加載折疊伸縮效果

          天就來做一款nav炫酷的下拉菜單效果,適合在PC端和移動端使用,運用到CSS3的動畫和過渡屬性,感興趣的朋友可以看看!

          實現(xiàn)效果如下:

          鼠標移上“菜單”兩個字時,二級的下拉菜單像百葉窗一樣打開,鼠標移走后也會收縮隱藏起來!

          實現(xiàn)代碼

          html結(jié)構(gòu):

          css樣式:

          在移動端頁面中,由于屏幕空間有限,導航條扮演著非常重要的角色,提供了快速導航到不同頁面或功能的方式。用戶也通常會在導航條中尋找他們感興趣的內(nèi)容,因此導航條的曝光率較高。在這樣的背景下,提供一個動態(tài)靈活的導航條,為產(chǎn)品賦能,變得尤其重要。

          使用原生導航欄現(xiàn)狀

          拿iOS原生導航條為例,導航條作為頁面進出棧的根視圖連接器,以及生命周期的管理器。尤其是在作為webView Controller的父容器的時候,面對webview中h5頁面靈活的的路由屬性,以及一些難料的異常情況,原生很難也不便于頻繁操作根試圖容器,因此也產(chǎn)生了一些性能差、體驗差、開發(fā)成本高、測試場景難覆蓋等問題。安卓也有類似情況。

          1、性能問題

          ?ssr預渲染時,無法對原生導航條進行預加載。對于百億,便宜包郵等使用ssr預渲染的頻道,因為原生導航欄無法進行預加載,導致上屏較慢等問題。

          2、開發(fā)/測試成本高

          ?原生導航條生命周期耦合。原生導航條作為webviewController的根容器,一旦操作時機不當,很可能影響到線上頁面,而且最大的問題在于這種場景測試很難覆蓋。比如:window.href.url使用這種方式更新當前頁面時,由于不同頻道操作同一根導航條,會引發(fā)不可預知的問題;

          ?場景有限。站外場景無法使用原生導航條,一些業(yè)務方往往需要單獨處理站內(nèi)外,造成開發(fā)資源浪費。

          3、體驗差

          ?webview初始化時會預置一個默認的導航條,然后根據(jù)前端配置,再去設置導航條的不同樣式,無法避免的存在一個過渡期,體驗較差。

          ?window.location.reload()刷新當前頁面的時候,即便是在js中隱藏了導航條,webview為了兼容一個線上問題,執(zhí)行reload時此時會先展示原生導航條,直到執(zhí)行了js的隱藏邏輯,才會被隱藏,體驗較差。

          4、難擴展造成營銷資源浪費

          ?無法擴展交互動效。得益于移動端頁面中,導航條得天獨厚的位置,產(chǎn)品往往希望有更生動的交互性,來提高曝光、粘性、活動觸達率等。比如導航欄上掛載搜索框、以及吸頂、延伸動畫、沉浸式、炫酷的營銷icon等等。遺憾的是原生系統(tǒng)導航條不能全部支持,其實無論從視圖層級上來說,還是從導航條職責上來說,apple并不希望過多操作導航欄上的元素。也就造成了高曝光位置的資源浪費。

          5、依賴性強

          ?因為要依賴原生JS橋,就一定會存在版本限制問題。造成需求迭代慢,甚至隨著時間的推移,版本卡口原因無跡可尋,代碼調(diào)整戰(zhàn)戰(zhàn)兢兢,版本審核慢、周期長等問題。

          解決方案

          基于原生導航條現(xiàn)狀,百億補貼頻道沉淀出了通用H5導航條組件@pango/navigation-bar,具有以下優(yōu)勢:

          1、性能好

          ?支持ssr預渲染,上屏較快。

          2、開發(fā)/測試成本低

          ?人力節(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ā)體驗佳;

          3、用戶體驗好

          ?生命周期和其他樓層保持同步,規(guī)避了原生容器和H5頁面天然的生命周期無法同步的問題,也就不存在兩者之間的過渡問題,體驗佳。

          4、靈活定制

          ?采用左、中、右、狀態(tài)欄、導航欄分層設計的模式,支持傳入React.ReactElement,比原生定制性更強,可靈活定制目前站內(nèi)絕大部分導航條樣式以及交互動畫,合理高效利用導航條資源;

          5、機型、系統(tǒng)兼容性好

          ?參考原生導航欄異形屏適配方案,參考原生絕對布局思路,完美適配折疊屏、異形屏。

          ?iOS9 - 最新 、Android5 - 最新均兼容性良好,未發(fā)現(xiàn)線上兼容異常。

          6、不對外依賴

          純手工打造,未使用第三方庫,不會對宿主造成依賴沖突,隨時改動隨時發(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即可,一張圖片一段文字,或者是一個搜索框……不管是伸縮或者是上滑吸頂,都可自定義。

          @pango/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

          特別注意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ī)范的設計語言。

          相關(guān)推薦

          一個輕量級的tabs菜單組件,支持一二級菜單,聯(lián)動切場等功能,常用于商品分類展示。

          作者:京東零售 張松超

          來源:京東云開發(fā)者社區(qū) 轉(zhuǎn)載請注明來源

          PC頁面自動伸縮,以適應所有設備

          在切頁面的過程中,我們不得不將頁面寫的死死的,精確到每一個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文檔的加載步驟:

          1. 首先解析HTML結(jié)構(gòu)

          2. 然后加載外部腳本和樣式表文件

          3. 接著解析并執(zhí)行腳本代碼

          4. DOM樹構(gòu)建完成 => DOMContentLoaded

          5. 加載圖片等外部文件

          6. 頁面加載完畢 => load

          document.documentElementDOMContentLoaded事件在第4步發(fā)生,即等DOM樹加載完成后,立即更新其style.fontSize屬性。

          其實document.documentElement對應的就是html標簽元素,在XML中就是文檔根節(jié)點。

          window上面添加orientationchangeresize事件,是為了當屏幕方向更改,或者瀏覽器寬度被更改時,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é),不知道你能否給我個膝蓋。

          詳情傳送地 => -^-^-


          主站蜘蛛池模板: 精品一区二区在线观看| 一区二区三区视频观看| 亚洲一区二区高清| 3d动漫精品啪啪一区二区中文| 一区二区三区免费在线观看| 国产午夜精品一区二区三区嫩草 | 尤物精品视频一区二区三区 | 在线精品亚洲一区二区| 亚洲a∨无码一区二区| 美女视频黄a视频全免费网站一区| 国产情侣一区二区三区| 欧美日韩精品一区二区在线视频| 中文无码一区二区不卡αv| 亚洲AV无码一区二区二三区入口| 精品无码综合一区| 日韩一区二区久久久久久| 国产精品伦一区二区三级视频| 国产福利电影一区二区三区久久老子无码午夜伦不 | 亚洲一区二区三区四区视频| 视频一区二区三区免费观看| 蜜桃AV抽搐高潮一区二区| 激情内射亚洲一区二区三区 | 人妻无码第一区二区三区| 国产精品自拍一区| 日本一区精品久久久久影院| 中文无码一区二区不卡αv| 3d动漫精品成人一区二区三| 日本一区二区三区不卡在线视频 | 国产在线一区二区三区| 国产日韩一区二区三免费高清| 免费无码VA一区二区三区| 无码人妻啪啪一区二区| 国产成人综合亚洲一区| 国产乱码精品一区二区三区香蕉| 四虎成人精品一区二区免费网站 | 日韩精品无码人妻一区二区三区| 久久精品人妻一区二区三区| 国产成人精品一区二区秒拍| 国产精品一区二区久久| 视频一区视频二区制服丝袜| 国产在线aaa片一区二区99|