個人2018前端踩坑記

某著名小白說過 :世上原本處處都是坑,只要走的人多了,也就把坑都給埋了。該小白還說過:坑自己並不可怕,可怕的是踩了一次以後,還第2、第三次踩到了相同的坑。html

所謂"坑",主要是因爲咱們對某些知識點理解不夠透徹,致使在應用的時出現了一些奇怪的問題。由於咱們每一個人,對於某個知識點的理解程度不同,因此,有些坑我以爲真的很坑,可是你可能以爲一點都不坑,由於你早就對它瞭如指掌了。前端

這裏列舉的一些坑,都是我過去一年在項目中所遇到過的,並當時在筆記中記錄下來的,如今稍加整理就造成了這篇博客,以供往後查閱。git

不知不覺,開頭又bb了這麼多,仍是趕忙進入正題哈。github

1. 設置透明度(opacity)引發的慘案

以前作爐石盒子的天梯環境頁面,地址是 爐石天梯環境 ,就在項目作得差很少的時候,準備上線了, QA 忽然發現了以下的一個 bug:
web

有一個選擇排序方式的下拉菜單,它的定位是 position: absolute,正常來講,它應該會覆蓋在其餘元素之上的,但是爲何 0.14% 反而會覆蓋在它上面呢? 在代碼中找了很久,那個 0.14% 並無設置 z-index屬性,也沒有 position: absolute 這樣的東西,真是好鬱悶哦。後來到 mdn 查文檔才發現,原來是 opacity屬性引發 的: opacity 屬性值小於 1 的元素會建立新的層疊上下文 。由於當時我有個偷懶的作法,字體繼承的顏色是 #666, 我想讓 0.14% (天梯比率)顏色變淺一些,直接加了個 opacity: 0.6 ,致使了建立了新的層疊上下文,層級比下拉菜單高了,因此就覆蓋在了上面。具體什麼是層疊上下文,以及哪些屬性會建立新的層疊上下文,這裏也不介紹了有須要的能夠參考一下 層疊上下文canvas

雖然上面描述得已經很詳細了,可是可能因爲個人表達能力不太好,有些朋友還不是很明白個人意思,能夠看一下這裏的 demo 代碼:小程序

<div class="menu">
  <div class="title">下拉菜單</div>
  <div class="menu-list">
    <div class="item">菜單1</div>
    <div class="item">菜單2</div>
    <div class="item">菜單3</div>
  </div>
</div>
<div class="content">
  我是半透明的文字,能夠覆蓋在下拉菜單之上哦~
</div>
<style>
  .menu {
    position: relative;
  }
  .menu-list {
    display: none;
    position: absolute;
    background: #ccc;
  }
  .menu:hover .menu-list {
    display: block;
  }
  .content {
    opacity: 0.6;
  }
</style>

將鼠標移動到下拉菜單上,就會發現文字會發生重疊了:
微信小程序

那這個坑有什麼解決辦法呢?最簡單的就是下拉菜單添加個屬性 z-index: 1 。另外,這裏再囉嗦一下,就是z-index的值不要亂設置。之前剛剛接觸前端時,會常常看一些視頻教程,看到裏面講師動不動就設置個 z-index: 999 之類的特別大的數值。這是一個很差的習慣。張鑫旭老師在《CSS世界》一書中,提到了 不三原則,就是說通常狀況下,z-index的值不要超過3,基本能知足大多數的需求了。數組

2. flex佈局:子項溢出後沒法查看所有內容

以前作漫畫閱讀器,由於漫畫可能有長圖片,也可能有短圖片。長圖片能夠滾動查看,短圖片就居中顯示。因此,很天然會想到用 flex 佈局來實現。簡單的代碼以下:微信

<div class="app">
  <img src="https://m.tuniucdn.com/fb2/t1/G1/M00/F1/51/Cii9EFkAaZ-IRgGNAATB18ldk0UAAJzuQN-p1cABMHv15.jpeg" alt="">
