css容易使人蒙圈的幾個經典問題

轉眼間,2019年還有不到12個小時就要徹底過去,回顧自己這一年來,收穫與失落並存。在這最後時刻,發一篇文章送給社區,也送給自己。

本文摘自這一年來自己在工作中經歷的幾個比較好的CSS問題(不一定複雜,但個人覺得都挺值得一說),這些CSS問題平時很少遇到,即使遇到後也不一定知道解決方案,即使知道解決方案也不一定知道產生的原理,同時也準備了2個JS問題(之前有整理過一篇較長的JS問題文章,在此不做推新)。本文會更新下去,希望幫到各位朋友。期待您的點贊,謝謝。

“我自己是一名從事了6年web前端開發的老程序員(我的微信:web-xxq),今年年初我花了一個月整理了一份最適合2019年自學的web前端全套培訓教程(視頻+源碼+筆記+項目實戰),從最基礎的HTML+CSS+JS到移動端HTML5以及各種框架和新技術都有整理,打包給每一位前端小夥伴,這裏是前端學習者聚集地,歡迎初學和進階中的小夥伴(所有前端教程關注我的微信公衆號:web前端學習圈,關注後回覆“2019”即可領取)。

一、CSS篇

1.1 元素默認藍色邊框

input標籤元素(如buttontextareatext)的一些事件(如clickfocus等),在很多瀏覽器下默認會有藍色邊框出現,如把一個普通buttonbackgroundborder都設置爲none後,觸發點擊後樣式如下:

 

rgba

 

這是由元素默認的輪廓線產生的,這是瀏覽器的一種防護機制,起到突出元素的作用,把它幹掉就行了,方法如下:

// 方法1:
outline: none / medium;

// 方法2:
outline-width: 0
複製代碼

1.2 背景透明,文字不透明

我們通常是使用 opacity來做背景的透明化處理,該屬性被所有瀏覽器支持,可以大膽使用,透明度從0.0(完全透明)到1.0(完全不透明),但該方法會使其所有子元素都透明,此時若只想讓背景透明,其他不透明,則可以使用rgba處理背景:

background-color: rgba( red , green , blue , alpha )
複製代碼

其中這個alpha 即設置透明度,取值在0~1之間。該方法除IE9以下不可用外,其他瀏覽器均可用,看一下效果:

rgba

 

同理,我們也可以用這個方法把整個背景做透明瞭,即多寫一個div作爲modal層做透明處理,可以明顯看到上面文字並未透明:

 

整體背景透明

 

上述種效果代碼如下:

// html
<section>
  <div class="item-pic">
    <header class="header1">
      <h4>你會微笑放手,說好不哭讓我出新專輯</h4>
    </header>
  </div>
  <div class="item-pic">
    <header class="header2">
      <h4>你會微笑放手,說好不哭讓我出新專輯</h4>
    </header>
  </div>
  <div class="item-pic">
    <div class="handle-opacity"> <!-- 透明罩 -->
      <header>
        <h4>你會微笑放手,說好不哭讓我出新專輯</h4>
      </header>
    </div>
  </div>
</section>
<style lang="less">
.header1 {
  opacity: .6;
}
.header2 {
  background-color: rgba(0, 0, 0, 0.45);
}
.handle-opacity {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgba(255, 255, 255, 0.45);
  header {
    background-color: rgba(0, 0, 0, 0.45);
  }
}
</style>
複製代碼

1.3 div內置img元素,底部總有間距

用一個div包裹一個img,會出現img不能完全覆蓋div空間,總會在底邊留下一點空隙。

 

div底部間隙

 

這種現象產生的原因是img是行內元素,瀏覽器爲下行字符(如:g、y、j、p、q)留下的一些空間,這些字符是會比其他字符多佔據底部一些空間(具體以當前字體大小有關),這種規則會影響行內元素img標籤(其默認垂直對齊方式是依照基線來的,即vertical-align: baseline),同樣行內元素都會和外部元素留這麼一丟丟安全距離。上圖右側就是加了文字的效果,這樣就更說明一切了。

現在我們知道這種現象主要是由於下行字符串保護機制和img是行內元素這兩個因素導致的,那解決方案就從這兩處入手,整理如下:

  1. div設置font-size: 0line-height: 0,進而行高爲0;
  2. img設置 vertical-align: top 或者 middle/,使其不再以默認基線爲對齊方式;
  3. img設置 display:block,使其變成塊級元素。

綜上,個人認爲方法3是最好用的,方法1不推薦使用。

1.4 元素自動填充上背景色

該現場多在表單輸入等場景上會出現,初次看到確實很怪異,效果如圖:

 

默認顏色

 

即當瀏覽器(chrome)給輸入框自動填充內容後,也會自動給輸入框帶上背景(黃或灰藍),該問題是由於chrome會默認給自動填充的inputselecttextarea等加上:-webkit-autofill私有僞屬性造成的,比較好的解決方案就是做樣式覆蓋,代碼如下:

input:-webkit-autofill{
  box-shadow: 0 0 0px 1000px white inset !important;
}
select:-webkit-autofill{
  box-shadow: 0 0 0px 1000px white inset !important;
}
textarea:-webkit-autofill{
  box-shadow: 0 0 0px 1000px white inset !important;
} 
複製代碼

比較渣的辦法是設置禁止自動填充,但還是別那樣做了...

1.5 transform 基數值導致字體模糊

