成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

REM,你這磨人的小妖精!

lei___ / 705人閱讀

摘要:但是有一部分的安卓機(jī),并不等于根節(jié)點(diǎn)的,舉個(gè)例子的,正常情況下也應(yīng)該是,但在部分機(jī)型中,它可能是或等等筆者懷疑上文中提到的頁面寬度溢出也是這個(gè)問題。

前言

移動(dòng)端的崛起,給了我們前端更大的舞臺(tái),與此同時(shí),也給我們帶來了一系列頭疼的問題,移動(dòng)端適配就是其中之一,目前市面上最常用的方案即是REM適配。

為什么說她是一個(gè)磨人的小妖精?因?yàn)樗_實(shí)讓人又愛又恨,靈活的自適應(yīng)布局再搭配上css單位轉(zhuǎn)換工具,讓人愛不釋手;另一方面,由于移動(dòng)端的機(jī)型和表現(xiàn)千奇百怪,想要達(dá)到完美的兼容又讓人頭疼。

即使如此,依然阻止不了筆者對(duì)于她的癡迷。本文將會(huì)圍繞REM適配這一話題進(jìn)行討論,同時(shí)也會(huì)將筆者個(gè)人的經(jīng)驗(yàn)以及自己目前在用的一套代碼分享給大家。另外,如今移動(dòng)端的兼容性越來越好,因此衍生出了一些其他的適配方案,這點(diǎn)不在本文的討論范圍之內(nèi)。

實(shí)例解析 全局變量
const docEl = document.documentElement
const metaEl = document.querySelector("meta[name="viewport"]")

const maxWidth = window.__MAX_WIDTH__ || 750
const divPart = window.__DIV_PART__ || 15
const bodySize = window.__BODY_SIZE__ || 12

let scale = 1
let dpr = 1
let timer = null

metaEl:抓取現(xiàn)有viewport,以支持使用者自定義頁面實(shí)際縮放比例,通過設(shè)置viewport可以實(shí)現(xiàn)視覺上的實(shí)際物理像素。例如initial-scale=0.5,即二倍屏,假設(shè)根節(jié)點(diǎn)的font-size=100px,那么0.01rem就是物理像素1px;而initial-scale=1.0,雖然在css單位中,0.01rem=1px,但我們知道,在二倍屏中,1px實(shí)際有4個(gè)物理像素。

maxWidth:UI稿寬度,一般以iphone6為基準(zhǔn),即750。

divPart:將設(shè)備寬度劃分為多少份,上述代碼中,750/15=50,意思是750寬度的屏幕,1rem=50px,劃分多少份實(shí)際上沒有固定規(guī)定,看個(gè)人習(xí)慣。

bodySize:初始化時(shí),設(shè)置body的字體大小。

scale、dpr分別是頁面縮放比例、設(shè)備像素比。

初始化設(shè)置
if (metaEl) {
  console.warn("根據(jù)已有的meta標(biāo)簽來設(shè)置縮放比例")

  const match = metaEl.getAttribute("content").match(/initial-scale=([d.]+)/)

  if (match) {
    scale = parseFloat(match[1])
    dpr = parseInt(1 / scale)
  }
} else {
  if (window.navigator.appVersion.match(/iphone/gi)) {
    dpr = parseInt(window.devicePixelRatio) || 1
    scale = 1 / dpr
  }

  const newMetaEl = document.createElement("meta")
  newMetaEl.setAttribute("name", "viewport")
  newMetaEl.setAttribute("content", `width=device-width, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no`)
  docEl.firstElementChild.appendChild(newMetaEl)
}

// 設(shè)置根節(jié)點(diǎn)dpr
docEl.setAttribute("data-dpr", dpr)

這里要重點(diǎn)將一下為什么要區(qū)分安卓和IOS設(shè)備,很多人可能會(huì)說因?yàn)镮OS有多倍屏。實(shí)際上,安卓也有多倍屏,那為什么我們不考慮呢?

有些安卓機(jī)的設(shè)備像素比很奇怪,比如2.5、3.8等一些奇怪的數(shù)字;