</div>
<style>

  html,
  body {
    height: 100%;
  }

  .app {
    display: flex;
    height: 100%;
    justify-content: center;
    align-items: center;
  }

  img {
    width: 100%;
  }
</style>

這裏,咱們的 .app 容器裏面這裏有一張很長的圖片。當咱們運行上面的代碼,若是你仔細觀察原圖和頁面顯示的圖片,就會發現圖片的頂部和底部的一些內容看不到了,滾動條到了必定位置就沒法滾動了。正常來講,咱們應該能夠經過滾動條的上下滑動看到圖片的所有內容纔對的。當時我想了好久也沒有想出來緣由,最後到 stackoverflow 找到了答案 Can't scroll to top of flex item that is overflowing container

答案中有提到,能夠設置子項的 margin: auto 來實現內容溢出時也自動居中(包括水平和垂直的):

修改後的 CSS 代碼以下:

.app {
    display: flex;
    height: 100%;
  }

  img {
    width: 100%;
    margin: auto;
  }

因此,之後若是在使用 flex 佈局實現居中,若是子項的內容會溢出 flex 容器 ,能夠將子項設置爲 margin: auto 試試。

3. transfrom 和 fixed 不能在一塊兒!

CSS3 的 transform 屬性也算是比較經常使用的,特別是作一些動畫效果的時候,用它來移動元素的位置,性能會比設置 top 或 left 要高一些。可是,若是一個元素設置了 transform 屬性,而它的子元素又設置 fixed 定位,那麼這個 fixed 定位的子元素表現會有些奇怪,以下代碼:

<div class="app">
  <button onclick="layer.style.display='block'">彈出蒙層</button>
  <div class="layer" id="layer"></div>
</div>

<style>
  .app {
    position: relative;
    width: 100px;
    height: 100px;
    background: #ccc;
    /* 使用transform讓元素向下偏移20px */
    transform: translate(0, 20px);
  }

  .layer {
    display: none;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.7);
  }
</style>

打開頁面,效果是這樣的:

咱們但願點擊「彈出蒙層」按鈕後,就顯示個覆蓋整個窗口的蒙層。可是結果卻出乎意料。以下:

蒙層只是遮住了小正方形,這不是咱們想要的結果,由於咱們知道,fixed 定位是相對於屏幕視口(viewport)定位的, 可是,本例卻相對於它的父親元素。這是爲何呢?若是認真查閱 mdn文檔 ,就會找到答案:

可見,問題的緣由在於,咱們只是記住了fixed是相對於 viewport 定位,可是也有特殊狀況: 當元素祖先的 transform 屬性非 none 時,容器由視口改成該祖先 。因此,這並非bug,是由於我基礎不紮實致使的。事實上, 除了 transform 會改變 fixed 的定位元素以外,還有其餘屬性也會改變,ChokCoco大佬有一篇文章作了詳細的講解,想要了解更多的請點擊 不受控制的 position:fixed

那遇到這種狀況怎麼辦呢?比較好的辦法就是把 fixed 元素移到外面去,不要放到有 transform 屬性的元素裏面。可是,有時候咱們沒有辦法移到外面怎麼辦呢?好比,這是它是一個子組件,它的某個父親組件就是用了 transform,那怎麼辦呢?我也不知道怎麼辦,歡迎你們探討一下哈哈哈~

fixed 定位還具備其餘的坑,這裏也不展開了,有興趣的可看 看github 上有大佬整理好的這篇文章 移動端web頁面使用position:fixed問題總結

4. 安卓微信視頻播放器的層級問題

咱們都知道, video 標籤設置了 playsinline 就能夠內聯播放視頻,而不是全屏播放。(注意:前提是客戶端的 Webview 配置了容許內聯播放,因此有時候雖然設置了 playsinline,但在某些 app 裏面打開依然是全屏播放,這不是前端的鍋哦)。最近有一個需求,相似下面這樣的:

頁面上有一個視頻,視頻播下面有一個按鈕,點擊按鈕就彈出一個圖片,該圖片要覆蓋整個屏幕,好比是這樣的:

