如何優雅地實現瀏覽器兼容與CSS規則回退

Marco Samaniego @ unsplash.com

讀完了《Visual Studio Code權威指南》,前端方面書籍不能停,於是撿起「CSS一姐」 Lea Verou 的《CSS魔法》。

我們沒法控制用戶使用新版本還是老版本的瀏覽器,因此往往需要根據瀏覽器對於屬性的兼容情況書寫多套 CSS 程式碼。本文就是探討如何優雅地應對瀏覽器兼容問題,包括四點:層疊機制來支援較早的瀏覽器,Modernizr設置輔助類來分別編寫樣式,使用 @supports 規則回退,簡短的 JavaScript 程式碼實現回退。

提供瀏覽器兼容的網站

層疊機制來支援較早的瀏覽器

/* 防止 linear-gradient 在老瀏覽器中掛掉導致沒有背景 */
background: rgb(255, 128, 0);
background: -moz-linear-gradient(0deg, yellow, red);
background: -o-linear-gradient(0deg, yellow, red);
background: -webkit-linear-gradient(0deg, yellow, red);
/* 應該將標準語法放在最後,來確保最終生效的是是標準語法 */
background: linear-gradient(90deg, yellow, red);

Modernizr設置輔助類來分別編寫樣式

這裡參考了一篇14年的老部落格 Modernizr 的介紹和使用

Modernizr 官網://modernizr.com/

Modernizr 如何生效?如果頁面支援 text-shadow 屬性,那麼 Modernizr 會添加 textshadow 類。如果不支援,那麼它用 no-textshadow 類作為替代進行添加。

因此,前端開發人員就可以設置兩套程式碼,來應對瀏覽器提供或者不提供 text-shadow 支援的兩種情況。

/* 瀏覽器不支援 text-shaow */
h1 { color: gray }

/* 瀏覽器支援 text-shaow */
.textshaow h1 {
  color: transparent;
  text-shadow: 0 0 .3rem gray;
}

使用 @supports 規則回退

除了使用 Modernizr ,也可以使用瀏覽器自帶的 @supports :

/* 瀏覽器不支援 text-shaow */
h1 { color: gray }

/* 瀏覽器支援 text-shaow */
@supports (text-shadow: 0 0 .3rem gray){
    h1 {
    color: transparent;
    text-shadow: 0 0 .3rem gray;
  }
}

但是 Lea Verou 指出,上述程式碼的投影效果只有在即支援 @supports 又支援 text-shadow 的瀏覽器中才會生效。因此慎用 @supports

簡短的 JavaScript 程式碼實現回退

思路與 Modernizr 相同,做特性檢測,然後添加輔助類。

var root = document.documentElement;  // <html>

if ('textShadow' in root.style) {
  root.classList.add('textshadow')
} else {
  rott.classList.add('no-textshadow')
}

如上,我們為 html 添加了輔助類:

  • 如果瀏覽器支援 text-shadow ,那麼添加 textshadow
  • 如果瀏覽器不支援 text-shadow ,那麼添加 no-textshadow

上述程式碼可以被封裝為函數:

function testProperty(property) {
  var root = document.documentElement;

  if (property in root.style) {
    root.classList.add(property.toLowerCase());
    return true;
  }

  root.classList.add('no-' + property.toLowerCase());
  return false;
}

注意到上述方法只能用來檢測屬性是否支援,而非屬性值。(如下,解釋一下屬性和屬性值,如下程式碼)

background : linear-gradient(red, tan);
    屬性    :     屬性值                ;

檢測屬性值是否支援,常見的思路是:賦給對應屬性,然後看瀏覽器是否還保存著這個值。這個方法會改變元素樣式,因此可以用隱藏元素防止樣式因為檢測被改變。

var dummy = document.createElement('p');
dummy.style.backgroundImage = 'linear-gradient(red, tan)';

if (dummy.style.backgroundImage) {
  root.classList.add('lineargradients');
} else {
  root.classList.add('no-lineargradients');
}

封裝函數如下:

function testValue(id, value, property) {
  var dummy = document.createElement('p');
  dummy.style[property] = value;

  if (dummy.style[property])  // 屬性值被瀏覽器保留
  {
    root.classList.add(id);
    return true;
  }
  
  root.classList.add('no-' + id);
  return false;
}

CSS一姐的書真的很有水平,怪不得前端大大們把她的《CSS揭秘》列為必讀書目。