部分安卓機(jī)表現(xiàn)很奇怪,比如頁面寬度比屏幕寬度多一點(diǎn),出現(xiàn)橫向滾動(dòng)條(具體原因不詳,已排除所有css干擾),兼容起來成本太高。

核心代碼
function bodyLoaded (cb) {
  if (document.body) {
    cb && cb()
  } else {
    document.addEventListener("DOMContentLoaded", function () {
      cb && cb()
    }, false)
  }
}

// 窗口寬度改變時(shí),刷新rem
function refreshRem () {
  let width = docEl.clientWidth

  if (width / dpr > maxWidth) {
    width = maxWidth * dpr
  }

  // 設(shè)置根節(jié)點(diǎn)font-size
  window.remUnit = width / divPart
  docEl.style.fontSize = window.remUnit + "px"

  bodyLoaded(() => {
    // 測試rem的準(zhǔn)確性,如果和預(yù)期不一樣,則進(jìn)行縮放
    let noEl = document.createElement("div")
    noEl.style.width = "1rem"
    noEl.style.height = "0"
    document.body.appendChild(noEl)

    let rate = noEl.clientWidth / window.remUnit

    if (Math.abs(rate - 1) >= 0.01) {
      docEl.style.fontSize = (window.remUnit / rate) + "px"
    }

    document.body.removeChild(noEl)
  })
}

// 初始化
refreshRem()

bodyLoaded(() => {
  document.body.style.fontSize = bodySize * dpr + "px"
  document.body.style.maxWidth = maxWidth * dpr + "px"
})

refreshRem函數(shù)是整個(gè)rem適配的核心,每次需要更新都會(huì)調(diào)用此函數(shù),我們還限定了頁面的最大寬度,可以保證在pc端打開也能看到不錯(cuò)的視覺效果。

但是有一部分的安卓機(jī),1rem并不等于根節(jié)點(diǎn)的font-size,舉個(gè)例子:html的font-size=20px,正常情況下1rem也應(yīng)該是20px,但在部分機(jī)型中,它可能是22px或18px等等(筆者懷疑上文中提到的頁面寬度溢出也是這個(gè)問題)。因此,筆者加上了bodyLoaded這段代碼,在rem設(shè)置完成后,再與實(shí)際視覺上的1rem進(jìn)行比較,若偏差超過1%,則認(rèn)為需要重新定義rem,這樣就能100%保證1rem就是我們期望的大小。

頁面寬度監(jiān)聽
window.addEventListener("resize", function () {
  clearTimeout(timer)
  timer = setTimeout(refreshRem, 200)
}, false)

// window.addEventListener("pageshow", function (e) {
//   if (e.persisted) {
//     refreshRem()
//   }
// }, false)

這段代碼用于監(jiān)聽resize事件,以此來重新計(jì)算根節(jié)點(diǎn)的font-size,定時(shí)器用來防止頻繁計(jì)算(實(shí)際上在手機(jī)中,也不會(huì)有頻繁觸發(fā)resize的機(jī)會(huì),因此定時(shí)器也可以不加)。有些讀者可能會(huì)問題,為什么不監(jiān)聽橫豎屏事件(onorientationchange),其實(shí)沒有必要,橫豎屏切換本質(zhì)也是resize的一種,我們已經(jīng)監(jiān)聽了resize事件,這里就沒有必要再次監(jiān)聽了。

那注釋掉的這段代碼是什么意思呢?它是用來監(jiān)聽瀏覽器返回,但是這段代碼在iPhone8、iPhoneX上會(huì)有問題,在返回的時(shí)候,我們拿到的document.documentElement.clientWidth是其實(shí)際的大小(沒有乘上設(shè)備像素比),因此整個(gè)頁面布局都亂了。筆者經(jīng)過深思熟慮,決定刪掉這段代碼,因?yàn)樵诜祷氐臅r(shí)候,會(huì)保留和離開時(shí)一摸一樣的狀態(tài),沒有必要重新再計(jì)算一遍。

工具函數(shù)
window.px2rem = function (d) {
  let val = parseFloat(d) / window.remUnit

  if (typeof d === "string" && d.match(/px$/)) {
    val += "rem"
  }

  return val
}

