Часть 1☞Резюме и опыт адаптации мобильных терминалов и ПК-терминалов (1) (может быть более полным
Проблемы, вызванные веб-адаптацией
1. Browser mate указывает ядро
Обнаружение и идентификация метаэлементов браузера QQ. Введение в правила ядра:
Определить как ядро хрома
- тип документа стандартный
- элемент метатега
пример:
<!DOCTYPE html>
<html>
<head>
<!-- 下面3个meta中任选一个,即可正确识别 -->
<meta name="renderer" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<title>chrome core</title>
</head>
<body>
meta webkit
</body>
</html>
Определить как ядро IE
- тип документа нестандартный
- обнаружение метаэлемента
пример:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<!-- 下面3个meta中任选一个,即可正确识别 -->
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta name="renderer" content="ie-comp" />
<meta name="renderer" content="ie-stand" />
<title>ie core</title>
</head>
<body>
meta ie
</body>
</html>
Ссылка: Документация браузера QQ
2. Проблема границы 1px
Причина появления:
Согласно размеру iPhone 6, рисунку шириной 750 пикселей, эти 750 пикселей на самом деле являются пикселем устройства iPhone6, 1 пиксель, измеренный при измерении чертежа дизайна, на самом деле равен 1 пикселю устройства, и когда мы устанавливаем область просмотра макета, равную идеальной области просмотра, равной до 375px, а поскольку DPR iPhone6 равен 2, 1px при написании CSS соответствует 2 пикселям устройства, поэтому выглядит толще.
Решение
1.border-image
на основеmedia
Запрос для определения различных соотношений пикселей устройства с учетом разныхborder-image
:
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0 stretch;
}
}
2. background-image
иborder-image
Точно так же подготовьте квалифицированное фоновое изображение границы и смоделируйте его на фоне.
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2{
.border_1px{
background: url(../img/1pxline.png) repeat-x left bottom;
background-size: 100% 1px;
}
}
Оба вышеперечисленных изображения нужно подготавливать отдельно, а с закругленными углами не очень легко обращаться, но они справятся с большинством сценариев.
3. Псевдокласс + преобразование
на основеmedia
Запрос для определения соотношения пикселей разных устройств для масштабирования линии:
.border_1px:before{
content: '';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: #000;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px:before{
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border_1px:before{
transform: scaleY(0.33);
}
}
Этот метод может встречаться в различных сценариях, если вам нужно соблюсти закругленные углы, вам нужно только добавить псевдоклассы.border-radius
Вот и все.
4. Используйте svg (помощь по плагинуpostcss-write-svg
)
над намиborder-image
иbackground-image
можно смоделировать1px
Границы, но все они используют растровые изображения и должны импортироваться извне.
с помощьюPostCSS
изpostcss-write-svg
мы можем напрямую использоватьborder-image
иbackground-image
Создайтеsvg
из1px
Рамка:
@svg border_1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
После компиляции:
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
3. Адаптируйтесь к iPhoneX
Нам нужно разумно разместить верх и низ в безопасной зоне,iOS11
добавил дваCSS
функцияenv、constant
, который используется для установки расстояния между безопасной зоной и границей.
Внутри функции может быть четыре константы:
-
safe-area-inset-left
: Расстояние от безопасной зоны до левой границы -
safe-area-inset-right
: Расстояние между безопасной зоной и правой границей -
safe-area-inset-top
: Расстояние от безопасной зоны до верхней границы -
safe-area-inset-bottom
: Расстояние от безопасной зоны до нижней границы
Примечание: мы должны указатьviweport-fit
Затем вы можете использовать эти две функции:
<meta name="viewport" content="width=device-width, viewport-fit=cover">
constant
существуетiOS < 11.2
действует в версии ,env
существуетiOS >= 11.2
, что означает, что нам часто приходится устанавливать их одновременно, чтобы ограничить страницу безопасной областью:
body {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
При использовании нижних фиксированных навигационных панелей нам нужно установить ихpadding
ценность:
{
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
Детали
4. О горизонтальном экране
признание js
window.addEventListener("resize", ()=>{
if (window.orientation === 180 || window.orientation === 0) {
// 正常方向或屏幕旋转180度
console.log('竖屏');
};
if (window.orientation === 90 || window.orientation === -90 ){
// 屏幕顺时钟旋转90度或屏幕逆时针旋转90度
console.log('横屏');
}
});
CSS-распознавание
@media screen and (orientation: portrait) {
/*竖屏...*/
}
@media screen and (orientation: landscape) {
/*横屏...*/
}
5. Проблема с размытием изображения
1 причина
Большинство изображений, которые мы обычно используем, являются растровыми изображениями (png、jpg..
), растровое изображение состоит из пикселей, каждый пиксель имеет определенное положение и значение цвета:
Теоретически каждый пиксель растрового изображения отображается на экране с использованием физического пикселя для достижения наилучшего эффекта отображения.
пока вdpr > 1
На экране растрового изображения пиксель растрового изображения может быть представлен несколькими физическими пикселями, однако этим физическим пикселям нельзя точно присвоить цвет соответствующего пикселя растрового изображения, и их можно только аппроксимировать, поэтому одно и то же изображение вdpr > 1
будет размыто на экране:
2 решения
Чтобы обеспечить качество картинки, мы должны сделать так, чтобы один пиксель экрана максимально отображал один пиксель изображения, поэтому для разныхDPR
экран, нам нужно отображать картинки разного разрешения.
например: вdpr=2
дважды отображает изображение на экране(@2x)
,существуетdpr=3
на экране(@3x)
.
3 медиазапрос
использоватьmedia
Запросите и оцените различные соотношения пикселей устройства для отображения изображений с различной точностью:
.avatar{
background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.avatar{
background-image: url(conardLi_2x.png);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.avatar{
background-image: url(conardLi_3x.png);
}
}
Только для фоновых изображений
4 image-set
использоватьimage-set
:
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
Только для фоновых изображений
5 srcset
использоватьimg
помеченsrcset
свойство, браузер автоматически подберет лучшее отображаемое изображение на основе плотности пикселей:
<img src="conardLi_1x.png"
srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
6 URL-адрес изображения сшивания JavaScript
использоватьwindow.devicePixelRatio
Получите соотношение пикселей устройства, просмотрите все изображения и замените адрес изображения:
const dpr = window.devicePixelRatio;
const images = document.querySelectorAll('img');
images.forEach((img)=>{
img.src.replace(".", `@${dpr}x.`);
})
7 Использование SVG
SVG
Полное название масштабируемой векторной графики, которое отличается от растрового изображения на основе пикселей,SVG
Он относится к описанию формы изображения, поэтому по сути является текстовым файлом небольшого размера и не будет искажаться, сколько бы раз его не увеличивали.
За исключением того, что мы вручную рисуем кодsvg
, мы также можем использовать то же самое, что и растровое изображениеsvg
рисунок:
<img src="conardLi.svg">
<img src="data:image/svg+xml;base64,[data]">
.avatar {
background: url(conardLi.svg);
}
Ссылаться на:
Адаптация мобильного терминала
Адаптация мобильного терминала Toutiao
h5 связанные
что такое h5
Технология H5Коллекция мобильных веб-интерфейсов
Сама технология H5 используется длямобильная веб-страница. Поскольку само приложение имеет webview
Контейнер, в котором может быть запущен код, связанный с веб-интерфейсом, и получена комбинация H5 и собственного приложения.Технология гибридных приложений.
Общий принцип технологии гибридных приложений
Мобильный адаптивный макет
Решение первое: rem + pxToRem
принцип
- Ширина окна экрана монитора назначается
html
изfont-size
. В этом случае размер корневого шрифта будет меняться в зависимости от ширины экрана. - будет
px
преобразовать вrem
, Существуют две традиционные схемы, одна из которых заключается в использованииsass
/less
пользовательская функция вpxToRem
,Писатьpx
когда используешьpxToRem
функция преобразуется вrem
. Другой - напрямую написатьpx
, в процессе компиляции используются плагины для преобразования всехrem
. такdom
Размер элемента будет меняться в зависимости от ширины экрана.
выполнить
- Динамически обновлять размер корневого шрифта
const MAX_FONT_SIZE = 420
// 定义最大的屏幕宽度
document.addEventListener('DOMContentLoaded', () => {
const html = document.querySelector('html')
let fontSize = window.innerWidth / 10
fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize
html.style.fontSize = fontSize + 'px'
})
-
px
изменятьrem
pxToRem
Вариант первый
$rootFontSize: 375 / 10;
// 定义 px 转化为 rem 的函数
@function px2rem ($px) {
@return $px / $rootFontSize + rem;
}
.demo {
width: px2rem(100);
height: px2rem(100);
}
pxToRem
Вариант 2
существуетvue-cli3
Серединаpostcss-pxtorem
Плагинов хватает, да и на других платформах примерно такая же идея.
const autoprefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')
module.exports = {
// ...
css: {
sourceMap: true,
loaderOptions: {
postcss: {
plugins: [
autoprefixer(),
pxtorem({
rootValue: 37.5,
propList: ['*']
})
]
}
}
}
}
продолжай исследоватьpostcss-pxtoremИсходный код плагина, чтобы увидеть принцип его реализации.
function createPxReplace (rootValue, unitPrecision, minPixelValue) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels < minPixelValue) return m;
var fixedVal = toFixed((pixels / rootValue), unitPrecision);
return (fixedVal === 0) ? '0' : fixedVal + 'rem';
};
}
px
превратиться вrem
В основном эта функция, конечно, там много настраиваемых параметров, основной принцип аналогичен нашему плану. Удобство в том, что не нужно каждый раз писатьpx
Нужно добавить функцию, и код станет намного понятнее.
все элементы
px
быть преобразованным вrem
Шерстяная ткань? Это не обязательно.border
серединаpx
не должен поворачиватьсяrem
, с участием другого1px
проблем, подробно рассмотренных в предыдущей статье, избежатьpx
изменятьrem
,будетborder
серединаpx
капитализироватьPX/Px/pX
Решение второе: vh + vw
принцип
vw
Единицы измерения относительно ширины области просмотра зависят от ширины.
выполнить
Подобно rem, используйте его напрямуюpostcss-px-to-viewportПлагин настроен, и способ настройки такой же, как иpostcss-pxtoremПочти такой же.То же самое верно и для плагинов
другие решения
план | дефект | |
---|---|---|
1 | процент | Высота не может быть в процентах |
2 | Запросы СМИ +meta серединаviewport
|
Разные устройства имеют разную ширину, и коэффициент масштабирования не может быть полностью определен. |
3 | flex |
Все еще не могу решить проблему превышения ширины |
Все вышеперечисленные решения имеют фатальные недостатки, и не рекомендуется использовать их для выполнения расчетов мобильной верстки.
flex
иrem
Лучше использовать в комплексе
мобильный шаблон быстрой настройки vue
Библиотеки с открытым исходным кодом
1. библиотека компонентов Vant
В библиотеке компонентов vant по умолчанию используетсяpx
Укажите единицу измерения, используйте при необходимостиrem
, используйте плагин напрямую для идеальной адаптации.
заvw
схема, вант так же можно добавить через плагиныpx
Превратиться вvw
,заvw
Могут быть ямки.
2.ant-design-мобильная библиотека компонентов
Библиотека компонентов ant-design-mobile все еще используется.px
единица измерения
@hd: 1px; // 基本单位
// 字体尺寸
// ---
@font-size-icontext: 10 * @hd;
@font-size-caption-sm: 12 * @hd;
@font-size-base: 14 * @hd;
@font-size-subhead: 15 * @hd;
@font-size-caption: 16 * @hd;
@font-size-heading: 17 * @hd;
// 圆角
// ---
@radius-xs: 2 * @hd;
@radius-sm: 3 * @hd;
@radius-md: 5 * @hd;
@radius-lg: 7 * @hd;
@radius-circle: 50%;
// 边框尺寸
// ---
@border-width-sm: 1PX;
@border-width-md: 1PX;
@border-width-lg: 2 * @hd;
Краткое изложение проблем, с которыми столкнулся h5
1. скольжение ios не гладкое
Представление
Скольжение по странице вверх и вниз вызовет зависание, палец оторвется от страницы, и страница немедленно перестанет двигаться. Общая характеристика заключается в том, что скольжение не является плавным и отсутствует инерция скольжения.
причина
Почему свайп не плавный в веб-просмотре iOS и как он определяется?
Оказывается, в iOS 5.0 и более поздних версиях для скольжения определены два значения.auto
иtouch
, значение по умолчаниюauto
.
-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
-webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */
решение
1. Добавьте метод касания прокрутки в контейнер прокрутки.
будет-webkit-overflow-scrolling
установлено значениеtouch
.wrapper {
-webkit-overflow-scrolling: touch;
}
Установите полосу прокрутки, чтобы скрыть:
.container ::-webkit-scrollbar {display: none;}
может привести к использованиюposition:fixed;
Фиксированные позиционированные элементы, которые прокручиваются вместе со страницей
2. Установить переполнение
установить внешнийoverflow
заhidden
, установите элемент содержимогоoverflow
заauto
. Если внутренний элемент выходит за пределы тела, происходит прокрутка, а часть за пределами тела скрывается.
body {
overflow-y: hidden;
}
.wrapper {
overflow-y: auto;
}
Сочетание этих двух продуктов еще лучше!
2. Раскрывающийся список границ выдвижения iOS отображается белым пустым
Представление
Нажмите и удерживайте палец на экране, чтобы потянуть вниз, и в верхней части экрана появится белая область. Нажмите и удерживайте палец на экране и потяните вверх, внизу появится лишняя белая область.
причина
В iOS перетаскивание пальца вверх и вниз по экрану вызываетtouchmove
событие. Объектом, вызванным этим событием, является весьwebview
Контейнер, контейнер естественно будет перетаскиваться, а остальное будет пустым.
решение
1. Отслеживайте события, чтобы запретить скольжение
Существует три события мобильного касания, которые определяются как
1. touchstart :手指放在一个DOM元素上。
2. touchmove :手指拖曳一个DOM元素。
3. touchend :手指从一个DOM元素上移开。
Очевидно, что нам нужно контролироватьtouchmove
событие
touchmove
Скорость событий определяется реализацией и зависит от аппаратных возможностей и других деталей реализации.
preventDefault
метод, который предотвращает все действия по умолчанию, такие как прокрутка, в одной и той же точке взаимодействия.
Из этого мы нашли решение, слушаяtouchmove
, позволяйте скользить там, где вам нужно скользить, и запрещайте скользить там, где вам не нужно скользить.
Стоит отметить, что мы хотим отфильтровать элементы с контейнерами прокрутки.
Реализация выглядит следующим образом:
document.body.addEventListener('touchmove', function(e) {
if(e._isScroller) return;
// 阻止默认事件
e.preventDefault();
}, {
passive: false
});
2. Компромиссы прокрутки заполняют пробелы и украшают другими функциями
Во многих случаях мы не можем решить эту проблему и изменить свой образ мышления. Судя по сцене,Мы можем использовать раскрывающийся список как функциональное действие.
Например: Обновить страницу после потянув вниз
3. Неопределенное поведение при увеличении или уменьшении масштаба страницы
Представление
Дважды коснитесь или сведите пальцы на элементе страницы, и страница увеличится или уменьшится.
причина
Сам HTML будет генерировать поведение увеличения или уменьшения масштаба Например, в браузерах ПК вы можете свободно управлять увеличением или уменьшением масштаба страницы. Но на мобильных устройствах нам такое поведение не нужно. Поэтому нам нужно запретить это неопределенное поведение, чтобы улучшить взаимодействие с пользователем.
Принципы и решения
HTML meta
В стандарте метатега естьviewport
Атрибут, используемый для управления масштабом страницы, обычно используемый на мобильных терминалах. Как показано на следующем рисунке, MDN
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Таким образом, мы можем установитьmaximum-scale
,minimum-scale
иuser-scalable=no
чтобы избежать этой проблемы
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0, user-scalable=no">
Предотвратить увеличение страницы (когда мета не работает)
window.addEventListener(
"touchmove",
function (event) {
if (event.scale !== 1) {
event.preventDefault();
}
},
{ passive: false }
);
4. Задержка события клика и проникновение
Представление
элемент прослушиванияclick
событие, щелчок по элементу вызывает временную задержку прибл.300ms
.
Щелкните слой маски, после того как слой маски исчезнет, нижележащий элемент щелкнет для срабатывания.
причина
Почему есть задержка клика?
В сафари в iOS, чтобы реализовать операцию двойного нажатия для увеличения, после 300 мс клика, если нет второго клика, выполнитеclick
Щелкните Действие. То есть определить, вызвано ли поведение пользователя двойным щелчком мыши. Однако в приложении независимо от того, требуется ли двойное касание для увеличения,click
Каждый клик имеет задержку 300 мс.
Почему происходит проникновение клика?
При наложении двухслойных элементов привязывать к верхнему элементуtouch
событие, привязка нижнего элементаclick
событие. так какclick
произошло вtouch
После этого нажмите на верхний элемент, элемент исчезнет, а сработает нижний элементclick
событие, приводящее к эффекту клика.
Принципы и решения
Решение 1. Замените щелчок на сенсорный запуск
Как упоминалось ранее, мобильные устройства поддерживают не только клики, но и несколько сенсорных событий. Итак, наша основная идея сейчас состоит в том, чтобы использоватьtouch
событие вместоclick
событие.
будетclick
заменитьtouchstart
не только решенclick
События все отложены, а проблема с проникновением тоже решена. Потому что проблема проникновения вtouch
иclick
Генерируется при смешивании.
использовать в родном
el.addEventListener("touchstart", () => { console.log("ok"); }, false);
использовать в vue
<button @touchstart="handleTouchstart()">点击</button>
Решения с открытым исходным кодом также предоставляютclick
мероприятие, которое обеспечиваетtouchstart
событие. как в вантеbutton
компоненты
Итак, можно лиclick
события заменены наtouchstart
Шерстяная ткань? Почему фреймворки с открытым исходным кодом по-прежнему даютclick
А события?
Давайте представим ситуацию, которая требует одновременного нажатия и смахивания. еслиclick
заменитьtouchstart
Что случится?
Последовательность триггера события:
touchstart
,touchmove
,touchend
,click
.
Легко представить, что когда мне нужноtouchmove
При скольжении срабатывает первымtouchstart
Событие click уже вызвало конфликт?
Итак, в случае прокрутки рекомендуется использоватьclick
иметь дело с.
В следующихfastclick
Библиотека с открытым исходным кодом также выполнила следующую обработку.
Основная цель – использоватьtouchstart
синтезclick
событие, убедитесь, что оно не находится под прокручиваемым родительским элементом.
Решение второе: используйте библиотеку fastclick
использоватьnpm/yarn
использовать после установки
import FastClick from 'fastclick';
FastClick.attach(document.body, options);
Аналогичным образом используйтеfastclick
После библиотеки,click
Проблемы с задержкой и проникновением исчезли
По моей практике, раз речь идет о открытой библиотеке, то надо понимать принцип ее реализации. В основном он инкапсулирует существующую собственную коллекцию событий в более совместимую коллекцию событий.
исходный код фасткликаКод ядра небольшой, менее 1000 строк. Интересно узнать!
5. Проблема в том, что программная клавиатура толкает страницу вверх, загибает ее, но не откидывает назад
Представление
На телефоне Android коснитесьinput
Когда поле отображается, клавиатура всплывает и толкает страницу вверх, в результате чего стиль страницы становится загроможденным.
При удалении фокуса клавиатура убирается, область клавиатуры остается пустой и не откидывается назад.
причина
У нас будет фиксированное дно в макете приложения. В некоторых версиях Android вылезет всплывающее окно ввода, которое распаковываетabsolute
иfixed
Позиционируемый элемент. Уменьшает видимую область и загромождает макет.
Принципы и решения
план 1:
Мониторинг события ввода вне фокуса, откат назад, когда он не в фокусе
/iphone|ipod|ipad/i.test(navigator.appVersion) &&
document.addEventListener(
"blur",
(event) => {
// 当页面没出现滚动条时才执行,因为有滚动条时,不会出现这问题
// input textarea 标签才执行,因为 a 等标签也会触发 blur 事件
if (
document.documentElement.offsetHeight <= document.documentElement.clientHeight &&
["input", "textarea"].includes(event.target.localName)
) {
document.body.scrollIntoView(); // 回顶部
}
},
true
);
Сценарий 2:
Решение для программной клавиатуры, толкающей страницу вверх, в основном заключается в отслеживании изменения высоты страницы и принудительном восстановлении ее высоты до всплывающего окна.
// Это должно быть изменено на стиль, атрибут высоты
// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function(){
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if(resizeHeight < originalHeight ){
// 恢复内容区域高度
// const container = document.getElementById("container")
// 例如 container.style.height = originalHeight;
}
}
Проблема, связанная с тем, что клавиатура не может вернуться назад, возникает в iOS 12+ и wechat 6.7.4+ и является относительно распространенной ошибкой при разработке WeChat H5.
Принцип совместимости, 1. Определить тип версии 2. Изменить видимую область прокрутки
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
// 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
window.scrollTo(x-coord, y-coord)
,вwindow.scrollTo(0, clientHeight)
Вернуться к исходному видовому экрану
6. Проблема с адаптацией безопасной зоны для iPhone серии X
Представление
По бокам или внизу челки на голове есть челка, закрывающая текст, или пустое место на черном или белом фоне.
причина
iPhone X и его серия выше, все используютЛю Хайпин дизайниполноэкранные жесты. Голова, низ и бока нуждаются в специальной обработке. Чтобы адаптироваться к особой ситуации iPhone X.
решение
Настройте безопасную область, заполните опасную область и не выполняйте операции и не отображайте содержимое в опасной области.
Опасная область относится к неровной области головы, области горизонтальной полосы внизу, а также левой и правой триггерным областям.
Конкретными операциями являются:viewport-fit
,meta
Метка установлена наcover
, чтобы получить заливку всех областей. Определяем принадлежность устройства к iPhone X, добавляем в низ головыадаптационный слой
viewport-fit
Есть 3 значения:
auto
: это значение не влияет на исходный порт просмотра макета, и вся веб-страница доступна для просмотра.contain
: область просмотра масштабируется, чтобы соответствовать самому большому прямоугольнику, отображаемому в строке.cover
: область просмотра масштабируется для заполнения экрана устройства. настоятельно рекомендуетсяsafe area inset
переменная, чтобы важный контент не отображался за пределами дисплея.
Установите для окна просмотра значениеcover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
Добавьте адаптационный слой
использоватьsafe area inset
Переменная
/* 适配 iPhone X 顶部填充*/
@supports (top: env(safe-area-inset-top)){
body,
.header{
padding-top: constant(safe-area-inset-top, 40px);
padding-top: env(safe-area-inset-top, 40px);
padding-top: var(safe-area-inset-top, 40px);
}
}
/* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-bottom)){
body,
.footer{
padding-bottom: constant(safe-area-inset-bottom, 20px);
padding-bottom: env(safe-area-inset-bottom, 20px);
padding-top: var(safe-area-inset-bottom, 20px);
}
}
safe-area-inset-top
,safe-area-inset-right
,safe-area-inset-bottom
,safe-area-inset-left
safe-area-inset-*
Четыре прямоугольника, которые определяют внутренний прямоугольник края окна просмотраtop
,right
,bottom
иleft
переменные окружения, чтобы содержимое можно было безопасно размещать без риска быть обрезанным непрямоугольным дисплеем.Для прямоугольного окна просмотра, такого как обычный монитор ноутбука, значение равно нулю.
Для непрямоугольных дисплеев (таких как круглые циферблаты,
iPhoneX
На экране все видно в пределах прямоугольника, образованного четырьмя значениями, заданными пользовательским агентом.
вenv()
Использование env(<custom-ident>
, <declaration-value>
? ), первый параметр — это настраиваемая область, а второй — альтернативное значение.
вvar()
Использованиеvar(<custom-property-name> , <declaration-value>?)
, роль вenv()
Дает альтернативное значение на случай, если оно не подействует.
constant()
одеялоcss
2017-2018 находится в стадии проекта, неизвестно, стандартизирован ли он. Неизвестно, существует ли эта функция в других версиях браузера iOS и добавлена ли она как совместимый процесс.
Подробности смотрите в ссылках в конце статьи.
7. Страница генерируется как картинка и проблема с QR-кодом
Представление
По работе возникает необходимость генерировать картинки или QR-коды для страниц. Возможно, первое, о чем мы думаем, это то, что его проще передать бэкенду для генерации. Но таким образом нам нужно передать весь код страницы на серверную часть, что потребляет слишком много сетевой производительности.
решение
Сгенерировать QR-код
Генерация QR-кода с помощью QRCode
import QRCode from 'qrcode';
// 使用 async 生成图片
const options = {};
const url = window.location.href;
async url => {
try {
console.log(await QRCode.toDataURL(url, options))
} catch (err) {
console.error(err);
}
}
будетawait QRCode.toDataURL(url, options)
присвоить изображениюurl
Просто
сгенерировать изображение
в основном используютhtmlToCanvas
генерироватьcanvas
холст
import html2canvas from 'html2canvas';
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
Но это не только здесь, потому что этоcanvas
причина. Изображения, генерируемые мобильным терминалом, относительно размыты.
мы используем новыйcanvas
Метод сгенерирован несколько раз, поместите его в двойной контейнер для достижения более четкого эффекта и загрузите картинку по гиперссылке.Загрузите файл для простой реализации и обновите его позже для более полной реализации.
const scaleSize = 2;
const newCanvas = document.createElement("canvas");
const target = document.querySelector('div');
const width = parseInt(window.getComputedStyle(target).width);
const height = parseInt(window.getComputedStyle(target).height);
newCanvas.width = width * scaleSize;
newCanvas.height = widthh * scaleSize;
newCanvas.style.width = width + "px";
newCanvas.style.height =width + "px";
const context = newCanvas.getContext("2d");
context.scale(scaleSize, scaleSize);
html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) {
// 简单的通过超链接设置下载功能
document.querySelector(".btn").setAttribute('href', canvas.toDataURL());
}
Установите по мере необходимости
scaleSize
размер
8. Проблема с общим доступом к учетной записи WeChat
Представление
При разработке официальной учетной записи WeChat H5, если вы нажмете кнопку «Поделиться» внутри страницы для вызова SDK, метод не сработает.
решение
Добавьте слой маски, сделайте руководство по обмену.
Потому что нажатие кнопки «Поделиться» внутри страницы не может быть вызвано напрямую, а для работы функции общего доступа необходимо щелкнуть больше в правом верхнем углу.
9. Решения, связанные с H5 Call SDK
Родная связь с H5
решение
использоватьDSBridge
Поддерживает как iOS, так и Android
Документацию см. Ссылки
Команда SDK предоставляет методы
- Способ регистрации
bridge.register
bridge.register('enterApp', function() {
broadcast.emit('ENTER_APP')
})
- метод обратного вызова
bridge.call
export const getSDKVersion = () => bridge.call('BLT.getSDKVersion')
Мониторинг событий и запуск
const broadcast = {
on: function(name, fn, pluralable) {
this._on(name, fn, pluralable, false)
},
once: function(name, fn, pluralable) {
this._on(name, fn, pluralable, true)
},
_on: function(name, fn, pluralable, once) {
let eventData = broadcast.data
let fnObj = { fn: fn, once: once }
if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
eventData[name].push(fnObj)
} else {
eventData[name] = [fnObj]
}
return this
},
emit: function(name, data, thisArg) {
let fn, fnList, i, len
thisArg = thisArg || null
fnList = broadcast.data[name] || []
for (i = 0, len = fnList.length; i < len; i++) {
fn = fnList[i].fn
fn.apply(thisArg, [data, name])
if (fnList[i].once) {
fnList.splice(i, 1)
i--
len--
}
}
return this
},
data: {}
}
export default broadcast
Обратите внимание на то, чтобы наступить на яму
Прежде чем вызывать метод, убедитесь, что SDK предоставляет этот метод. Если Android предоставляет этот метод, метод появится в iOS.Ошибка вызова и другие всплывающие окна. Как это решить?
Предоставьте решение, является ли Android, iOS. Судя по устройству
export const hasNativeMethod = (name) =>
return bridge.hasNativeMethod('BYJ.' + name)
}
export const getSDKVersion = function() {
if (hasNativeMethod('getSDKVersion')) {
bridge.call('BYJ.getSDKVersion')
}
}
Для одной и той же функции требуются iOS и Android с одинаковым именем метода, с которым проще работать.
10.H5 Стратегии решения, связанные с отладкой
Представление
Отладочный код обычно делается дляПросмотр данныхиПоиск ошибок. Существует два сценария: один — отладка во время разработки и тестирования, а другой — отладка в производственной среде.
Зачем отлаживать в производственной среде? Иногда ошибка не может быть воспроизведена в тестовой среде, а тестовая среда несовместима с производственной средой, в этом случае требуется экстренная отладка производственной среды.
При разработке на стороне ПК мы можем напрямую выйти из консоли и использовать инструменты, предоставляемые браузером, для работы с инструментами разработки или просмотра журналов. Но что мы делаем внутри приложения?
Принципы и решения
1. vconsole
консольный плагин
Он также очень прост в использовании
import Vconsole from 'vconsole'
new Vconsole()
Заинтересованы в том, чтобы увидеть основные принципы его реализации, наше внимание должно быть сосредоточено наКак vsconsole распечатывает все наши журналы Виртуальная консоль Tencent с открытым исходным кодом
Вышеупомянутый метод предназначен только для разработки и тестирования.Это не разрешено в производственной среде, поэтому при его использовании необходимо оценивать среду.
import Vconsole from 'vconsole'
if (process.env.NODE_ENV !== 'production') {
new Vconsole()
}
2. Агент + шпион-отладчик
Операция немного хлопотная, но распишу подробно, примерно разделив на 4 шага
- Установите плагин (глобальная установка)
sudo npm install spy-debugger -g
- Мобильный телефон и компьютер подключены к одному и тому же Wi-Fi, а мобильный телефон настроен как прокси.
Установите HTTP-прокси мобильного телефона, IP-адрес прокси-сервера будет равен IP-адресу ПК, а портspy-debugger
стартовый порт
порт по умолчанию для шпионского отладчика: 9888
Android: Настройки - WLAN - долгое нажатие для выбора сети - изменить сеть - дополнительно - настройки прокси - вручную
IOS: Настройки - Wi-Fi - Выберите сеть, нажмите восклицательный знак, HTTP-прокси вручную
- Мобильный телефон открывает страницу H5 в браузере или приложении.
- Откройте веб-сайт журнала рабочего стола для отладки и щелкните адрес прослушивания консоли npm. Просмотр захвата пакетов и структуры страницы H5
Этот метод может отлаживать страницы сгенерированной среды без изменения кода и может удовлетворить большинство потребностей в отладке.
12 Сводка проблем с мобильным 100вх
Описание проблемы:
На прокручивающемся мобильном терминале требуется полноэкранная прокрутка (с помощью swiper).Поскольку высота мобильного терминала является переменной, используется макет 100vh, который очень гармоничен в симуляторе.В результате было обнаружено, что в мобильный терминал Браузеры Chrome и WeChat/safari, так как панель браузера и некоторые заголовки панели навигации вызывают различное отображение
Рендеринг 1: высота плагина swiper установлена на innerHeight, что приводит к сбою браузера WeChat при прокрутке.
Рендеринг 2: 100vh фактически превышает высоту экрана, что приводит к блокировке некоторого контента.
Причина появления:
лучше избегать100vh
Но зависимыйjavascript
чтобы установить высоту для полного просмотра окна просмотра.
Основная проблема заключается в том, что мобильные браузеры (Chrome и Safari) имеют функцию «справки», в которой адресная строка иногда видна, а иногда скрыта, изменяя видимый размер области просмотра,
Эти браузеры не100vh
высота подстраивается под видимую часть экрана при изменении высоты области просмотра, вместо100vh
Установите высоту браузера, чтобы скрыть адресную строку. В результате, когда адресная строка видна, нижняя часть экрана будет обрезана, нарушая100vh
первоначальное намерение.
Рендер 3:
Когда мы используем браузер iOS Safari, панель инструментов и адресная строка будут скрыты при пролистывании страницы.
Когда страница скользит вверх, панель инструментов будет скрыта, а window.innerHeight в это время изменится, но vh в css не изменится, 100vh = window.innerHeight, когда панель инструментов скрыта. (В IphoneXR window.innerHeight = 719px, когда панель инструментов отображается, и window.innerHeight = 833px, когда панель инструментов скрыта)
Не имеет значения, если ваша страница изначально спроектирована как длинная страница с возможностью перелистывания, но если ваша страница будет одностраничным приложением только с одним размером области просмотра, возникнут проблемы. потому что даже если вы установите
width: 100%
, страница все равно будет прокручиваться, а когда прокрутка вверх достигнет определенного порога, панель инструментов будет скрыта, а макет будет совершенно хаотичным. И высота панели инструментов также отличается в альбомной и портретной ориентации.Кроме того, если мы установим абсолютные или фиксированные атрибуты для элементов, чтобы зафиксировать их внизу, Safari не будет делать то, что мы хотим. Как упоминалось выше, часть вашей страницы фактически заблокирована панелью инструментов внизу, поэтому элементы, которые мы установили внизу, также будут заблокированы панелью инструментов.
Некоторые решения:
1. Используйте calc для динамического расчета высоты объектов, заблокированных навигацией (не пробовал)
min-height: calc(100vh - 0.9rem) //0.9rem是挡住的高度
2. Используйте js для динамической установки высоты
установить высоту наwindow.innerHeight
правильно установит высоту видимой части окна. Если адресная строка видна, тоwindow.innerHeight
это высота всего экрана. Если адресная строка скрыта, тоwindow.innerHeight
будет высотой видимой части экрана,
3. Используйте в проекте vue
${app}/src/app.vue
mounted() {
// First we get the viewport height and we multiple it by 1% to get a value for a vh unit
let vh = window.innerHeight * 0.01
// Then we set the value in the --vh custom property to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`)
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
let vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
},
${app}/views/foo.vue
<style lang="scss" scoped>
.container {
height: 100vh; /* 在之前设置为100vh,可以兼容某些不支持自定义属性的浏览器。*/
height: calc(var(--vh, 1vh) * 100 - 46px);
</style>
4. Используйтеheight:100%
Установите высоту на 100% для каждого уровня под телом.
* {
padding: 0;
margin: 0;
border: 0;
outline: 0;
box-sizing: border-box;
}
html {
width: 100%;
height: 100%;
border: 5px solid red;
overflow: hidden;
//没试验 明天实验一下
height:-webkit-fill-available;
}
5. В сафари динамически определяйте высоту, используйте css
Высота панели инструментов составляет 75 пикселей, а свойство вычисления calc несовместимо с более ранней версией Safari. Вы можете использовать метод 4.
Установите высоту на 100% для каждого уровня под телом.
calc(100vh - 75px)
6. Что касается родительского контейнера, у которого нет высоты, высота дочернего элемента: 100%, что приводит к сворачиванию содержимого.
Описание сцены:
<head>
<style>
.app { width: 100%;height: 100%;display: flex;flex: 1;flex-direction: column; }
header { width: 100%;height: 75px; }
main { flex: 1; }
iframe { width: 100%;height: 100%;}
</style>
</head>
<body>
<div class="app">
<header></header>
<main>
<iframe v-if="true"></iframe>
<div v-else></div>
</main>
</div>
Родительский элемент с высотой в процентах должен иметь определенную высоту и свойство высоты. В противном случае элемент с высотой в процентах должен по умолчанию иметь высоту: авто (высота содержимого).
Chrome автоматически компенсирует это, но Safari сочтет это недостатком, родительский элемент iframe не имеет заданной высоты, что напрямую приводит к сворачиванию высоты iframe (с высотой содержимого). Поэтому, когда окно браузера растягивается, фактическая высота содержимого iframe изменяется, что приводит к проблеме.
решение:
- Укажите высоту для данного родителя
main { flex: 1;height: calc(100% - 75px); }
height: calc(100vh - calc(100vh - 100%))
- Укажите высоту непосредственно дочернему элементу iframe
iframe { width: 100%; height: calc(100vh - 75px); }
Здесь нет необходимости в 100% - 75px, потому что 100% зависит от указанной высоты родителя, а vh напрямую зависит от браузера, а не от высоты окна.
7. Используйте -webkit-fill-available
(сафари бесполезно)
CSS
body {
min-height: 100vh;
/* mobile viewport bug fix */
min-height: -webkit-fill-available;
}
html {
height: -webkit-fill-available;
}
body {
display: flex;
flex-direction: column;
margin: 0;
min-height: 100vh;
}
main {
flex: 1;
}
8. Идеальное решение
<template>
<div class="module">
<div class="module__item">20%</div>
<div class="module__item">40%</div>
<div class="module__item">60%</div>
<div class="module__item">80%</div>
<div class="module__item">100%</div>
</div>
</template>
<script>
export default {
mounted() {
// First we get the viewport height and we multiple it by 1% to get a value for a vh unit
const vh = window.innerHeight * 0.01
// Then we set the value in the --vh custom property to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`)
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
const vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
}
}
</script>
<style>
body {
background-color: #333;
}
.module {
height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
margin: 0 auto;
max-width: 30%;
}
.module__item {
align-items: center;
display: flex;
height: 20%;
justify-content: center;
}
.module__item:nth-child(odd) {
background-color: #fff;
color: #f73859;
}
.module__item:nth-child(even) {
background-color: #f73859;
color: #f1d08a;
}
</style>
13 Сводка проблем браузера сафари
1. Высота входного тега в сафари по умолчанию
Выполняя совместимость с браузером, я обнаружил, что высота входного тега в браузере Safari Apple всегда используется по умолчанию.Решение в настоящее время состоит в том, чтобы добавить атрибут line-height для его установки;
Если настройка высоты ввода в браузере Safari не работает, обязательно установите высоту строки, а затем удалите собственный стиль пользовательского интерфейса iOS: -webkit-appearance: none;
14 Проблемы с гибкой версткой (расширение)
Каждый модульный блок в контейнере называется flex-элементом.
Пространство шпинделя: основной размер
Пространство поперечной оси: поперечный размер
1. гибкий контейнер
div{ display: flex | inline-flex; }
После установки гибкого макета в это время свойства float, clear и vertical-align дочерних элементов будут недействительными.
Высота div, где находится flex:1, адаптируется к оставшейся высоте экрана.
2. 6 свойств, установленных для контейнера flex
1. flex-direction: определяет направление главной оси (т.е. направление расположения элементов)
.container {
flex-direction: row(默认) | row-reverse | column | column-reverse;
}
2. flex-wrap: определяет, могут ли элементы в контейнере быть обернуты
.container {
flex-wrap: nowrap(默认) | wrap(项目主轴总尺寸超出容器时换行,第一行在上方) | wrap-reverse;(反向)
}
- flex-flow: сокращение для flex-direction и flex-wrap.(Бесполезный)
4. justify-content: определяет выравнивание элемента по главной оси.
.container {
justify-content:
flex-start(默认值 左对齐)
| flex-end(右对齐)
| center
| space-between(两端对齐,只有两行的时候,分别在首尾)
| space-around(每个项目两侧的间隔相等,项目之间的间隔比项目与边缘的间隔大一倍)
| space-evenly 子元素会均匀分布在容器内,同时额外的空间将会被子元素的两侧所分享
}
Помнитеjustify-content
только вКогда в коробке осталось место для размещенияИграть роль.
5. align-items: определяет выравнивание элементов по поперечной оси.
.container {
align-items:
stretch(默认值):如果项目未设置高度或者设为 auto,将占满整个容器的高度。
flex-start (顶点对齐)
flex-end (尾点对齐)
center
baseline (项目的第一行文字的基线对齐)
}
6. align-content: определяет выравнивание нескольких осей.Если элемент имеет только одну ось, это свойство не будет работать
.container {
align-content: flex-start | flex-end | center | space-between | space-around | stretch(默认值);
}
Когда вы устанавливаете flex-wrap на nowrap, у контейнера есть только одна ось, и, поскольку элементы не переносятся, не будет нескольких осей.
Когда вы устанавливаете flex-wrap для переноса, в контейнере может быть несколько осей, поэтому вам нужно установить выравнивание между несколькими осями.
Выравнивание такое же, как и для justify-contentОба конца/середина/эквидистантное выравнивание и т. д.
3. Свойства элемента Flex
1. порядок: определяет порядок элементов в контейнере. Чем меньше значение, тем выше порядок. Значение по умолчанию — 0.
Порядок установлен так, чтобы он мог выйти на передний план.
2. flex-basis: определяет пространство главной оси, занимаемое элементом, до выделения лишнего пространства Браузер вычисляет, есть ли на главной оси избыточное пространство в соответствии с этим свойством.
Значение по умолчанию: авто, которое является исходным размером элемента.В настоящее время ширина и высота элемента зависят от значения ширины или высоты.
Когда главная ось горизонтальна, когда установлен flex-basis, значение настройки ширины элемента будет недействительным. flex-basis необходимо использовать в сочетании с flex-grow и flex-shrink, чтобы быть эффективным.
- Когда значение flex-basis равно 0 %, считается, что элемент имеет нулевой размер, поэтому даже объявление размера 140 пикселей бесполезно.
- Когда значение flex-basis установлено автоматически, тогда заданное значение в соответствии с размером (если оно равно 100 пикселей), 100 пикселей не будут включены в оставшееся пространство.
3. flex-grow: определите коэффициент увеличения элемента.
Значение по умолчанию равно 0, т.е. если осталось место, не увеличивать
Когда все элементы расположены со значением flex-basis, остается еще место, тогда в игру вступает flex-grow.
Если все элементы имеют свойство flex-grow, равное 1, они будут делить оставшееся пространство поровну. (если так)
Если один элемент имеет свойство flex-grow, равное 2, а все остальные элементы равны 1, первый займет в два раза больше оставшегося места, чем другие элементы.
Конечно, если вы обнаружите, что после расстановки всех элементов со значением flex-basis места не хватает, а flex-wrap:nowrap, flex-grow в это время работать не будет, то вам нужно следующее свойство.
4. flex-shrink: определяет коэффициент уменьшения элемента.
По умолчанию: 1, т.е. элемент будет сжиматься, если не хватит места, отрицательные значения на это свойство не влияют.
Если свойство flex-shrink одного элемента равно 0, а других элементов равно 1, первый не будет сжиматься при недостатке места.
5. flex: сокращение от flex-grow, flex-shrink и flex-basis.
.item{
flex: <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
0 1 auto(默认)
}
Они следующие:
1. Когда значение flex является неотрицательным числом, число является значением flex-grow, flex-shrink равно 1, а flex-basis равно 0%.
.item {flex: 1;} (等分剩余空间)
//等价于
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
}
2. Когда значение flex равно 0, соответствующие три значения равны 0 1 0%
.item {flex: 0;}(存在剩余空间,也不放大)
//等价于
.item {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 0%;
}
Наконец, пожалуйста, господа多多关注
~~~ Я всегда буду стараться обновляться!!Будь квалифицированным носильщиком (смеется)
В этой статье есть ссылки на множество отличных статей других больших парней~ Некоторые ссылки можно не указывать, если есть какие-то пропуски, обязательно восполняйте ❤
(*^▽^*)
В следующей главе я планирую поделиться высокочастотными тестовыми сайтами и ответами, появившимися в недавних интервью~!