transform作爲CSS3最爲自豪的屬性,已經成爲了當前前端開發中不可或缺的方法,但它有個渲染的問題,即當元素設置有transform,且其值爲基數或小數,同事其整體高度也有基數時,其內部文字會變模糊,如圖:

 

模糊

 

上圖上模糊狀態下的,下圖是修正過的,具體原因經查可能是因爲transform變換會在瀏覽器上單獨創建一個繪畫層並重新進行渲染,在此渲染過程中也處理了周圍的文字,如果高度爲奇數的文字可能會存在半個像素的計算量,瀏覽器對這半個像素會進行優化渲染,所以邊緣會出現模糊的情況。解決方案即:

  1. 不要給transform屬性值設置基數和小時值;
  2. 調整整體元素高度不要爲基數。

1.6 :last-child 和 :last-of-type

作爲CSS常用僞類選擇器,:last-child經常會被用到,但有時遇到極端情況,它會意外失效,讓人摸不着頭腦,例子如下: 3個img標籤包裹在card中,當前需求是使最後一張圖的邊框呈粉色,代碼如下:

// html
<div class="card">
  <img 
    v-for="(item,i) in pics"
    :key="i"
    :src="item"
  />
</div>
// css
<style lang="less">
.card {
  > img {
      width: 150px;
      margin-right: 10px;
      &:last-child {
        border: 5px solid pink;
      }
   }
}
</style>
複製代碼

同理用:last-of-type也能實現:

.card {
  > img {
      width: 150px;
      margin-right: 10px;
      &:last-of-type {
        border: 5px solid pink;
      }
   }
}
複製代碼

效果如下:

 

有效

 

現在要往img後加一個span,發現:last-child已失效:

// html
<div class="card">
  <img 
    v-for="(item,i) in pics"
    :key="i"
    :src="item"
  />
  <span>next is ...</span>
</div>
// css
<style lang="less">
.card {
  > img {
      width: 150px;
      margin-right: 10px;
      &:last-child {
        border: 5px solid pink;
      }
   }
}
</style>
複製代碼

 

失效

 

而此時:last-of-type依然沒問題:

 

有效2

 

現在得出結論:

  1. :last-child選取一羣兄弟元素中的最後一個元素,且最後的這個元素必須是所聲明的指定元素(注意2個條件);
  2. :last-of-type選取一羣兄弟元素中的最後一個指定類型的元素。

可知,:last-of-type更嚴謹一些,不容易產生意外bug,我更推薦使用它。同理適用於:nth-last-child(n):nth-last-of-type(n)

二、DOM篇

這部分我會敘述一些DOM操作遇到的一些容易被忽視的問題。

2.1 IOS日期顯示問題

經常做H5移動端開發的朋友我想對這個問題肯定不陌生,那就是在部門IOS版本(IOS5及以下)中,對以“-”間隔的字符串時間格式的解析是不成功的,比如我們寫了這麼一個雞肋時間格式適配器:

function DateFormat(date) {
  if(!date) return null;
  date = new Date(date);
  let Y = date.getFullYear();
  let M = (date.getMonth() >= 0 && date.getMonth() <= 8) ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`;
  let D = (date.getDate() >= 0 && date.getDate() <= 9) ? `0${date.getDate()}`: `${date.getDate()}`;
  return `Y-M-D`
}
複製代碼

此時如果在IOS5及以下版本的iphone下,傳入 "2019-12-31"就會呈現出 NaN-NaN-NaN,而其他IOS版本及安卓系統都是沒問題的。

針對上述問題,要做兼容適配,即把以"-"間隔的事件字符串替換成以"/"即可,同樣是這個適配器,添加一段代碼:

function DateFormat(date) {
  if(!date) return null;
  if(typeof date === 'string' &&  date.indexOf('T')!=-1 && date.indexOf('+')!=-1) {
    date = date.replace(/-/g, '/').replace('T',' ').substring(0,date.indexOf('.'))
  }
  date = new Date(date);
  let Y = date.getFullYear();
  let M = (date.getMonth() >= 0 && date.getMonth() <= 8) ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`;
  let D = (date.getDate() >= 0 && date.getDate() <= 9) ? `0${date.getDate()}`: `${date.getDate()}`;
  return `Y-M-D`
}
複製代碼

2.2 ENTER鍵使當前頁刷新

這個真的很詭異的問題,當在一個表單中執行了ENTER鍵提交後,如果是打開新頁面顯示提交結果,則會發現當前表單頁面也跟着刷新了,這種體驗當然是很糟糕的。經查證,該問題的產生條件爲:Form中只有一個input時,此時執行ENTER鍵會自動提交表單並刷新頁面。解決方案也很粗暴,直接在input輸入框附近寫一個隱藏標籤,這樣就有2個input了,即避免了產生默認刷新的bug,實例如下:

<form>
  <input 
    type="text" 
    v-model.trim="searchText" 
    placeholder="搜索您感興趣的內容"
    @keyup.enter="goSearch" 
  />
  <input 
    id="hidden" 
    type="text" 
    style="display:none" 
    @keyup.enter="goSearch"
  />
</form>
複製代碼

終於在2020年到來前夕發了一篇比較趕的文章,結束我的2019之旅。本文會一直更新下去,如有不同見解和問題,請留言指出,期待您的點贊。最後祝您2020好運連連。

發佈了163 篇原創文章 · 獲贊 265 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章