window.rem2px = function (d) {
  let val = parseFloat(d) * window.remUnit

  if (typeof d === "string" && d.match(/rem$/)) {
    val += "px"
  }

  return val
}

暴露全局函數(shù),方便使用js來控制尺寸大小。

CSS重置樣式

篇幅所限,樣式代碼就不在這里貼了,感興趣可以在這里看:reset.css

總結(jié)

這一套rem適配代碼是筆者日常開發(fā)中總結(jié)提煉出來,不能說是100%完美,但是也足夠適配市面上的主流機(jī)型了。再配合構(gòu)建工具,自動(dòng)轉(zhuǎn)換為rem單位,省心又省力。

最后推薦一個(gè)好用的全局構(gòu)建工具fle-cli,幫你從復(fù)雜繁瑣的構(gòu)建配置中解放出來。

本文源碼地址:https://github.com/ansenhuang/axe/blob/master/packages/rem-resize/README.md

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95529.html

相關(guān)文章

  • 一次痛苦又甜蜜的微信支付踩坑之旅

    摘要:這是我第一次接觸微信支付,發(fā)現(xiàn)網(wǎng)上還是有很多同學(xué)在求助,了怎么辦是什么情況為了幫助更多的小伙伴脫離苦海,我決定寫下這次的踩坑之旅,給更多的人幫助。 凡是和錢打交道的事,沒有一樣是容易的。這是我第一次接觸微信支付,發(fā)現(xiàn)網(wǎng)上還是有很多同學(xué)在求助,XXX了怎么辦?XXX是什么情況?為了幫助更多的小伙伴脫離苦海,我決定寫下這次的踩坑之旅,給更多的人幫助。 介紹 微信支付方式分為刷卡支付、公眾號(hào)...

    vpants 評(píng)論0 收藏0
  • 一次痛苦又甜蜜的微信支付踩坑之旅

    摘要:這是我第一次接觸微信支付,發(fā)現(xiàn)網(wǎng)上還是有很多同學(xué)在求助,了怎么辦是什么情況為了幫助更多的小伙伴脫離苦海,我決定寫下這次的踩坑之旅,給更多的人幫助。 凡是和錢打交道的事,沒有一樣是容易的。這是我第一次接觸微信支付,發(fā)現(xiàn)網(wǎng)上還是有很多同學(xué)在求助,XXX了怎么辦?XXX是什么情況?為了幫助更多的小伙伴脫離苦海,我決定寫下這次的踩坑之旅,給更多的人幫助。 介紹 微信支付方式分為刷卡支付、公眾號(hào)...

    DrizzleX 評(píng)論0 收藏0
  • 字符串拼接引發(fā)的BUG

    摘要:你的線上代碼真的沒有嗎歡迎免費(fèi)使用我們可以幫助您第一時(shí)間發(fā)現(xiàn)字符串拼接加法仔細(xì)查看生成的代碼,你會(huì)發(fā)現(xiàn)出現(xiàn)在標(biāo)記的后面,然而標(biāo)簽不見了。在中,根據(jù)左右兩邊變量的類型的不同,符號(hào)可以用于數(shù)字相加或則字符串拼接。然后又轉(zhuǎn)換為字符串拼接起來。 譯者按: bug雖小,卻是個(gè)磨人的小妖精! 原文: Fixing a bug: when concatenated strings turn int...

    zengdongbao 評(píng)論0 收藏0
  • 列舉幾條常用的CSS reset,是否了解normalize.css

    摘要:相比于傳統(tǒng)的是一種現(xiàn)代的為準(zhǔn)備的優(yōu)質(zhì)替代方案??傊且环N的替代方案。一般化的樣式為大部分元素提供。保護(hù)了有價(jià)值的默認(rèn)值通過為幾乎所有的元素施加默認(rèn)樣式,強(qiáng)行使得元素有相同的視覺效果。 Normalize.css只是一個(gè)很小的css文件,但它在磨人的HTML元素樣式上提供了跨瀏覽器的高度一致性。相比于傳統(tǒng)的CSS reset,Normalize.css是一種現(xiàn)代的、為HTML5準(zhǔn)備的優(yōu)...

    Airy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<