示例代碼以下:

<video id="video" controls="" playsinline="" src="https://vod.cc.163.com/file/5bcbe1ae9efdc0608bb6d06b.mp4"></video>
<img id="image" src="https://ds.163.com/2018/mrzh/appointment/static/img/bg-body.cdef1ec.jpg" alt="">
<button id="button">彈出圖片</button>
<style>
  video,
  img {
    width: 100%;
  }

  img {
    display: none;
    position: absolute;
    top: 0;
  }
</style>

<script>
  var video = document.getElementById('video');
  var image = document.getElementById('image');
  var button = document.getElementById('button');
  button.onclick = function() {
    image.style.display='block';
  }
  image.onclick = function() {
    this.style.display='none';
  }
</script>

可是,在安卓上卻發現一個問題,開始播放視頻後(注意,只有播放視頻後才能夠復現),點擊「彈出圖片」按鈕,顯示以下所示:

圖片沒法覆蓋在視頻播放器上面。而後,我設置了 z-index 或者 transform ,都沒有任何效果。最後, 剩下的可能緣由就是: 安卓微信視頻播放器實際上用的是原生組件。爲了驗證這一猜測,咱們能夠啓用開發者選項的繪圖模式 (開發者選項 --> 繪圖 --> 顯示佈局邊界,不一樣機型不同,找不到的請百度找一下哈),結果以下:


看到沒有,視頻是一個完整的有邊框的東西,證實他是一個獨立於 Webview 的原生組件。

那怎麼辦呢?只能上網找答案呀!咱們都知道,微信 webview 使用的是 X5 內核,因此我也但願能從它的開發者文檔上找到一些有用的信息,好不容易找到了一篇叫作 H5同層播放器接入規範 。它說能夠能夠在 video 標籤添加一個屬性 x5-video-player-type ,而且給出的例子是這樣的:

<video src="http://xxx.mp4" x5-video-player-type="h5"/>

我當時很高興,覺得問題就這樣解決了,然並卵,添加了 x5-video-layer-type 屬性以後,playsinlie 屬性就失效了,沒法內聯播放了,只能全屏播放,因此,不能添加這個屬性。

而後我就想,既然沒法覆蓋這個視頻,那在彈出圖片的時候能不能把視頻給隱藏掉?而後關閉圖片的時候再把視頻顯示回來呢?因而就把 JS 代碼改爲下面這樣:

button.onclick = function() {
    image.style.display='block';
    video.style.display = 'none';
  }
  image.onclick = function() {
    this.style.display='none';
    video.style.display = 'block';
  }

而後,這樣就能夠了。由於我在網上找不到更好的辦法,若是你們遇到這個問題能夠參考這種作法。固然,若是大家找到了有更好的辦法,歡迎評論分享出來哈~

關於安卓微信視頻播放器的坑就先講到這裏啦。

等等,一講到原生組件,這裏還得再補充一下微信小程序相關的東西,固然,我本身尚未太小程序的開發的經驗, 這是以前的一次內部交流會,一位同事的分享:小程序在渲染的時候,大多數組件都是渲染成 HTML 組件,可是有少部分好比 canvas、 video、 input、 map 等會渲染成原生組件的。因此,若是你在寫小程序時,想用一段文字覆蓋在一個 canvas 上,發現怎麼設置都沒法實現,那是由於 canvas 渲染後是原生組件,而文字是 html 組件,因此沒法覆蓋上去的 。那有什麼辦法呢?能夠考慮把文字放到 cover-view 上, 它也是一種原生組件,能夠覆蓋在 canvas 上的。具體的能夠參考小程序官方文檔 原生組件說明

關於2018踩的坑就寫到這裏了,固然還有一些其餘的,暫時沒有時間整理,下次若是整理後,再寫一篇補充一下。

若是你們有什麼問題,或者過去踩到過了哪些坑,歡迎在評論區討論哈。

相關文章
相關標籤/搜索