モバイルページ開発におけるレムレイアウトの適応原則
適応とは何ですか?なぜ適応する必要があるのですか?
私たちが入手する設計図は一般的に640、750、1080の解像度に基づいて設計されており、現在モバイル端末にはさまざまな解像度があります。さまざまなスタイル、さまざまな解像度、さまざまな論理ピクセル、さまざまなビューポートがあるため、すべてのデバイスでページを適切に表示するには、これらのデバイスに合わせて統一された処理を行う必要があります。これをモバイル エンド アダプテーションと呼びます。
知っておくべきいくつかの概念:
物理ピクセル
物理ピクセルは、ディスプレイ (携帯電話の画面) 上の最小の物理表示単位であり、私たちが通常話している解像度として理解できます。
デバイスに依存しないピクセル (密度に依存しないピクセル)
デバイスに依存しないピクセル (密度に依存しないピクセルとも呼ばれます) は、コンピューター座標系の点として考えることができます。この点は、コンピュータで使用できる仮想ピクセルを表します。プログラム (例: CSS ピクセル) は、関連するシステムによって物理ピクセルに変換されます。これは、私たちが話しているビジュアル ビューポートのサイズとして理解できます
したがって、物理ピクセルと物理ピクセルの間には、一定の対応関係があります。デバイスに依存しないピクセル、これが次に起こることです。デバイスのピクセル比について話しましょう。
デバイス ピクセル比 (デバイス ピクセル比)
デバイス ピクセル比 (略して dpr) は、物理ピクセルとデバイス非依存ピクセルの対応を定義します。その値は、次の式に従って取得できます: デバイス ピクセル比 = 物理ピクセル / デバイス。独立したピクセル // 特定の方向、つまり x 方向または y 方向
デバイスのピクセル比も、JavaScript では window.devicePixelRatio を通じて取得できます。
ビューポート
PC ビューポートは、ツールバーとスクロール バーを除く、ブラウザ ウィンドウ内のコンテンツ領域を指します。
モバイル ブラウザのビューポートは、いくつかの状況に分けられます:
私たちが見るブラウザウィンドウとWebページ領域のサイズはビジュアルビューポートと呼ばれ、CSSピクセル(デバイス論理ピクセル)で表されます
rem
remはcss3の一部です。長さの単位は、ドキュメントと要素 html; たとえば、set html font-size=100px; その後に続くすべての要素は、このベースライン値を使用してサイズを設定できます:
Adapt からの固定の高さ、幅、 em)
rem レイアウトを使用する
以下は、淘宝網のホームページで rem を使用する NetEase の計画の概要です
NetEase のアプローチ:
1) レイアウトの適応性をスケーリングなしのビジュアル ビューポート、つまり理想的なビューポートに設定します。 。
<meta name="viewport"content="initial-scale=1,maximum-scale=1, minimum-scale=1”>
2) デザインドラフトの解像度に基づいて、フォントサイズの基準として 100px を取ると、デザインドラフトの幅が 640 の場合、body 要素の幅は width: 6.4rem ( 640/100) レイアウト ビューポートを 320 に設定すると、html font-size=deviceWidth / 6.4 になります。
3) document.documentElement.clientWidth を通じて deviceWidth を取得します。
4) ページの dom が準備できたら、HTML フォント サイズを設定します。
document.documentElement.style.fontSize =document.documentElement.clientWidth / 6.4 + ‘px’
5) フォント サイズには、rem を使用できません。エラーが大きすぎます。
640 のデザイン案を例に挙げると、HTML の font-size を設定する最終的なコードは次のとおりです。レイアウトするときは、デザイン案に記載されているサイズを rem の値で割ります。 simple
var deviceWidth = document.documentElement.clientWidth; if(deviceWidth > 640) deviceWidth = 640; document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
ここで (deviceWidth > 640) deviceWidth = 640; は、deviceWidth が 640 より大きい場合、物理解像度が既に 1280 より大きいためです (dpr に応じて)、PC の Web サイトにアクセスする必要があります
淘宝的做法:
原理
1) 通过dpr设置缩放比,实现布局视口大小,
var scale = 1 / devicePixelRatio; document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale='+ scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
2) 动态计算html的font-size
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + ‘px’;
这里的意思是,clientWidth / 10 得到是布局视口下的rem基准值(以iphone6为例 1rem=75px),那么设计稿正好也是 750,所以对应的关系 clientWidth / 10==设计稿的尺寸/x, 那么x=设计稿的尺寸/rem基准值。如果是iphone6 plus rem基准值等于clientWidth / 10 等于124.2,那么x=750/124.2。
关于具体的实现 淘宝提供了一个开源的方案lib-flexible:https://github.com/amfe/lib-flexible
具体逻辑 :
1)判断head中是否设置了viewport,如果有设置,按照已有viewport 设置缩放比;
if (metaEl) { console.warn('将根据已有的meta标签来设置缩放比例'); var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/); if (match) { scale = parseFloat(match[1]); dpr = parseInt(1 / scale); } }
2)如果没有设置meta viewport,判断是否设置dpr,如果有,通过dpr计算缩放scale。
var content = flexibleEl.getAttribute('content'); if (content) { var initialDpr = content.match(/initial\-dpr=([\d\.]+)/); var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);//maximum 设置最大值,与initial的值比较,取最小值; if (initialDpr) { dpr = parseFloat(initialDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } if (maximumDpr) { dpr = parseFloat(maximumDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } }
3)如果 dpr &scale都没有设置,那么就通过设备的dpr设置起缩放 scale,
if (!dpr && !scale) {//meta[name="viewport"]&&meta[name="flexible"]都不存在。 var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; }
4)得到scale之后 ,如果meta 的viewport不存在,那么就创建一meta[name=“viewport”],将scale配置进去。
metaEl = doc.createElement('meta'); metaEl.setAttribute('name', 'viewport'); metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); if (docEl.firstElementChild) { docEl.firstElementChild.appendChild(metaEl); }
5)动态改写html的font-size
var width = docEl.getBoundingClientRect().width;//获取html的宽度 if (width / dpr > 540) {//判断屏幕逻辑像素大于540时,取540 width = 540 * dpr; } var rem = width / 10; docEl.style.fontSize = rem + 'px'; flexible.rem = win.rem = rem;
总结:
使用rem布局,实质都是通过动态改写html的font-size基准值,来实现不同设备下的良好统一适配;
网易与淘宝不同 的地方是 ,网易将布局视口设置成了 视觉视口,淘宝将布局视口设置成了物理像素大小,通过 scale缩放嵌入了 视觉视口中;
容器元素的字体大小都不使用rem,需要额外的media查询;