移動端Web前端註解

一,佈局

移動端的總體佈局通常來講能夠分爲上中下三個部分,分別爲 header、main、footer,其中header、footer 是固定高度,分別固定在頁面頂部和頁面底部,而 main 是佔據頁面其他位置,而且能夠滾動。html

頁面佈局以下:web

<body>

  <div class="header"></div>

  <div class="main"></div>

  <div class="footer"></div>

</body>

根據頁面滾動的位置分爲兩種佈局,一種是滾動 body,另外一種是固定 body 的高度爲100%,在 main 中滾動。瀏覽器

第一種佈局有個優勢,就是頁面的地址欄會隨着 body 的滾動隱藏起來,而且 Android 設備中,滾動 body 會更加的流暢,若是項目中有相似需求能夠考慮。工具

實現佈局的方式以下:佈局

body {
  overflow: auto;
}

.header,
.footer {
  position: fixed;
  left: 0;
  right: 0;
  height: 44px;
}

.header {
  top: 0;
}

.footer {
  bottom: 0;
}

.main {
  height: 100%;
  padding: 44px 0;
}

第一種狀況比較適合長列表頁面,整個頁面除了 header 和 footer 以外都須要滾動,但不少時候,咱們只但願頁面的某個元素滾動,這個時候,就採起第二種佈局方式。flex

這種頁面佈局有三種相對簡單的實現方式:flexbox

  1. fixed 定位
  2. absolute 定位
  3. flex 定位

最容易想到的實現方式是 fixed 定位,實現方式以下:spa

html, body {
  height: 100%;
  overflow: hidden;
}
.header,
.footer {
  position: fixed;
  left: 0;
  right: 0;
  height: 44px;
}


.header {
  top: 0;
}


.footer {
  bottom: 0;
}


.main {
  height: 100%;
  padding: 44px 0;
  box-sizing: border-box;
}

fixed 定位實現起來簡單,在大多數瀏覽器中也能正常顯示,可是 fixed 定位在移動端會有兼容性問題,後面會提到,因此不建議這種實現方式。code

absolute 定位和 fixed 定位相似,只要把 header 的 footer 的 position 改成 absolute 就能夠了。orm

細心的小夥伴可能發現了,這裏的 main 沒有設置 overflow ,由於這裏有一個坑,不論是absolute 定位仍是 fixed 定位都同樣,爲了方便描述,如下只說 fixed 定位(在 absolute 定位也同樣成立)。在PC端沒有問題,可是在移動端,若是 main 設置了 overflow 爲 true,header 會被 main 遮住,對,沒有錯,雖然是 fixed 定位,可是在移動端,若是 fixed 定位節點後面緊接跟着的兄弟節點是可滾動的(也就是設置了 overflow 爲 true ),那麼 fixed 節點會被其後的兄弟節點遮住。

這個問題解決方式有不少,既然是 fixed 定位後面緊接着可滾動的兄弟節點纔會有這個坑,只要讓他的條件有一個不成立就行了,有如下解決方案:

  1. 讓 fixed 定位節點後面不緊接着可滾動的節點
  2. 不讓 scroll 節點遮住 fixed 節點

 

第一種方方案有如下可選方法:

1. 把全部 fixed 節點放在 scroll 元素後面,即把 header 節點放在 main 節點後面

<body>
  <div class="main"></div>
  <div class="header"></div>
  <div class="footer"></div>
</body>

但這樣顯然不太符合通常人的思惟習慣,代碼可讀性下降。

2. 使 main 不可滾動,給 main 嵌套一層可滾動的子節點

<body>
  <div class="header"></div>
  <div class="main">
    <div class="scroll-container"></div>
  </div>
  <div class="footer"></div>
</body>


<style>
  .main {
    overflow: hidden;
  }
  .scroll-container {
    height: 100%;
    overflow: auto;
  }
</style>

第二種方案有如下可選方法:

1. 讓 scroll 節點不與 fixed 節點有重合

body {
  padding: 44px 0;
}


.main {
  padding: 0;
}

2. 給 fixed 節點設置 z-index

.header,
.footer {
    z-index: 8888;
}

 

簡單的方式--->>>第三種實現方式,flex 佈局。flex 定位在移動端兼容到了 iOS 7.1+,Android 4.4+,若是使用 autoprefixer 等工具還能夠降級爲舊版本的 flexbox ,能夠兼容到 iOS 3.2 和 Android 2.1。並且用 flex 實現起來相對簡單,在各個瀏覽器裏表現也相對一致。實現以下:

body {
  display: flex;
  flex-direction: column;
}
.main {
  flex: 1;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}
.header {
  height: 44px;
}
.footer {
  height: 44px;
}

2、fixed 與 input

要在有 input 標籤的頁面使用 fixed 定位,由於這二者在一塊兒的時候,老是會有奇奇怪怪的問題。

在 iOS 上,當點擊 input 標籤獲取焦點喚起軟鍵盤的時候,fixed 定位會暫時失效,或者能夠理解爲變成了 absolute 定位,在含有滾動的頁面,fixed 定位的節點和其餘節點一塊兒滾動。

