Зачем писать эту статью?
В последнее время компания проделала много модных мероприятий по H5.На самом деле, страницу H5 не сложно написать на каждом фронтенде, но в деталях есть много деталей фронтенда, которые не так совершенны.Это очень сложно( по крайней мере я так думаю), так что давайте подытожимH5适配的那些事
иллюстрировать
Чтобы лучше понять эту статью, вы можете сначала прочитатьПочему мы часто говорим о проблеме 1px, а не 2pxправильно设备独立像素,css像素,逻辑像素,设备像素比Базовое понимание концепций
Эта статья является первой из серии статей об адаптации
универсальное решение
Перед исследованием мы можем увидеть, как крупные заводы адаптируются к H5.
Таобао
адрес:main.m.taobao.com/
строить планы:Flexible
Анализ: об этом стоит поговоритьFlexibleЭто решение для адаптации мобильного терминала, предложенное командой Taobao, но мобильное Taobao, похоже, не использует это решение.Вы можете увидеть следующие изображения, чтобы сделать выводы.
Теперь мы меняем модель телефона
Можно обнаружить, что адаптационная единица других непосредственноpxвообще не используетсяrem,ТолькоpxЗначение рассчитывается по разной динамике экрана телефона, поэтому, когда мы изменим размер яблока, веб-сайт刷新динамически вычислять соответствующиеpxзначение, с тем чтобы достичь цели адаптации
Просто зайдите на внутреннюю страницу Taobao и обнаружите, что используемая схема адаптацииvw
JD.com
адрес:m.jd.com/строить планы:rem
Анализ: адаптация JD.com относительно грубая, используйте ее напрямуюМедиа-запрос для изменения размера корневого шрифта htmlзатем используйтеremадаптировать
ByteDance
адрес:job.byte dance.com/campus/no/broken…
строить планы:responsive.js
Анализ: я думаюresponsive.jsи ТаобаоFlexible.jsПо сути одно, это все динамические измененияhtmlизfont-sizeзатем используйтеremадаптировать
Резюме адаптации
Благодаря продуктам этих основных производителей мы можем сделать вывод, что существует три решения для адаптации мобильных терминалов.
- рем (мейнстрим)
- vw/vh (частично)
- Прямой пиксель (разделенная сцена)
Так? Эта статья закончилась? 😶 На самом деле, это только начало нашей сегодняшней галантереи.
сказатьFlexible
FlexibleКак создатель адаптации мобильного терминала, он очень ценен для исследований, и теперь многие мобильные терминалы H5 используют это решение для адаптации, сегодня мы узнаем его принцип.
0.3.2版本
эта версияFlexibleПринцип приспособления заключается вmetaМетка изменяет коэффициент масштабирования страницы, чтобы достичь цели адаптации.В то же время это решение также может быть решено1pxПроблема, исходный код выглядит следующим образом
(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
// 如果已经设置<meta name="viewport">属性,就根据当前设置的属性
if (metaEl) {
var match = metaEl
.getAttribute("content")
.match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
// 同上
var content = flexibleEl.getAttribute("content");
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
// 这里就是 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;
}
// 将 <meta> 根据当前设备的 dpr 标签进行缩放
scale = 1 / dpr;
}
docEl.setAttribute("data-dpr", dpr);
// 根据当前的 dpr 自动设置 <meta> 属性
if (!metaEl) {
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);
} else {
var wrap = doc.createElement("div");
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem() {
// 对ipad等设备的兼容
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
// 将屏幕10等分,设置 fontSize
var rem = width / 10;
docEl.style.fontSize = rem + "px";
flexible.rem = win.rem = rem;
}
win.addEventListener(
"resize",
function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
},
false
);
win.addEventListener(
"pageshow",
function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
},
false
);
// 设置字体 12 * dpr
if (doc.readyState === "complete") {
doc.body.style.fontSize = 12 * dpr + "px";
} else {
doc.addEventListener(
"DOMContentLoaded",
function(e) {
doc.body.style.fontSize = 12 * dpr + "px";
},
false
);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
// 工具函数
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === "string" && d.match(/rem$/)) {
val += "px";
}
return val;
};
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === "string" && d.match(/px$/)) {
val += "rem";
}
return val;
};
})(window, window["lib"] || (window["lib"] = {}));
Эффект адаптации заключается в следующем.
Мы можем легко увидеть из исходного кодаdata-dpr, HTMLfont-size, телоfont-szieи мета缩放比例как это рассчитывается
Ниже мы просто рассмотримdprрасчет
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;
}
Видно, что в этой версии толькоiosdpr обрабатывается, для安卓модели по умолчаниюdpr = 1, очевидно, такое обращение немного неразумно
о
<meta>Для ярлыка мы можем понять это так: вы читаете газету (ширина содержимого страницы 750 пикселей) через рамку (ширина экрана мобильного телефона 375 пикселей), в это время рамка близка к газета,так что вы видите через рамку,Только содержимое в области рамки.Для того,чтобы увидеть все содержимое,объектив нужно уменьшить.Гибкая делает вышеуказанные вещи,а затем позволяет нам писать в соответствии с дизайном черновик при написании размера. Это поможет нам разделить на соответствующее кратное dpr, но это поможет нам уменьшить масштаб окна просмотра до 1/dpr
flexible-2.0
Версия 2.0 больше не нацеленаviewportмасштабируется, увеличивая0.5pxСуждение, исходный код выглядит следующим образом:
(function flexible(window, document) {
var docEl = document.documentElement;
var dpr = window.devicePixelRatio || 1;
// 设置 body 字体
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = 12 * dpr + 'px';
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize);
}
}
setBodyFontSize();
// 设置 rem 基准值
function setRemUnit() {
var rem = docEl.clientWidth / 10;
docEl.style.fontSize = rem + 'px';
}
setRemUnit();
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit);
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit();
}
});
// detect 0.5px supports
if (dpr >= 2) {
var fakeBody = document.createElement('body');
var testElement = document.createElement('div');
testElement.style.border = '.5px solid transparent';
fakeBody.appendChild(testElement);
docEl.appendChild(fakeBody);
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines');
}
docEl.removeChild(fakeBody);
}
})(window, document);
мы видим правильно0.5pxрешение проблем
if (dpr >= 2) {
var fakeBody = document.createElement('body');
var testElement = document.createElement('div');
testElement.style.border = '.5px solid transparent';
fakeBody.appendChild(testElement);
docEl.appendChild(fakeBody);
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines');
}
docEl.removeChild(fakeBody);
}
Наверное по логике судить поддерживает устройство или нет0.5px, если поддержкаbodyДобавьте файл с именем вышеhairlinesизclass, поэтому 2 наш код можно записать так
/* dpr=1的时候*/
.line{
border:1px solid red;
}
/* dpr>=2且支持0.5px的时候*/
.hairlines .line{
border:0.5px solid red;
}
Но это также имеет следующие две проблемы
- для тех
dpr>2 且不支持0.5pxКак мы должны поступить с этим единым образом? - если
dpr=3Такborderдолжно быть0.3333pxвместо0.5px, ноflexibleиспользуйте один из этихhairlinesсодержит
похоже на тоflexibleЭто не кажется идеальным, но мы не можем этого отрицать.flexibleплан адаптации, выбросить1pxпроблема, так сказатьflexibleидеально
сказатьvw/vh
по моему мнениюvwНа самом деле принцип адаптацииflexibleТо же самое, они все окна разделены, но одно разделено10одна акция100доля
оvwМы подробно объясним, когда будем использовать его в реальном бою, в следующей главе.
Как решить1pxвопрос
я здесьПочему мы часто говорим о проблеме 1px, а не 2pxКак указано в статье, если
UIКогда требования не высоки,1pxНа самом деле это не проблема, часто в проекте много сравнений.1pxНам нужно исправить более важные ошибки, но понять1pxСуть его помогает нам понять принцип адаптации мобильного терминала
Решения
既然1个css像素代表两个物理像素,设备又不认0.5px的写法,那就画1px,然后再想尽各种办法将线宽减少一半。Основываясь на этом мышлении, у нас есть следующие решения
Изображение Дафа и градиент фона
Принципы этих двух схем одинаковы, обе из них заключаются в том, чтобы настроить половину элементов как цветную, а половину как прозрачную, например, сделать2pxвысота фото, где1pxэто цвет, который мы хотим,1pxЕсли установлено значение «Прозрачный», процесс адаптации выглядит следующим образом.
Увеличить Дафа
Слишкомflexible 0.3.2Используемая схема адаптации
Мы можем немного изменить код
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
// 对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
// 将 <meta> 根据当前设备的 dpr 标签进行缩放
scale = 1 / dpr;
}
Принцип также очень прост, согласно соответствующемуdprОтрегулируйте соответствующий коэффициент масштабирования для достижения цели адаптации, прямое масштабирование страницы кажется немного личным.暴力
Используйте масштабирование псевдоэлементов
Увеличить всю страницу太暴力,может просто масштабировать границу?Ответ однозначно да.У нас нет transform: scaleты
.border1px{
position: relative;
&::after{
position: absolute;
content: '';
background-color: #ddd;
display: block;
width: 100%;
height: 1px;
transform: scale(1, 0.5); /* 进行缩放*/
top: 0;
left: 0;
}
}
Суммировать
В этой статье в основном объясняется общая адаптация мобильного терминала и1pxРешение, в этой главе в основном рассказывается о теории, в следующей главе мы получим адаптацию мобильного терминала, основанную на реальном бою.最佳实践,Если вам интересно, не забудьте поставить лайк и подписаться💓