<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      web開發中移動端適配

      這個話題有些復雜,說起來有些瑣碎,因為和移動端適配相關的問題太多了。

      1. 概念

      1.1 設備像素

      設備像素被稱為物理像素,它是顯示設備中一個最小的物理部件。每個像素可以根據操作系統設置自己的顏色和亮度。這些設備像素的微小距離欺騙了我們肉眼看到的圖像效果。

      1.2 屏幕密度(ppi)

      屏幕密度是指一個設備表面上存在的像素數量,它通常以每1英寸上排列有多少像素來計算(ppiPixels Per Inch)。蘋果公司聲稱人類的肉眼無法區分單個像素,當一個顯示器像素密度超過300ppi的時候,肉眼就無法區分出單獨的像素。也就是說設備清晰度超過人的視網膜可以分辨像素的極限。因此手機顯示器的像素密度達到或超過300ppi就不會出現顆粒感,平板電腦像素密度達到或超過260ppi就不會再出現顆粒感。蘋果公司給這類設備起了一個科技感十足的名字“Retina”屏,即視網膜屏

      1.3 css像素

      css是一個相對的單位,主要使用在瀏覽器上,用來精確地度量web頁面上的內容。一般情況,css像素被稱為與設備無關的像素(device-independent像素),簡稱dips,也叫設備獨立像素,名字多,容易混淆。在一個標準顯示密度下,一個css像素對應著一個設備像素。

      <div height="200" width="300"></div> 

      上面的代碼重定義了一個為200px,高為300px的div盒子。但是在Retina屏下,相同的div卻使用了400X600的設備像素保持相同的物理尺寸顯示,導致每個css像素點實際上有4倍的普通像素點。

      如果我們把這個寬,高屬性設置在一張圖片上,如下css設置

      img {
          width: 200px;
          height: 200px;
      } 

      在Retina屏中,這樣一個css像素點實際上分成了4個設備像素點,造成顏色會近似選取,于是造成我們看上去變得模糊

      因此在Retina屏上要想清晰地還原圖片,需要一個原始尺寸為400X400css像素的圖片,而css像素仍然是200X200。如下:

      此外還可以使用device-pixel-ratio來處理,下面內容將會介紹。

      1.4 dips(叫dip或者dp或者divice independent pixels)

      設備獨立像素(也叫密度無關像素),可以認為是計算機屏幕坐標系統中的一個點,這個點代表一個可以由程序使用的虛擬像素(比如:css像素)然后由系統轉換為物理像素。dips可以用來輔助區分視網膜設備。視網膜設備是指分辨率達到300ppi的屏幕。

      1.5 dpr(window.divicePixelRatio

      divicePixelRatio是設備上物理像素和設備獨立像素(dips)的比例,即window.divicePixelRatio = 物理像素/dips。以iphone4s為例說明,它是“Retina屏”,分辨率為960x640,以二者較小的屏幕寬度來計算,物理像素640px,設備獨立像素320px,那么window.devicePixelRatio = 640px / 320px = 2

      1.6 Retina屏高清圖片模糊問題

      為了提升用戶體驗,節省移動端流量,針對不同的顯示屏,采用不同的方案,保證圖片在不同顯示屏幕下正常顯示。這里采用的方法和原生app中針對不同分辨率采用不同圖片的原理類似。有以下兩點:

      a. 普通顯示屏(devicePixelRation = 1.0, 1.3)加載一張1倍的圖片
      b. Retina顯示屏(divicePixelRation >= 1.5, 2.0, 3.0 )加載一張2倍大小的圖片

      利用媒體查詢結合devicePixelRatio可以區分普通顯示屏和高清顯示屏

      .css{/* 普通顯示屏(設備像素比例小于等于1.3)使用1倍的圖 */ 
          background-image: url(img_1x.png);
      }
      @media only screen and (-webkit-min-device-pixel-ratio:1.5){
      .css{/* 高清顯示屏(設備像素比例大于等于1.5)使用2倍圖  */
          background-image: url(img_2x.png);
        }
      }

      也可以使用image-set加載不同圖片,image-set,是webkit的私有屬性,也是css3的一個屬性,目前已經有部分瀏覽器支持。它是為了解決Retina屏幕下的圖像顯示而生。

      .css{
          background: url(../img/bank_ico.png) no-repeat;/* 不支持image-set的顯示屏 */ 
          background: -webkit-image-set(
                      url(../img/bank_ico.png) 1x,/* 支持image-set的瀏覽器的[普通屏幕]下 */
                      url(../img/bank_ico_retina.png) 2x);/* 支持image-set的瀏覽器的[Retina屏幕] */
                      
      } 

      上面兩種方式都會使用兩套或者多套圖片,增加了工作量。

      1.7 dip&dp(設備獨立像素&密度無關像素)

      dip:divice independentpixels,設備獨立像素,一個基于density的抽象單位。不同設備下有不同的顯示效果,這個和設備硬件有關,在Android上開發的程序將會在不同分辨率的手機上運行。為了讓程序外觀不至于相差太大,引入了dip的概念。例如定義一個10 X 10dip的矩形,在分辨率為160dpi的屏幕上,剛好是10 x 10像素;而在240dpi的屏,則是15 x 15像素,換算公式為pixs = dips * (density / 160),density就是屏幕的分辨率。

      這里注意dip與屏幕密度有關,而屏幕密度與具體的硬件有關,硬件設置不正確,有可能導致dip不能正產顯示。在屏幕密度為160的顯示屏上,1dip === 1px,有時候屏幕分辨率很大,例如400 * 800,但是屏幕密度沒有正確的設置,比如還是設置成160,那么凡是使用dip的都會顯示過小。

      dp:與密度無關的像素,同dip一樣是一種基于屏幕密度的抽象單位,在每英寸160點的顯示器上,1dp=1px。

      所有非視網膜屏幕的iPhone設備在垂直屏幕顯示的時候,它的寬度為320物理像素,通過meta改變viewport時

      <meta name="viewport" content="width=device-width"> 

      這時視窗布局變成320px(不同于視覺區域寬度,不放大顯示的情況下,兩者大小一致) ,這樣整個頁面自然地覆蓋在屏幕上。這樣非視網膜屏幕的iPhone上,屏幕的物理像素320像素,獨立像素也是320像素,因此window.devicePixelRatio等于1。

      而對于視網膜屏幕的iPhone,如iPhone4s,縱向顯示的時候屏幕物理像素640,同樣當用戶設置

      <meta name="viewport" content="width=device-width"> 

      這個時候,視區寬度并不是640像素,而是320像素,這時為了更好的閱讀體驗,更合適大小的文字。這樣物理像素是640像素,獨立像素還是320px,因此window.divicePixelratio等于2。

      1.8 位圖像素

      位圖像素(Pixel)組成的,像素是位圖最小的信息單元,存儲在圖像柵格中(PNG, JPG, GIF)。每個像素都具有特定的位置和顏色值。從左到右,從上到下的順序記錄圖像中的每一個像素信息,如:像素在屏幕上的位置,像素的顏色等信息。位圖圖像是有單位長度內像素的多少來決定的。單位長度內像素越多,分辨率越高,圖像效果越好。

      位圖也稱為“位圖圖像”,“點陣圖像”,“數據圖像”,“數碼圖像”。基于圖像的格柵分辨率,圖像在web中是由css像素定義了一個抽象的大小。瀏覽器擠壓或者拉伸圖像都是基于其css高度或者寬度來呈現的過程。

      當一個光柵圖像在標準設備下全屏顯示時,一位圖像素對應的就是一設備像素,導致一個完全保真的顯示。因為一個像素不能進一步分裂,在Retina屏幕下,要放大四倍來保持相同的物理像素大小,這樣就會丟失很多的細節,造成失真的情況。換句話說,每一位圖像素被乘以四填補相同的物理標簽在Retina屏幕下顯示。

      1.9 高分辨率屏幕&高像素密度屏幕

      在Retina視網膜屏幕面世之前很少有人關注像素密度,在windows系統下,提高屏幕分辨率一般都是通過提高屏幕尺寸。而隨著屏幕分辨率的提升,圖像和文字顯示目標會相應縮小,造成觀看不方便。因為系統不會自動根據屏幕尺寸和分辨率關系相應的調整文字和圖標大小。即手動調整也會因為微軟一直采用的點陣字體和大多數位圖在提高分辨率后,因為多余的像素點沒有填充渲染會出現拉伸,進而會產生鋸齒,這是系統不會自動適配的原因之一。這也給我們造成一種假象:顯示器尺寸越大,分辨率就會越大。

      所以蘋果的Retina視網膜屏幕讓很多人困惑不已,為什么那么小的屏幕會有那么大的分辨率。為什么那么大的分辨率,非但沒有使文字和圖像變小,反而更加清晰。

      1.10 高像素密度屏幕(高ppi)

      嚴格來說,高像素密度屏幕也是屬于高分辨率屏幕,不同的是高像素密度屏幕在提升了分辨率的同時也提高了像素密度,即相同的尺寸有著更大的分辨率。以蘋果的Retina視網膜屏幕為例,它并不是普通屏幕那樣通過增大尺寸來增加分辨率,而是靠提升單位面積屏幕的像素數量,即像密度來提升分辨率,這樣就有了高像素度屏幕。

      同時操作系統也會采取相應的模式,如Mac下的HiDPI進行適配,將縮小的字體(蘋果一直采用矢量字體)和圖標重新放大,這樣蘋果用了更多的像素來顯示同樣的內容,顯示尺寸仍然不變,但是多了更多細節,因此會有非常明顯的視覺效果提升。

      iPhone/iPod Touch

      普通屏幕分辨率 ====>  320px X 480px
      Retion分辨率   ====>  640px X 960px 

      iPad,iPad2/New iPad

      普通屏幕分辨率 ====>  768px X 1024px
      Retion分辨率   ====>  1536px X 2048px 

      換算關系

      普通屏幕分辨率 ====>  1點=1像素
      Retion分辨率   ====>  1點=2像素 

      1.11 Retina設備

      Retina是蘋果提出來的,根據蘋果的定義,PPI高于210(筆記本電腦) ,260(平板電腦),300(手機)的屏幕就成為Retina屏

      上圖是部分蘋果手機屏幕參數。

      1.12 HTML和CSS的標準

      盡管現在的顯示設備大部分還是非Retina屏,但是如何使用Retina來優化web顯示的方法如雨后春筍,越來越多的處理方案被提出。

      最直接的方式就是通過手動制圖或者編程的方式制作兩種不同的圖形,一張是普通屏幕的圖片,另一種是Retina的圖形,并且Retina屏幕下的圖片像素是普通屏幕下的兩倍。如有一張200X300像素的圖片(css像素),然后制作一張400X600像素的圖片,通過css或者html屬性將其屬性壓縮50%,這時在一個標準分辨率的顯示器上,其呈現的圖像是位圖的四分之一像素。簡單的說,普通屏幕下的圖像被壓縮,減少像素取樣(只是位圖含像素的四分之一),同時,這樣會造成資源浪費。把這個過程稱為“Downsampled”。

      在Retina屏幕下,相同的圖像會使用四倍的物理像素顯示,這樣一來,每個物理像素最終完全配備一位圖像素,使圖像得到完全的呈現。

       

      有幾種方法可以實現這樣的效果。

      1. HTML屬性

      最簡單的方式是通過img標簽,設置width,height屬性:

      <img src="example@2x.png" width="200" height="300" /> 

      注意,即使指定的圖片高度是可選的,但是在加載圖片前,瀏覽器已經預留了所需的空間。這樣可以防止頁面布局更改圖片時,再加載一次。

      2. 使用Javascript

      同樣的效果,可以通過Javascript腳本對圖像(為Retina屏幕準備的圖像)進行減半。

      $(window).load(function() {
        var images = $('img');
        images.each(function(i) {
          $(this).width($(this).width() / 2);
        });
      }); 

      3. 使用css

      另外一種方法是通過css來實現。常見方式就是給元素設置一個背景圖像,比如給div元素設置一個背景圖像,最關鍵的是給這個背景圖像設置background-size,來指定背景圖像的大小,也可以給元素設置一個大小,然后給background-size設置一個contain屬性值。不過IE7,IE8不支持這個屬性的運用。

      .image {
        background-image: url(example@2x.png);
        background-size: 200px 300px;
        /*或者設置background-size: contain; */
        height: 300px;
        width: 200px;
      } 

      還可以使用元素的偽元素來代替

      .image-container:before {
        background-image: url(example@2x.png);
        background-size: 200px 300px;
        content:'';
        display: block;
        height: 300px;
        width: 200px;
      } 

      HTML和CSS方法的

      優點是:
      很容易實現;
      能跨瀏覽器兼容;

      缺點是:
      非Retina屏下必須下載更大的圖片資源;
      Downsampled圖像在不同的分辨率下可能會失去一定的清晰度;
      background-size在IE9下瀏覽器下支撐不友好; 

      1.13 查詢圖像密度

      為Retina屏幕下查詢web圖像的像素密度,然后調用對應的圖像。目前常用的方式是通過css或者Javascript來實現。

      1. 使用CSS Media Queries

      通過divice-pixel-ratio屬性或者其擴展屬性min-device-pixel-ratio和max-device-pixel-ratio。這幾個Media Queries可以使用background-image為Retina準備高精度像素圖片。

      通過window.devicePixelRatio的比例1.5或2為不同的蘋果設備做相應的查詢。

      .icon {
        background-image: url(example.png);
        background-size: 200px 300px;
        height: 300px;
        width: 200px;
      }
      
      @media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
      only screen and (-moz-min-device-pixel-ratio: 1.5),
      only screen and (-o-min-device-pixel-ratio: 3/2),
      only screen and (min-device-pixel-ratio: 1.5) {
        .icon {
          background-image: url(example@2x.png);
        }
      } 

      iPhone4

      @media only screen and (-webkit-min-device-pixel-ratio : 1.5),only screen and (min-device-pixel-ratio : 1.5) {
          /* Styles */

      Retina屏幕和普通屏幕

      @media only screen and (min-width: 320px) {
      
        /* Small screen, non-retina */
      
      }
      
      @media
      only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 320px),
      only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 320px),
      only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 320px),
      only screen and (        min-device-pixel-ratio: 2)      and (min-width: 320px),
      only screen and (                min-resolution: 192dpi) and (min-width: 320px),
      only screen and (                min-resolution: 2dppx)  and (min-width: 320px) { 
      
        /* Small screen, retina, stuff to override above media query */
      
      }
      
      @media only screen and (min-width: 700px) {
      
        /* Medium screen, non-retina */
      
      }
      
      @media
      only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 700px),
      only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 700px),
      only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 700px),
      only screen and (        min-device-pixel-ratio: 2)      and (min-width: 700px),
      only screen and (                min-resolution: 192dpi) and (min-width: 700px),
      only screen and (                min-resolution: 2dppx)  and (min-width: 700px) { 
      
        /* Medium screen, retina, stuff to override above media query */
      
      }
      
      @media only screen and (min-width: 1300px) {
      
        /* Large screen, non-retina */
      
      }
      
      @media
      only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 1300px),
      only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 1300px),
      only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 1300px),
      only screen and (        min-device-pixel-ratio: 2)      and (min-width: 1300px),
      only screen and (                min-resolution: 192dpi) and (min-width: 1300px),
      only screen and (                min-resolution: 2dppx)  and (min-width: 1300px) { 
      
        /* Large screen, retina, stuff to override above media query */

      CSS Media Queries的優點:
      只有對應的目標元素才會下載圖片資源;
      跨瀏覽器兼容;
      像素可以精確控制;

      CSS Media Queries的缺點:
      單調無味的實現過程,代碼冗長;
      只能通過HTML元素的背景圖片來實現,無語義化

      2. 使用Javascript

      使用Javascript中的window.devicePixelRatio進行判斷,然后根據對應的值給Retina屏選擇圖像。

      $(document).ready(function(){
        if (window.devicePixelRatio > 1) {
          var lowresImages = $('img');
      
          images.each(function(i) {
            var lowres = $(this).attr('src');
            var highres = lowres.replace(".", "@2x.");
            $(this).attr('src', highres);
          });
        }
      }); 

      開源的Retina.js是為Retina而生,基本實現了上面所有功能。目前支持window.devicePixelRatio的瀏覽器不多,將來會有更多的瀏覽器添加這個api。

      Javascript查詢的優點:
      易于實施;
      非Retina屏幕不用下載額外的資源;
      像素精確控制;

      Javascript查詢的缺點:
      Retina屏幕下必須下載標準準備和高密度的兩個資源;
      Retina屏幕下圖像交互可見;
      瀏覽器兼容性不強;

      1.14 可縮放矢量圖形

      不管用什么方式,光柵圖像仍然有自己固定的圖像分辨率,也就是其縮放始終受限于其像素,也絕對無法限制伸縮。但是矢量圖就不一樣,可以隨意伸縮,而且無任何影響。在Retina屏幕下的web圖形,矢量圖具有先天優勢。

      目前,基于XML的svg格式制作的矢量圖得到大部分瀏覽器的支持,可以使用svg繪制各種圖形,并且在Retina屏幕下可以任意伸縮。開發過程中使用svg最簡單的方法是通過HTML的img標簽,CSS的background屬性或者微元素的content中的url()。

      HTML的img標簽加載svg

      <img src="example.svg" width="200" height="300" /> 

      在這里是一個svg凸顯更可以為普通屏幕和Retina屏幕的通用圖像,可以做任何伸縮,而不會像光柵位圖一樣失真,而且資源統一,節省帶寬,方便維護。

      CSS中使用svg圖像

      svg圖像可以像普通圖像一眼個,當作元素的背景圖片來使用:

      .image {
        background-image: url(example.svg);
        background-size: 200px 300px;
        height: 200px;
        width: 300px;
      } 

      除了當作背景圖片之外,還可以通過偽元素的“content”來調用:

      .image-container:before {
        content: url(example.svg);
      } 

      如果想在IE7,IE8和Android2.x上使用,要用png圖片來代替svg圖像 

      .image { 
          background-image: url(example.png); 
          background-size: 200px 300px; 
      }
      .svg { 
          .image { 
              background-image: url(example.svg); 
          } 
      } 

      在HTML標簽中,給img標簽定義一個屬性,給這個自定義屬性設置一個png圖片,以做備用,不過這種方式需要使用Javascript配合使用。

      $(document).ready(function(){
        if(!Modernizr.svg) {
          var images = $('img[data-png-fallback]');
          images.each(function(i) {
            $(this).attr('src', $(this).data('png-fallback'));
          });
        }
      });

      SVG矢量圖的優點:
      一個資源適合所有的設備
      易于維護
      面向未來,可伸縮向量圖形

      SVG矢量圖的缺點:
      沒有像素那樣有精度
      由于文件大小,不適合復雜的圖形
      不支持IE7-8和部分安卓版本

      最后開發人員如何讓網站適應Retina屏幕呢,看下面的總結:

       

       

       

       

      2. H5頁面適配的一些基本概念

      2.1 視窗viewport

      viewport的功能在于控制網站最頂層容器,即html元素。假設我們定義一個可變尺寸的布局,且定義了一個側邊欄的寬度為10%,當改變瀏覽器窗口大小時,改側邊欄會自動擴展個收縮。這是什么原理呢?側邊欄寬度是父元素寬度的10%,假設父元素是<body>,那么問題就變成了<body>的寬度到底是多少?通常一個塊元素占父元素100%的寬度,所以body元素的寬度就是其父元素<html>的寬度。

      那么<html>的寬度又是多少呢?它的寬度是瀏覽器的寬度。所以側邊欄寬度10%會占用10%的瀏覽器寬度。<html>的寬度受viewport所限制,<html>元素為viewport寬度的100%。

      反過來,viewport是嚴格的等于瀏覽器的窗口。viewport不是一個html概念,所以它不會被CSS屬性修改。它就是為瀏覽器窗口的寬度高度,在桌面瀏覽器上是如此,在移動端有些復雜。

      簡單的理解,viewport是嚴格等于瀏覽器窗口。在桌面瀏覽器中,viewport就是瀏覽器窗口的寬度高度。但是在移動端有些復雜,移動端viewport太窄,為了更好的偽css布局服務,所以提供了兩個viewport:虛擬的,visual viewport和布局的layout viewport

      設備的pixels和css的pixels

      相對css像素來說,設備像素的概念比較單一。我們的網頁在什么樣的設備上運行呢?設備像素給出了這個答案,可以從window.screnn.width/height(大多數情況下)讀到。

      設備的pixels和設備本身有關,簡單來說就是window.screen.width/window.screen.height,可以認為設備的pixels是正確,標準的寬和高,這些pixels決定了設備上正式的分辨率。

      假設設置頁面中一個元素的寬度是128px,顯示器的寬度是1024px,且沒有拖拉顯示器的右上角是的顯示器變小,那么可以在瀏覽器中放置8個這樣的元素(忽略掉margin,padding等這些概念)。

      如果用戶縮放(zoom)了瀏覽器,情況就改變了。如果瀏覽器放大到200%,結果是只能在瀏覽器中放置4個這樣的元素來占滿顯示器1024的寬度。

      現代瀏覽器都實的“縮放”(zoom)功能,除了可以“拉伸”像素之外沒有什么作用,結果是html元素的寬度沒有因為縮放200%而由128pix變成256px,而是實際的的pixels被計算成了雙倍。html元素在形式上依然是128css的pixels,但是它占用了256設備pixels。換言之,縮放200%將一個單位的css的pixels變成了4倍的設備的pixels那么大,即寬度*2,高度*2,面積*4。

      用一些圖片來說明這個概念,下面圖片中有4個正常縮放(100%縮放)的像素,縮放為100%的html元素,css的pixels完整和設備的pixels重疊。

      當我們縮小瀏覽器時,css的pixels開始收縮,導致1單位的設備pixels上重疊了多個css的pixels,如下:

      同理,放大瀏覽器的時候,相反的事情發生了,CSS的pixels開始放大,導致1單位的CSS的pixels上重疊了多個設備的pixels。

      問題在于,設備的pixels幾乎毫無用處,開發者只關注css的pixels,這些pixels指定了html元素如何渲染。但是對用戶來說是另外一回事,用戶會縮放界面,直至可以舒適的閱讀網頁內容,但是開發者不需要關注這些縮放級別,瀏覽器會自動的保證css的pixels會被伸展還是收縮。

      100%縮放

      在縮放級別是100%的時候,1單位的CSS的pixels是嚴格等于1單位的設備pixels。

      100%縮放的概念非常有利于表達下面的問題,在日常開發中不必過分擔憂這個問題。在桌面系統中,通常會在100%縮放級別下測試網站,即使用戶縮放,css的pixels的魔法依然可以保證網站外觀保持相同的比例,開發者不必過分擔心。

      屏幕尺寸 Screen size

      screen.width/height

      含義:用戶的屏幕的完整大小
      度量:設備的pixels
      兼容性:IE8里,不管使用IE8模式還是IE7模式,都是以CSS的pixels來度量

      這兩個屬性包含用戶屏幕的完整高度和寬度。這些尺寸使用設備的pixels來定義,他們的值不會因為縮放而改變,他們是顯示器特征,而不是瀏覽器。我們可以拿著個來做什么呢?除了獲取用戶屏幕信息之外用到的地方很少。

      瀏覽器尺寸window size

      window.innerWidth/window.innerHeight

      含義:包含滾動條尺寸的瀏覽器完整尺寸
      度量:CSS的pixels
      兼容性問題:IE不支持,Opera用設備pixels來度量

      瀏覽器內部尺寸,很明顯它定義了當前用戶有多大區域可供CSS布局使用。可以用window.innerWidth和window.innderHeight來獲取。窗口的內部寬度使用CSS的pixels,開發時需要知道自己定義的元素是否能塞入瀏覽器窗口,這兩個尺寸會隨著用戶放大(縮放)瀏覽器而減少。所以當用戶放大顯示時,能獲取的瀏覽器窗口可用空間會減少。window.innerWidth/window.innerHeight就是縮小的比例。

      (在Opera瀏覽器上有些異常,window.innerWidth/innerHeight不會隨著用戶放大(縮放)瀏覽器而減小,它以物理像素衡量。這在桌面端非常討厭,但是在移動端會帶來致命的結果,稍后討論)

      注意,窗口內部寬度和高度的尺寸,包含了滾動條的尺寸,這是歷史原因。

      滾動移位 Scrolling offset

      含義:頁面的移位
      度量:CSS的pixels
      兼容性問題:window.pageXOffset和window.pageYOffset,在IE8及之前的IE瀏覽器不支持。使用document.body.scroolLeft和document.body.scrollTop來取代

      window.pageXOffset和window.pageYOffset定義了頁面(document)相對于窗口原點的水平,垂直位移。因此可以定位用戶滾動了多少滾動條距離。注意因為頁面中的內容是可以無限添加的,頁面滾動的距離可能比頁面實際可見的高度要大得多。

      理論上,如果用戶滾動并放大(縮放)瀏覽器,window.pageXOffset/pageYOffset會改變,但是,現代瀏覽器會盡量保持在屏幕上方被卷入的元素有相同的尺寸。實際情況是,這不一定都會起作用,實際上,通常情況下,window.pageXOffeset/pageYOffset并不會改變。

      該屬性也以CSS的pixels來度量,同上面的問題,當用戶放大頁面時,瀏覽器會嘗試著保存用戶當前可見的頁面的元素依然在可見位置。雖然這個特性表現的不如預期,但是它意味著,理論情況下window.pageXOffset/window.pageYOffset并沒有改變,被用戶滾出屏幕的CSS的pixels幾乎保持不變。

       概念:視窗viewport

      viewport的功能在于控制網站的最高級別的塊容器,<html>元素。舉個例子,定義個一個可變尺寸的布局,且定義了一個側邊欄尺寸為10%,當改變瀏覽器窗口大小的時候,該側邊欄會自動擴張和收縮。側邊欄是父元素body寬度的10%,那么body的寬度又是多少呢?通常一個塊級元素占有父元素的100%的寬度,所以body的寬度就是其父元素html的寬度。那么html元素到底有多寬?因為它的寬度恰好是瀏覽器的寬度。所以側邊欄的寬度就是瀏覽器寬度的10%。通常是這么個道理,實際上html寬度受viewpoint所限制,html元素為view寬度的100%。

      viewpoint被定義成嚴格等于瀏覽器的窗口,它不是一個html的概念,不能通過css定義修改它。在PC端他的寬度和高度嚴格等于瀏覽器的高度,在移動端,情況有些復雜。

       結果

      viewport的定義會帶來一些奇怪的后果。縮小(拖動瀏覽器右上角)瀏覽器,按住Ctrl鍵,向上滾動鼠標滾輪2至3格,放大(縮放)瀏覽器,拖動滾動條到網頁頂部,會發現藍色的頁眉有些錯亂,沒有占滿整個瀏覽器。如下圖:

      這是由于viewport的局限帶來的后果。頂部藍色頁眉的寬度是這樣定義的width:100%; 它的寬度應該是html元素的100%,viewport的寬度又是真個瀏覽器寬度的100%。

      關鍵在于,在瀏覽器100%大小(縮放)情況下完全沒有問題,現在放大(縮放)了。viewport變得比網站寬度小(這時css像素比物理像素要小,瀏覽器的寬度已經變窄了(拖放),頁眉的寬度要比瀏覽器小),,overflow:visible;元素默認超出父元素時正常顯示。

      頁眉并沒有溢出,是因為頁眉的寬度css定義為width:100%,即為viewport寬度的100%,它沒有意識到因為這時viewport的寬度已經變窄了。

      document width

       網頁文檔的寬度,包含溢出的那部分是多少呢?現在沒有一個api能夠告訴我們,除非計算出每個元素的寬度,包含margin,padding,border等諸多因素,這是非常容易出錯的。

      如果能有一個javascript屬性能夠告訴我們這個document width就好了。如果有一個文檔寬度,就可以設置藍色頁眉的寬度為文檔寬度的100%。

       

      度量viewport

      含義:viewport的尺寸
      度量:css的pixels
      兼容性問題:無

       viewport的尺寸可以用document.documentElement.clientWidth/clientHeight來獲取。document.documentElement實際代表整個網頁的根元素:html元素。實際這對屬性描述的是viewport的尺寸,它描述的是viewport的尺寸,而不管html元素的尺寸如何改變。

      描述viewport的兩種方式

      上文中已經說了,window.innerWidth/innerHeight是viewport的寬度和高度嗎?嗯, 是, 也不是。嚴格說這兩對屬性有細微的差別。

      document.documentElement.clientWidth/clientHeight是viewport的不包含滾動條長度的寬度和高度
      window.innerWidht/innerHeight是viewport的包含滾動條長度的寬度和高度

      之所以會出現兩套屬性來描述viewport的寬度和高度是瀏覽器大戰留下的遺物。那個時候網景公司支持window.innerWidth/innerHeight,IE只支持document.documentElement.clientWidth/clientHeight,盡管其他瀏覽器都開始支持clientWidth/clientHeight,但是IE仍然沒有支持,僅僅支持innerHeight/innerWidth。

      桌面端有兩種方式獲取viewport的尺寸是一個困惑,但是在移動端確是一個福利。

      度量html元素

      document.documentElement.offsetWidth/offsetHeight用來表示html元素的尺寸,包含看不見的部分。

      含義:<html>的尺寸
      度量:css的pixels
      兼容性問題:IE用這個描述viewport的尺寸而不是<html>

      用這一對屬性可以獲取html元素的寬度和高度,可以通過設置html元素的css屬性來改變它。

      事件坐標

      含義:當發生鼠標事件的時候,至少會有5個屬性來暴露當前鼠標的位置信息,下面來看其中的個屬性
      度量:見下文
      兼容性問題:IE不支持pageX/pageY,IE使用screenX/screenY,css的pixels
      定義:1. pageX/pageY描述事件相對于html元素的坐標,css的pixels
                 2. clientY/clientY描述事件相對于viewport的坐標,css的piexles
                 3. screenX/screenY描述事件相對于屏幕的坐標,css的pixels

       

      通常我們會有90%的可能來使用pageX/pageY,即相對于html元素的尺寸,其余10%的可能會使用clientX/clientY,即相對于viewport的尺寸,screenX/screenY這對屬性通常沒有用。

      媒體查詢

      含義:見下文
      度量:見下文
      兼容性:IE不支持媒體查詢,在firefox中,使用screen.width/height,而不是divice-width/divice-height,使用css的pixels;對于width/height,Safari和chrome使用document.documentElement.clientWidth/clientHeight的值(如果他們是以設備像素為單位的話)

      媒體查詢的思路是很簡單的,定義在不同頁面尺寸下的css的規則,比如大于,小于,等于某一個尺寸,看下面的例子:

      div.sidebar {
          width: 300px;
      }
      
      @media all and (max-width: 400px) {
          // styles assigned when width is smaller than 400px;
          div.sidebar {
              width: 100px;
          }
      
      }

      當前sidebar是300px,當寬度小于400px的時候變成100px。

      問題是以哪個寬度為依據的呢?有兩類媒體查詢,widht/height,divice-width/divice-height。

      1. width/height使用的是document.documentElement.clientWidth(viewport,不帶滾動條),使用css的pixels
      2. divice-width/divice-height使用的是screen.width/screen.height(顯示器的寬度和高度),使用物理像素

      毫無疑問,我們要使用with/height,顯示器寬度和高度對開發者來說意義不大,瀏覽器開發商才會關心這個。在移動端,情況會稍微簡單點,接下來討論這些問題。

      移動端瀏覽器的問題

      和pc端相比,移動端最大的不同是屏幕尺寸。移動端尺寸要小,顯示的內容也要比pc端少,要么縮小導致網頁內容難以辨認,要么只顯示網頁中的一小部分。

      移動端屏幕要比pc端小很多,通常最大也就400px,當前雖然有些制造商聲稱他們的屏幕很大,但是他們往往夸大其詞。一些折中的方案,比如ipad或者其他的平板電腦介于手機和pc之間,但是這些也沒有根本解決問題。移動端大潮不可避免,網頁必須能在移動端工作,所以想方設法是得網頁在移動端一樣表現良好。

      大多數問題集中在css上,特別是viewport的度量上。如果我們簡單地把pc端網頁拷貝到移動端,樣式將變得奇丑無比。

      這里我們繼續用sidebar的寬度10%這個問題來討論。如果移動端行為和pc端一樣,那么這個sidebar最多也只有40px,這個尺寸就太小了。一種解決方式是為移動端再做一個網站。暫且不說這個網站要怎么做,通常只有少部分公司才會投入成本來做這件事,為移動端單獨做一個網站。移動瀏覽器廠商則希望他們的軟件提供更好的體驗,“盡量像pc端一樣的體驗”,所以他們就會無所不盡其能。

      兩種viewports

      移動端的viewport對于css布局來說非常小,一種解決方案是把viewport變得大一點。這種需求就把viewport分成兩種:虛擬viewport,布局viewport。

      George Cummins(喬治.康明斯,不知道是誰,應該是前端大牛把)對著兩種viewport給出了這樣的解釋:

      可以把布局viewport想象成一個不能改變大小和形狀的圖片。現在用一個小一點的框來觀察這個大圖片。這個小框有被不透明的材料包裹,因此通過這個框只能觀察到這個圖片的一部分。通過這個框能夠觀察到的部分圖片就是虛擬viewport,如果我們后移這個框,站遠一點,就能看到整張圖片了,相當于放大(縮放)了這個框。你也可以改變這個框(可視viewport)的方向,但是后面的圖片(布局viewport)是不會改變的。

      虛擬viewport是我們當前能夠在移動端顯示器上看到的部分。用戶可能會滾動來改變可見部分,放大,縮小,都可以修改這個可視viewport。

      但是,css布局中,尤其是百分比寬度,是按照布局layout來計算的,這樣一來就要比按照可視viewport計算要寬得多了。

      所以,默認情況下,html元素繼承了布局viewport的寬度,css布局或按照這個寬度來計算,這使得網站在移動端盡量貼近pc端樣式。

      布局viewport有多寬呢?根據瀏覽器不同而不同,Safari iPhone是980px,Opera是850px,AndroidWebkit是800px,IE是974px。部分瀏覽器行不同:

      • Symbian Webkit的布局viewport和可是viewport是一致的,這意味著按照百分比來定義的元素的尺寸會很小,很難看。如果頁面中有個別元素有特定的尺寸而不適合虛擬viewport,那么寬度的最大值將會被設置成850px
      • Sumsung Webkit中的布局layout以網頁中最寬的元素為準
      • 黑莓的布局viewport在縮放比例為100%的時候和虛擬viewport一樣。

      縮放

      兩種布局都是以css的pixels來度量的,但是當縮放比例變化的時候可視viewport也會改變(縮放比例變大的時候,一個css的pixels會占據多個物理的pixels,可視范圍內css的pixels變少),布局viewport的度量保持不變。這是頁面會重繪,元素的百分比尺寸會被重新計算。

      理解布局viewport

      為了理解布局layout的尺寸,我們先看看當王爺縮小到時候回有什么情況發生。許多移動端瀏覽器默認以最小縮放比例打開王爺,這樣可以看到王爺所有內容。關鍵點在于,瀏覽器選擇最小縮放比例模式,以便屏幕能夠顯示所有的網頁。

      因此,布局視圖的寬度和高度和最小縮放模式下在屏幕中能夠顯示的內容的寬和高。當用戶放大(縮放)的時候,保持不變。

      布局視圖不變,但是在旋轉(橫放)模式下可視viewport改變,瀏覽器通過稍微放大以適應這一新方向,這樣布局viewport再次與可視viewport再次保持一致。

      這對布局viewport有一些影響,現在的高度比縱向模式要小得多。但是開發人員不會關心屏幕高度,只關心寬度。

      度量視圖viewport

      document.documentElement.clientWidth/clientHeight
      含義:布局viewport的尺寸
      度量:css的pixels
      完整支持:Opera,iPhone,Android,Symbian,Bolt,MicroB,Skyfire,Obigo
      問題:

      • 在Iris上它標示可視視圖;
      • 三星的webkit核心瀏覽器,僅當在頁面上寫入<meta viewport>標簽,才能正確標示。否則就代表html元素的尺寸;
      • Firefox中用設備的pixels來衡量;IE瀏覽器中返回的值是1024*768,正確的獲取方式是document.body.clientWidth/clientHeight;
      • NetFront僅當100%縮放的時候才正確;
      • 塞班班的weibkit1不支持這些屬性;
      • 黑莓不支持

       很幸運,雖然有兩種viewport,瀏覽器大戰留下了兩對屬性來衡量他們。document.documentElement.clientWidth/clientHeight代表可視viewport的度量

      旋轉模式下只影響到高度,不影響寬度。

      度量可視viewport

      window.innerWidth/innerHeight

      含義:可視viewport的度量
      度量:css的pixels
      完整支持:iPhone,Symbian,BlackBerry
      問題:

      • FireFox和Opera返回的是物理的pixels;
      • Android,Bolt,MicroB,NetFront返回的是可視viewport的css的pixels度量;
      • IE不支持這個屬性,但是IE給出了document.documentElement.offsetWidth/offsetHeight來代替;
      • 三星的Webkit瀏覽器,僅當在頁面上寫入<meta viewport>標簽,才能正確標示。否則代表<html>元素的尺寸;
      • 在Iris,Skyfire,Objgo上很混亂;

       可視viewport使用window.innerWidth/innderHeight來衡量。顯然,隨著用戶縮放瀏覽器,這個值會改變,屏幕上的css的pixels會改變。

      不幸的是,這對屬性兼容性很差,很多瀏覽器沒有支持,但愿將來有更多瀏覽器實現它,使它成為一個標準。

      屏幕尺寸度量

      screen.width/height

      含義:屏幕的尺寸;
      度量:物理的pixels;
      完全支持:Opera,Android,Symbian,Iris,Firefox,MicroB,IE,BlackBerry;
      問題:

      • Opera在Window Mobile下只給出了橫向尺寸,在S60還是錯誤的;
      • 三星的Webkit核心瀏覽器,僅當在頁面上寫入<meta viewport>標簽,才能正確表示,否則代表html元素的尺寸;
      • iPhone和Obigo僅給出縱向尺寸;
      • Android,Bolt,MicroB,NetFront以CSS的pixels返回該數值,且為布局的viewport的值;
      • Bolt,Skyfire下很混亂;

      pc端中screen.width/height給出的是屏幕尺寸,用物理pixels衡量,作為web開發者,這個不常用。同樣在移動端,你不用屏幕上有多少物理pixels,只關心有多少css的pixels。

      縮放等級zool level

      無法直接獲取縮放等級,但是可以通過計算獲取:screen/width/window.innerWidth,當然只有在這兩個屬性都被支持的情況下才能這樣獲取。幸運的是,縮放等級并不重要,只需要知道當前有多少css的pixels能供使用就可以了。在瀏覽器支持的情況下,使用window.innerWidth獲取這一信息。

      滾動scrolling offset

      window.pageXOffset/pageYOffset

      含義:見下文;
      度量:css的pixels;
      完整支持:iPhone,Android,Symbian,Iris,MicroB,Skyfire,Obigo;
      問題:

      • Operia,Bolt,Firefox,NetFront總是返回0;
      • 三星的webkit核心瀏覽器,僅當在頁面上寫入<meta viewport>標簽才起能獲取;
      • IE,BlackBerry不支持,在IE中使用document.documentElement.scrollLeft/scrollTop來獲取;

      通常還要知道當前可視viewport相對于布局viewport的位置,這就是滾動,和pc端一樣,可以通過window.pageXOffset/pageYOffset獲取。

       

      <html>元素的度量

      document.documentElement.offsetWidth/offsetHeight

      含義:真個html元素的尺寸
      度量:css的pixels
      完整支持:Opera, iPhone, Android, Symbian, Samsung, Iris, Bolt, Firefox, MicroB, Skyfire, BlackBerry, Obigo
      問題:只有在100%縮放下NetFront瀏覽器返回的值才是正確的;IE使用這個屬性來輸出可視viewport,html元素尺寸使用document.body.clientWidth/clientHeight來輸出;

      和桌面端一樣,移動端也使用document.documentElement.offsetWidth/offsetHeight來表示html元素的尺寸,用css的pixels度量。

      媒體查詢

      含義:已css的pixels度量html元素或者已設備的pixels來度量設備;
      完整支持:Opera, iPhone, Android, Symbian, Samsung, Iris, Bolt, Firefox, MicroB;
      不支持:Skyfire, IE, BlackBerry, NetFront, Obigo;
      注意:這里測試了瀏覽器是否明確地出了這些值,這些值的準確性沒有測試;

      移動端媒體查詢和桌面端類似,width/height使用以css的pixels度量的布局viewport,divice-width/divice-height使用物理pixels來度量。換句話說width/height就是document.clientWidth/clientHeight,divice-width/divice-height就是screen.width/height(所有瀏覽器都是這樣,即使屬性的值是錯誤的)

      開始我認為divice-width/divice-height比較重要,因為它給出了我們所使用設備的屏幕的尺寸信息。例如,可以根據設備尺寸來設置不同的網頁尺寸。但是同樣可以定義<meta viewport>來達到這個目的。所以divice-width/divice-height不是不可替代的。

      瀏覽器廠商自認為他們通過width/height給出了一些對網站有用的尺寸細節,但是這些內容含糊,混亂。所以媒體查詢在區分當前設備是移動設備(手機,pad,pda)還是pc誰被時很有用,但是在區分是當前手機(或pad,pda)的尺寸上用處沒有那么大。

      事件坐標event coordinates

      含義:見下文
      度量:見下文
      完整支持:Symbian,Iris
      問題:
      Opera移動端給出了pageX/pageY,但是當屏幕滾動查出范圍時,這個值是錯誤的;
      在iPhone,firefox,blackberry上,clientX/clientY和pageX/pageY相等的;
      在Android和MicroB上screenX/screenY和clientX/clientY是相同的,css的pixels度量;
      在Firefox上screenX/screenY是錯誤的;
      IE,blackberry,Obigo不支持pageX/pageY;
      在NetFront上三種尺寸的值都用screenX/screenY;
      在Obigo上clientX/clientY是用screenX/screenY來表示;
      在三星webkit瀏覽器上總是返回pageX/pageY;

      時間坐標在pc端上大致是支持的,不幸的是移動端上只有symbian,Irias完全支持,其他的移動端瀏覽器或多或少都有些問題。

      pageX/pageY依然是基于css的pixels度量,和pc端瀏覽器刪狗一樣,它是三個特性里面最有用的。

      clientX/clientY是聚義可視viewport的,以css的pixels為度量的,這樣比較可靠。screenX/screenY基于屏幕的物理的pixels為度量的。同樣,它也是沒有什么用的。

      meta viewport標簽

      含義:設置可視viewport的寬度
      度量:css的pixels
      完整支持:Opera Mobile, iPhone, Android, Iris, IE, BlackBerry, Obigo
      不支持:Opera Mini, Symbian, Bolt, Firefox, MicroB, NetFront
      問題:

      • Skyfire不支持;
      • 三星瀏覽器,如果在頁面中設置<meta viewport>標簽,會有其他的屬性受到影響;
      • opera,iPhone,三星,blackberry不允許用戶縮放;

      最后,我們討論<meta name="viewport" content="width=320">這個標簽。起初,它是apple的一個擴展,后來很多瀏覽器都實現了這個擴展。它意圖重置可視viewport,下面我們來討論為什么會出現這個擴展。

      假設我們有一個簡單的網頁,所有元素都沒有設置css寬度。現在設置縮放比例為100%,大多數瀏覽器會在屏幕上顯示所有布局viewport,如下:

      當我們放大(縮放)瀏覽器的時候,大多數瀏覽器都保存元素完整的寬度(保持元素位置不變)導致閱讀困難(文字超過屏幕)。

      (Android瀏覽器有些特殊,它會減小包含文字的元素的尺寸,保證他們仍然完全顯示在瀏覽器上,我覺得這個特性很酷,其他瀏覽器應該學習)

      現在設置html元素的樣式{ width: 320px },現在html元素收縮,其他元素通過100%繼承320px。在用戶放大(縮放)的情況下正常,但是在最初期狀態下縮小(縮放)的時候頁面幾乎沒有什么內容,體驗很糟糕。

      為了解決這個問題,apple發明了meta視圖標簽,當設置標簽<meta name="viewport" content="width=320">,可以將布局viewport設置為320px,現在初始狀態下頁面的顯示就變得正常了。

      通過這個標簽可以將布局viewport的寬度設置為你需要的任意尺寸,甚至是divice-width。通過參考screen.width(物理的pixels)可以設置布局viewport尺寸。

      可以使用鉤子,有時候嚴格的screen.width一點意義都沒有,因為pixels的值太大。例如Nexus One上的嚴格寬度是480px,但是google的工程師覺得在用戶誰知device-width的時候,設置為480太大了,他們將這個值減小為原來的2/3,為320px,和iPhone上一致。

      3. 使用Flexible實現H5適配

      3.1 痛點

      雖然h5的頁面比pc端簡單不少,但是要想匹配所有的設備是一件非常痛苦的事情,因為移動端設備太多了。

      3.2 flexible適配方案 

      為了適應這么多的移動端誰被,設計師和前端開發之前應該采用什么樣的協作模式呢?手淘團隊曾經的協作思路是:

      1. 選擇一種尺寸作為設計和開發的基準
      2. 定義一套適配規則,自動適配剩下的尺寸
      3. 特殊適配效果單獨處理

      看下圖:

      手淘設計師通常會選擇iPhone6作為基準設計尺寸,交付給前端開發的設計尺寸是按照750px/1334px為準,當然高度會隨內容增多和改變。前端開發通過一套適配規則自動適配到其他的尺寸。經過多年的摸索實踐,總結了一套移動端適配方案—flexible方案。

      3.3 使用方法

      lib-flexible庫的使用方法非常簡單,只需要在web頁面的<head></head>之間添加對應的flexible_css.js,flexible.js文件,可以直接下載文件,然后放在項目目錄中:

      <script src="build/flexible_css.debug.js"></script>
      <script src="build/flexible.debug.js"></script> 

      可以使用CND

      <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script> 

      強烈建議對js做內聯處理,在所有資源加載之前執行這個js。執行之后會在<html>元素上增加一個data-dpr屬性,以及一個font-size樣式。JS會根據不同的設備添加不同的data-dpr值,比如2或者3,同時給html加上對應的font-size的值,比如說75px。

      如此一來,頁面的元素都可以通過rem單位來設置,他們會根據html的font-size值做相應的計算,從而實現屏幕的適配效果。

      除此之外,在引入lib-flexible需要執行的js之前,可以手動設置mea來控制dpr的值。例如:

      <meta name="flexible" content="initial-dpr=2" /> 

      其中initial-dpr強制設置為給定的值。如果手動設置了dpr之后,不過設備的dpr是多少,都會強制認為其dpr是我們設置的這個值。在此不建議手動強制設置dpr,因為在flexible中只對ios設備進行dpr的判斷,android系列的,始終認為dpr=1

      if (!dpr && !scale) {
          var isAndroid = win.navigator.appVersion.match(/android/gi); 
          var isIPhone = win.navigator.appVersion.match(/iphone/gi); 
          var devicePixelRatio = win.devicePixelRatio; 
          if (isIPhone) { 
          // iOS下,對于2和3的屏,用2倍的方案,其余的用1倍方案 
          if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { 
              dpr = 3; 
          } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
              dpr = 2; 
          } else { 
              dpr = 1; 
          } 
          } else { 
              // 其他設備下,仍舊使用1倍的方案 
              dpr = 1; 
          } 
          scale = 1 / dpr; 
      } 

      3.4 flexible的實質

      flexible實質是通過js來動態改寫meta標簽,代碼類似這樣:

      var metaEl = doc.createElement('meta');
      var scale = isRetina ? 0.5:1;
      metaEl.setAttribute('name', 'viewport');
      metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
      if (docEl.firstElementChild) {
          document.documentElement.firstElementChild.appendChild(metaEl);
      } else {
          var wrap = doc.createElement('div');
          wrap.appendChild(metaEl);
          documen.write(wrap.innerHTML);
      } 

      事實上它做了這樣幾件事情:

      1. 動態改寫<meta>標簽
      2. 給<html>元素添加data-dpr屬性,并動態改寫data-dpr的值
      3. 給<html>元素添加font-size屬性,并且動態改寫font-size的值

      3.5 px轉化成rem

      接下來就需要把視覺稿中的px轉換成rem。首先,目前日常工作中,視覺設計給到前端開發人員的視覺稿尺寸一般都是640px,750px,以及1125px寬度為準(考慮Retina屏),如何轉換成rem呢?

      這里拿一個推廣頁做例子,視覺稿的寬度是750px,下面看看如何將其中的個元素px轉換成rem。

      手淘的視覺設計師把相關的信息在視覺稿上標注出來。flexible會將視覺稿分成100等份(為了更好兼容vh,vw),每一份被稱為一個單位a,同時1rem單位被認定為10a。針對這樣的視覺稿可以算出:

      1a = 7.5px
      1rem = 75px 

      這個例子的稿子就分成了10a,也就是整個寬度為10rem,<html> 對應的font-size為75px。這樣視覺稿上的元素,只需要原始的px值除以rem基準即可。例如,此比例視覺稿中的圖片,尺寸是176px/176px,轉換為2.346667rem/2.346667rem

      3.6 如何快速計算

      實際生產中,每次都要計算px轉rem,會非常麻煩。阿里開源了一些插件來解決,例如cssrem是一個css轉rem的Sublime Text3的插件。

      css處理器

      除了使用編輯器插件,還可以使用css處理器來幫助我們處理,比如sass,less,postcss這樣的處理器。

      sass

      熟悉sass的開發人員,可以使用sass的函數,混合宏來實現這個功能。

      sass函數大致如下:

      @function px2em($px, $base-font-size: 16px) {
          @if (unitless($px)) { 
              @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you"; 
              @return px2em($px + 0px); 
          // That may fail. 
          } @else if (unit($px) == em) { 
              @return $px;
          } 
          @return ($px / $base-font-size) * 1em; 
      } 

      Sass的混合宏代碼如下:

      @mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
          //Conver the baseline into rems 
          $baseline-rem: $baseline-px / 1rem * 1; 
          //Print the first line in pixel values 
          @if $support-for-ie { 
              #{$property}: $px-values; 
          } 
          //if there is only one (numeric) value, return the property/value line for it. 
          @if type-of($px-values) == "number" { 
              #{$property}: $px-values / $baseline-rem; 
          } @else {
              //Create an empty list that we can dump values into $rem-values:(); 
              @each $value in $px-values{ 
              // If the value is zero or not a number, return it 
              @if $value == 0 or type-of($value) != "number" {
                  $rem-values: append($rem-values, $value / $baseline-rem); 
                  } 
              } 
              // Return the property and its list of converted values 
              #{$property}: $rem-values; 
          } 
      } 

      PostCss

      除了Sass這樣的CSS處理器之外,還可以使用px2rem工具,使用gulp任務來處理:

      var gulp = require('gulp');
      var postcss = require('gulp-postcss');
      var px2rem = require('postcss-px2rem');
      gulp.task('default', function() {
          var processors = [px2rem({remUnit: 75})];
          return gulp.src('./src/*.css')
              .pipe(postcss(processors))
              .pipe(gulp.dest('./dest'));
      }); 

      3.7 字號不用rem

      上面介紹使用rem來完成h5適配,文本又要怎么處理呢?是不是也通過rem來處理呢?顯然,我們在iPhone3G和iPhone4的retina屏下,希望看到的文本字號是相同的,也就是說,我們不希望文本在Retina屏幕下變小,另外,大屏幕手機上希望看到更多的文本。現在絕大多數的字體文件都自帶一些點陣尺寸,通常是16px和24px,所以我們不希望出現13px和15px這樣奇葩的尺寸。

      如此一來,就決定了在制作h5頁面中,rem不適合用到段落文本上。在flexible整個適配方案中個,考慮文本還是使用px作為單位。只不過使用[data-dpr]屬性來區分不同的dpr下的大小:

      div { 
          width: 1rem; 
          height: 0.4rem; 
          font-size: 12px; 
      // 默認寫上dpr為1的fontSize 
      } 
      [data-dpr="2"] div { 
          font-size: 24px; 
      } 
      [data-dpr="3"] div { 
          font-size: 36px; 
      } 

      為了更好的利于開發,實際開發中定制一個font-dpr()這樣的sass混合宏:

      @mixin font-dpr($font-size){
          font-size: $font-size; 
          [data-dpr="2"] & { 
              font-size: $font-size * 2; 
          } 
          [data-dpr="3"] & { 
              font-size: $font-size * 3; 
          } 
      } 

      有了這樣的混合宏之后,在開發中可以直接這樣使用:

      @include font-dpr(16px);

       這只是針對描述性的文本,比如段落文本,有時候文本字號也是要分場景的,比如項目中有個slogan,產品希望這個slogan能根據不同終端適配。針對這樣的場景,完全可以使用rem給這個slogan做計量單位。

      H5適配方案有很多,flexible只是其中一種。

      4. 使用vm,vh實現移動端布局

      4.1 Flexible回顧

      flexible解決了針對H5頁面布局的適配問題,這是一套成熟的方案。為了適配不同的終端,通過Hack手段根據設備的dpr設置viewport的值:

      <!-- dpr = 1--> 
      <meta name="viewport" content="initial-scale=scale,maximum-scale=scale,minimum-scale=scale,user-scalable=no">
      <!-- dpr = 2--> 
      <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no"> 
      <!-- dpr = 3--> 
      <meta name="viewport" content="initial-scale=0.3333333333,maximum-scale=0.3333333333,minimum-scale=0.3333333333,user-scalable=no">

       

      從而讓頁面達到縮放的效果,同時也實現了頁面的適配功能,主要思想有三點:

      1. 根據dpr的值來修改viewport實現1px的線
      2. 根據dpr的值來修改html的font-size,從而使用rem實現等比縮放
      3.使用Hack手段用rem模擬vw特性

      4.2 適配方案

      隨著前端技術不斷變化,flexible不再是最佳方案。移動端布局有兩個最重要的問題:

      1.各終端下的適配問題
      2.Retina屏的細節處理問題

      不同終端,面對的屏幕分辨率,DPR,1px,2px圖等一些列的問題。這個布局方案也是針對性的解決這些問題,只不過不再使用Hack手段來處理,而是直接使用原生的CSS技術來處理。

      4.3 適配終端

      首先要解決的是適配終端,flexible方案是通過javascript來模擬vm的特性,到今天為止,vw已經得到眾多瀏覽器的支持,也就是說,可以直接考慮將vw用到我們的適配布局中。

      眾所周知,vw是基于Viewport視窗的長度單位,這里視窗(Viewport)指瀏覽器可視化區域,而這個可視化區域是window.innerWidth/window.innerHeight的大小,如下圖:

       

       

      CSS Values and Units Module Level 3這篇文章中介紹了和Viewport相關的4個單位,分別是vw,vh,vmin,vmax:

      vw:是Viewport's width的簡寫,1vw代表window.innerWidth的1%
      vh:和vw類似,是Viewport's height的簡寫,1vh代表window.innerHeight的1%
      vmin:是當前vw和vh中的較小的值
      vmax:是當前vw和vh中的較大的值

      vmin和vmax是根據Viewport中長度偏大的那個唯獨值來計算出來的,如果window.innerHeight>window.innerWidth則vmin取window.innerWidth的百分之一,vmax取window.innerHeight的百分之一。如下圖:

       

      所以在這個方案中,大膽使用vw來替換之前flexible中rem縮放方案。先來回歸到實際業務中,目前出現的視覺設計稿,大部分是使用750px寬度的,從上面的定義中可以看出100vw = 750px,即1vw=75px,可以根據設計圖上的px值直接轉換成對應的vw。看到這里也需要問,每次都要計算,很麻煩,能不能簡單一點呢?其實我們可以使用PostCSS插件postcss-px-to-viewport,讓我們可以在代碼中直接使用px,如下:

      [w-369]{
          width: 369px;
      }
       
      [w-369] h2 span {
          background: #FF5000;
          color: #fff;
          display: inline-block;
          border-radius: 4px;
          font-size: 20px;
          text-shadow: 0 2px 2px #FF5000;
          padding: 2px 5px;
          margin-right: 5px;
      } 

      經過PostCSS編譯之后就是我們所需要的vw代碼:

      [w-369] {
          width: 49.2vw;
      }
      [w-369] h2 span {
          background: #ff5000;
          color: #fff;
          display: inline-block;
          border-radius: .53333vw;
          text-shadow: 0 0.26667vw 0.26667vw #ff5000;
          padding: .26667vw .66667vw;
      }
      [w-369] h2 span,
      [w-369] i {
          font-size: 2.66667vw;
          margin-right: .66667vw;
      } 

      實際使用的時候,可以對插件進行相關的參數配置,如下:

      "postcss-px-to-viewport": {
          viewportWidth: 750,
          viewportHeight: 1334,
          unitPrecision: 5,
          viewportUnit: 'vw',
          selectorBlackList: [],
          minPixelValue: 1,
          mediaQuery: false
      

      假設你的設計稿不是750px而是1125px,那么就可以修改viewportWidth的值為1125px。更多的介紹可以參考使用文檔

      4.4 使用場合

      上面解決了px到vw的轉換計算,那么在那些地方可以使用vm來適配我們的頁面呢,根據相關的測試:

      1. 容器適配,可以使用vw
      2. 文本適配,可以使用vw
      3. 大于1px的邊框,圓角,陰影都可以使用vw
      4. 內邊距和外邊距可以使用vw

      長寬比

      另外還有一個細節需要提出,例如我們有一個這樣的設計: 

      如果直接使用:

      [w-188-246] {
          width: 188px;
      }
      [w-187-246]{
          width: 187px
      

      最終效果會造成[w-187-246]容器的高度小于[w-188-246]。這個時候就要考慮到容器的長寬比縮放。這方面的方案很多,但我們還是推薦使用工具來處理。這里推薦一個PostCSS插件。這個插件的使用很簡單,不需要做任何配置,只需要本地安裝一下就好了,使用如下:

      [aspectratio] {
          position: relative;
      }
      [aspectratio]::before {
          content: '';
          display: block;
          width: 1px;
          margin-left: -1px;
          height: 0;
      }
       
      [aspectratio-content] {
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          width: 100%;
          height: 100%;
      }
      [aspectratio][aspect-ratio="188/246"]{
          aspect-ratio: '188:246';
      }

      翻譯出來:

      [aspectratio][aspect-ratio="188/246"]:before {
          padding-top: 130.85106382978725%

      這樣就可以實現長寬比的效果。

      目前采用PostCSS插件只是一個過渡階段,在將來可以直接在CSS中使用aspect-ratio屬性來實現長寬比。

      解決1px方案

      前面提到過,對于1px不建議直接轉換成vw單位,在Retina下,我們時鐘需要面對如何解決1px的問題。這里推薦使用一種解決1px的方案,依舊是使用PossCSS插件postcss-write-svg

      使用postcss-write-svg可以通過border-img或者background-image兩種方式來處理,比如:

      @svg 1px-border {
          height: 2px;
          @rect {
              fill: var(--color, black);
              width: 100%;
              height: 50%;
          }
      }
      .example {
          border: 1px solid transparent;
          border-image: svg(1px-border param(--color #00b1ff)) 2 2 stretch;
      } 

      這樣PostCSS自動幫你翻譯過來:

      .example {
          border: 1px solid transparent;
          border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch;
      } 

      使用PostCSS插件比我們修改圖片要來得簡單與方便。

      上面延時的是使用border-image方式,除此之外,還可以使用background-image來實現。如下:

      @svg square {
          @rect {
              fill: var(--color, black);
              width: 100%;
              height: 100%;
          }
      } 
      #example {
          background: white svg(square param(--color #00b1ff));
      } 

      編譯出來就是:

      #example {
          background: white url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2300b1ff' width='100%25' height='100%25'/%3E%3C/svg%3E");
      } 

      這個方案簡單易用,是我們所需要的,也基本能達到所有需求,但是一定要記得在<head>標簽中添加下面這一句:

      <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" /> 

      3.5  總結一下

      這個適配方案中所用到的技術點,簡單總結一下:

      使用vw來實現頁面的適配,并且通過PostCSS的插件postcss-px-to-viewport把px轉換成vw,這樣我們在寫代碼不需要做任何的計算,只需要按照原型設計稿中的尺寸來寫代碼,但是要配置一下設計稿的尺寸。

      為了更好的實現長寬比,特別是針對img,vedio和iframe元素,通過postcss-aspect-ratio-mini來實現,在實際使用中,只需要吧對應的寬和高寫進去即可。

      為了解決1px問題,使用PostCSS插件postcss-write-svg自動生成border-image或者background-img的圖片。

      這里使用了多個PostCSS插件,其實很多優秀的PostCSS插件能幫助我們解決很多問題,可以在這里關于PostCSS相關的文章查閱相關的文章。如果要系統的學些PostCSS,可以購買《深入PostCSS Web設計》這本書。

      3.6 降級處理

      本節最開始提到,目前為止T30的機型中還有幾款機型不支持vw的適配方案。如果業務需要,應該怎么處理呢?有兩種方式可以進行降級處理:

      CSS Houdini:通過CSS Houdini針對vw做處理,調用CSS Typed OM Level1提供的CSSUnitValue API.
      CSS Polyfill:通過對應的Polyfill做相應的處理,目前針對vw單位的Polyfill主要有:vminpolyViewport Units Buggyfillvunits.jsModernizr,推薦使用Viewport Units Buggyfill

      3.7 Viewport不足之處

      采用vw做適配并不是沒有任何缺陷,有一些細節還是存在不足之處的。比如容器使用vw單位,margin采用px單位,很容易造成整體寬度超過100vw,從而印象布局效果。對于這種情況我們可以使用相關的技術進行避免。比如將margin換成padding,并且配合box-sizing。只不過這不是最佳方案,隨著瀏覽器或者應用自身的Viewport對calc()函數支持以后,碰到vw和px混合使用的時候,可以結合calc()函數一起使用,這樣可以完美解決。

      另外,px轉換成vw單位,多少還是存在一些像素差,畢竟很多時候不能完全整除。

      3.8 如何判斷自己的應用是否支持

      雖然很多瀏覽器都支持vw,在使用的時候還是會擔心自己的app應用是否支持vw,可以打開下面的頁面查看

       

       頁面測試完成后,找到對應的Valus and units列表項:

       

      如果vw欄是綠色的代表你的設備支持,反之不支持。另外你可以經常關注css3test相關的更新,后面會根據相關的規范更新測試代碼,讓你快速掌握那些屬性可以大膽使用。

       

       

      參考:

      https://www.w3cplus.com/css/towards-retina-web.html
      https://www.w3cplus.com/css/viewports.html
      https://www.quirksmode.org/mobile/viewports.html
      https://www.zhangxinxu.com/wordpress/2012/10/new-pad-retina-devicepixelratio-css-page/

      posted @ 2019-09-10 21:09  nd  閱讀(6984)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩黄色av一区二区三区| 亚洲激情国产一区二区三区| 亚洲精品国产av一区二区| 少妇裸交aa大片| 一本色道久久加勒比综合 | 26uuu另类亚洲欧美日本| 国产成人精彩在线视频| 成年在线观看免费人视频| 亚洲无av在线中文字幕| yy111111在线尤物| 国产精品视频第一第二区| 欧美va天堂在线电影| 日韩av一区二区三区在线| 亚洲国产精品日韩在线| 国产成人av电影在线观看第一页| 国产又黄又爽又不遮挡视频| 欧美一区二区三区欧美日韩亚洲 | 亚洲国产精品一二三区| 光棍天堂在线手机播放免费| 中文字幕理伦午夜福利片| 一区二区三区岛国av毛片| 亚洲春色在线视频| 欧美成人www免费全部网站| 国内女人喷潮完整视频| 亚亚洲视频一区二区三区| 一卡2卡三卡4卡免费网站| 99精品人妻少妇一区二区| 东京热tokyo综合久久精品| 国产乱人伦av在线无码| 久久精品国产99麻豆蜜月| 男女性高爱潮免费网站| XXXXXHD亚洲日本HD| 国产精品第一二三区久久| 国产专区一va亚洲v天堂| 国产乱码精品一区二三区| 国产精品美女久久久久久麻豆| 97人人添人人澡人人澡人人澡| 国产精品制服丝袜无码| 亚洲国产韩国欧美在线| 国产一区二区三区色噜噜| 黄平县|