其實這個問題也很好解決,只要保證 fixed 定位的節點的父節點不可滾動,那麼即便 fixed 定位失效,也不會和其餘滾動節點一塊兒滾動,影響界面。

可是除此以外,還有不少坑比較難以解決,例如 Android 軟鍵盤喚起後遮擋住 input 標籤,用戶無法看到本身輸入的字符串,iOS 則須要在輸入至少一個字符以後,才能將對應的 input 標籤滾動到合適的位置,因此爲了避開這些難以解決的坑,在有表單輸入的頁面,儘可能用absolute 或者 flex 替換 fixed。

3、input 的 compositionstart 和 compositionend 事件

在 Web 開發中,常常要對錶單元素的輸入進行限制,好比說不容許輸入特殊字符,標點。一般咱們會監聽 input 事件:

inputElement.addEventListener('input', function(event) {
  let regex = /[^1-9a-zA-Z]/g;
  event.target.value = event.target.value.replace(regex, '');
  event.returnValue = false
});

 

這段代碼在 Android 上是沒有問題的,可是在 iOS 中,input 事件會截斷非直接輸入,什麼是非直接輸入呢,在咱們輸入漢字的時候,好比說「喜茶」,中間過程當中會輸入拼音,每次輸入一個字母都會觸發 input 事件,然而在沒有點選候選字或者點擊「選定」按鈕前,都屬於非直接輸入。

因此輸入「喜茶」兩個字,會觸發6次 input 事件,若是把每次 input 的 value 打印出來,結果以下:

這顯然不是咱們想要的結果,咱們但願在直接輸入以後才觸發 input 事件,這就須要引出我要說的兩個事件—— compositionstart 和 compositionend。

compositionstart 事件在用戶開始進行非直接輸入的時候觸發,而在非直接輸入結束,也即用戶點選候選詞或者點擊「選定」按鈕以後,會觸發 compositionend 事件。

var inputLock = false;
function do(inputElement) {
    var regex = /[^1-9a-zA-Z]/g;
    inputElement.value = inputElement.value.replace(regex, '');
}

inputElement.addEventListener('compositionstart', function() {
  inputLock = true;
});


inputElement.addEventListener('compositionend', function(event) {
  inputLock = false;
  do(event.target);
})


inputElement.addEventListener('input', function(event) {
  if (!inputLock) {
    do(event.target);
    event.returnValue = false;
  }
});

添加一個 inputLock 變量,當用戶未完成直接輸入前,inputLock 爲 true,不觸發 input 事件中的邏輯,當用戶完成有效輸入以後,inputLock 設置爲 false,觸發 input 事件的邏輯。這裏須要注意的一點是,compositionend 事件是在 input 事件後觸發的,因此在 compositionend事件觸發時,也要調用 input 事件處理邏輯。

4、iOS 1px border 實現

iOS設備上,因爲retina屏的緣由,1px 的 border 會顯示成兩個物理像素,因此看起來會感受很粗,這是一個移動端開發常見的問題。解決方案有不少,但都有本身的優缺點。

0.5px border

從iOS 8開始,iOS 瀏覽器支持 0.5px 的 border,可是在 Android 上是不支持的,0.5px 會被認爲是 0px,因此這種方法,兼容性是不好的。

背景漸變

CSS3 有了漸變背景,能夠經過漸變背景實現 1px 的 border,實現原理是設置 1px 的漸變背景,50% 有顏色,50% 是透明的。

@mixin commonStyle() {
  background-size: 100% 1px,1px 100% ,100% 1px, 1px 100%;
  background-repeat: no-repeat;
  background-position: top, right top,  bottom, left top;
}


@mixin border($border-color) {
  @include commonStyle();
  background-image:linear-gradient(180deg, $border-color, $border-color 50%, transparent 50%),
  linear-gradient(270deg, $border-color, $border-color 50%, transparent 50%),
  linear-gradient(0deg, $border-color, $border-color 50%, transparent 50%),
  linear-gradient(90deg, $border-color, $border-color 50%, transparent 50%);
}

這種方法雖然可行,可是沒有辦法實現圓角。

僞類 + transform

這類方法的實現原理是用僞元素的 box-shadow 或 border 實現 border,而後用 transform縮小到原來的一半。即便有圓角的需求也能很好的實現。

@mixin hairline-common($border-radius) {
  position: relative;
  z-index: 0;
  &:before {
    position: absolute;
    content: '';
    border-radius: $border-radius;
    box-sizing: border-box;
    transform-origin: 0 0;
  }
}
@mixin hairline($direct: 'all', $border-color: #ccc, $border-radius: 0) {
  @include hairline-common($border-radius);
  &:before {
    transform: scale(.5);
    @if $direct == 'all' {
      top: 0;
      left: 0;
      width: 200%;
      height: 200%;
      box-shadow: 0 0 0 1px $border-color;
      z-index: -1;
    } @else if $direct == 'left' or $direct == 'right' {
      #{$direct}: 0;
      top: 0;
      width: 0;
      height: 200%;
      border-#{$direct}: 1px solid $border-color;
    } @else {
      #{$direct}: 0;
      left: 0;
      width: 200%;
      height: 0;
      border-#{$direct}: 1px solid $border-color;
    }
  }
}
相關文章
相關標籤/搜索