Краткое описание адаптации мобильного терминала (длинный текст)

CSS

макет

  • Статическая компоновка: макет с фиксированной шириной и фиксированной высотой, не меняется с устройством и областью просмотра [фиксированная ширина и центр, ПК]
  • План потока: размер изменяется, макет не меняется, ширина использует проценты и мин/макс, высота фиксирована [система ограждений (система сетки)]
  • Адаптивная верстка: меняется размер, основной контент и верстка остаются прежними, недостатки, слишком маленький экран, контент слишком тесный (размер остается прежним, положение меняется)
  • Гибкая компоновка: размер и положение будут меняться (flex/rem/em/vw/vh)
  • Отзывчивый макет: отображаемый контент, размер и положение будут меняться, медиа-запрос + макет потоковой передачи (медиа-запрос, vw, rem/em)

Связанные концепции

Пиксели устройства

Физический пиксель экрана устройства, указывающий, сколько точек может быть размещено на экране, а не абсолютная единица длины (например, дюймы, мм); единицей измерения является пиксель, например iPhone6 ​​(750 x 1334 пикселей)

разрешение

физическая концепция
Для экранов разрешение обычно относится к сумме физических пикселей, отображаемых на экране. Например, допустим, разрешение экрана iPhone 6 (750 x 1334 пикселей)
Для изображений концепции эквивалентны размеру изображения, размеру изображения, размеру в пикселях и т. д. Например, скажем, значок (20 x 20 пикселей)

CSS-пиксели

— это концепция веб-программирования, относящаяся к логическим пикселям, используемым в коде стилей CSS или называемая设备独立像素, потому что это относится только к устройству;
1 пиксель CSS может соответствовать разным физическим пикселям на разных устройствах.Это соотношение является свойством устройства (Device Pixel Ratio), например, iPhone6: 375 x 667px.

пройти черезdocument.documentElement.clientWidth/clientHeight / document.documentElement.getBoundingClientRect().widthПолучать

В спецификации CSS единицы длины можно разделить на абсолютные и относительные единицы. px — это относительная единица относительно пикселя устройства (Device Pixels).

аппаратно-независимые пиксели (DIP) / независимые от плотности пиксели (DP)

Характеристики устройств Android заключаются в том, что существует множество размеров экрана, поэтому, чтобы отображать как можно больше независимо от устройства, предлагается dip, а эталонная плотность составляет 160.

// 当屏幕密度density为160(单位是ppi或者dpi,一个意思)时,px === dip
px = dip * density / 160 
// 所以
dip = px * 160 / density

注: 此处只针对于Android, windows 也有 DIP 概念, 含义不同, IOS貌似不存在

Соотношение пикселей устройства (DPR)

Соотношение пикселей устройства, соотношение между физическими пикселями и логическими пикселями, используемое каскадными таблицами стилей (CSS): другие названия для него — «Соотношение пикселей CSS» и «dppx». Указывает, что 1 CSS-пиксель (ширина) равен нескольким физическим пикселям (ширине).

DPR = 物理像素(设备像素) / 逻辑像素(css像素/设备独立像素) // [未缩放]

плотность пикселей

Плотность пикселей также называется плотностью дисплея или плотностью экрана, сокращенно DPI (точек на дюйм) или PPI (пикселей на дюйм).

// 屏幕对角线的像素尺寸 / 物理尺寸(inch 英寸)
Math.sqrt(750*750 + 1334*1334) / 4.7 = 326ppi

окно просмотра

Ширина области просмотра равна ширине браузера на компьютере, но отличается на мобильных устройствах.

видовой экран макета

Чтобы разместить веб-сайты, предназначенные для настольных браузеров на мобильных телефонах, ширина окна просмотра макета по умолчанию намного больше, чем ширина экрана, чтобы пользователи могли видеть полную картину веб-сайта, он уменьшит размер веб-сайта. document.documentElement.clientWidth

Визуальный вьюпорт

Видимая область экрана, то есть физический размер пикселя, является переменной величиной и связана с текущим значением масштабирования и шириной экрана устройства.visual viewport宽度 = ideal viewport宽度 / 当前缩放值в состоянии пройтиwindow.innerWidthчтобы получить его, но он не получает его правильно в Android 2, Oprea mini и UC 8.

идеальное окно просмотра

Идеальный вьюпорт — это тот вьюпорт, который наиболее подходит для мобильных устройств, а ширина идеального вьюпорта равна ширине экрана мобильного устройства. В мобильной разработке, в meta[name='viewport'], черезwidth = device-widthУстановите текущую ширину области просмотра на идеальную область просмотра, в противном случае ширина по умолчанию будет равна 980 области просмотра макета.

Идеальное окно просмотра не имеет фиксированного размера, и разные устройства имеют разные идеальные окна просмотра. Идеальным окном просмотра для всех ранних iPhone было 320x480px.

Таким образом, без масштабирования ширина экрана в пикселях CSS фактически равна ширине идеального окна просмотра, а метатег:

<meta name="viewport" content="width=device-width, inital-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

Окно просмотра макета = задано идеальное окно просмотра, масштабирование отключено. Таким образом, после добавления метаданных окна просмотра width=device-width страница становится больше (содержимое страницы слишком маленькое, чтобы его можно было увидеть поначалу), на самом деле окно просмотра макета становится меньше.

initial-scale=1 решает ширину идеального окна просмотра, когда iphone и ipad устанавливают ширину вертикального экрана независимо от вертикального или горизонтального экрана width=device-width решает ширину идеального окна просмотра, когда IE устанавливает ширину в книжную, независимо от альбомной или портретной.

Отношение визуального окна просмотра и идеального окна просмотра:

visual viewport宽度 = ideal viewport宽度 / 当前缩放值
当前缩放值 = ideal viewport宽度 / visual viewport宽度

Ссылаться на:www.ayqy.net/blog/ Полностью понимаю px… GitHub.com/jawIL/блог/…

rem (Font size of the root element)

Относительная единица длины. Воздействовать на корневой элемент относительно размера начального значения/значения по умолчанию; область некорневого элемента относительно размера шрифта html корневого элемента (обычно используется)

em

Font size of the parent, in the case of typographical properties like font-size, and font size of the element itself, in the case of other properties like width.
Действует на свойство font-size относительно размера шрифта родительского элемента (обычно используется); действует на свойство non-font-size относительно собственного размера шрифта.

План размещения

Процент + медиа-запросы

запросы средств массовой информации помещение:<meta name="viewport" content="width=device-width"/>в приятельdevice-width / width:

  • ширина устройства — это фактическая ширина устройства, которая связана только с разрешением устройства. Обычно это соотношение физических пикселей устройства к пикселям устройства, и его значение не изменится при повороте телефона, поэтому оно не подходит для разработки адаптивных веб-сайтов (логические пиксели css)
  • Ширина относится к ширине видимой области, которая связана со свойством масштаба окна просмотра, то есть шириной видимой области страницы.
    Это можно понимать как настройку окна просмотра макета на идеальное окно просмотра.

Наиболее распространенный способ различать различные устройства — по ширине экрана (ширина, описываемая в пикселях CSS):

@media (min-width:320px) { /* smartphones, portrait iPhone, portrait 480x320 phones (Android) */ }
@media (min-width:480px) { /* smartphones, Android phones, landscape iPhone */ }
@media (min-width:600px) { /* portrait tablets, portrait iPad, e-readers (Nook/Kindle), landscape 800x480 phones (Android) */ }
@media (min-width:801px) { /* tablet, landscape iPad, lo-res laptops ands desktops */ }
@media (min-width:1025px) { /* big landscape tablets, laptops, and desktops */ }
@media (min-width:1281px) { /* hi-res laptops and desktops */ }


min-width: 480px: Will target mobile devices in landscape mode and up
// 
@media screen and (min-width: 320px) {
    html {
        font-size: 50px;
    }
}
@media screen and (min-width: 360px) {
    html {
        font-size: 56px;
    }
}
@media screen and (min-width: 414px) {
    html {
        font-size: 63px;
    }
}

рем-макет

rem: размер шрифта корневого элемента (html), то есть 1rem = размер шрифта, заданный в html.

Получить ширину устройстваdocument.documentElement.getBoundingClientRect().width / document.documentElement.clientWidth

Принцип: проблема масштаба в реальном времени, фиксированное значение rem рассчитывается в соответствии с масштабом чертежа. Реализация: в основном путем изменения fontSize html

  1. напрямую импортировать [woo woo Краткое описание.com/fear/no 00 Чэнду 3506…]
   (function (doc, win) {
        var docEl = doc.documentElement,
            resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
            recalc = function () {
                var clientWidth = docEl.clientWidth;
                if (!clientWidth) return;
                if(clientWidth>=640){
                    docEl.style.fontSize = '100px';
                }else{
                    docEl.style.fontSize = 100 * (clientWidth / 640) + 'px'; // 640: 可根据设计图来定
                }
            };

        if (!doc.addEventListener) return;
        win.addEventListener(resizeEvt, recalc, false);
        doc.addEventListener('DOMContentLoaded', recalc, false);
    })(document, window);
  1. Используйте гибкий.js
    GitHub.com/Ah Trouble/Церковное право…

недостаток:

  1. проблема с iframe
  2. проблема с форматированным текстом
  3. HD-решение
  4. Некоторые модели Android несовместимы
  5. Когда системный шрифт масштабируется, он изменяется, что приводит к загромождению страницы, поскольку он тесно связан со шрифтом корневого элемента; решение: восстановление масштабирования
    1> nuggets.capable/post/684490…
    2> Добавьте следующий код на основе flexible.js:nuggets.capable/post/684490…
var root = window.document.documentElement;
var fontSize = parseFloat(root.style.fontSize);
// html最终的font-size大小 
var finalFontSize = parseFloat(window.getComputedStyle(root).getPropertyValue("font-size"));
if(finalFontSize !== fontSize) {
    root.style.fontSize = fontSize * fontSize / finalFontSize + "px";
}
  • getComputedStyle Метод Window.getComputedStyle() возвращает объект, который сообщает значения всех свойств CSS элемента после применения активной таблицы стилей и анализа любых базовых вычислений, которые могут содержаться в этих значениях. Доступ к частным значениям свойства CSS можно получить через API, предоставляемый объектом, или просто путем индексации с использованием имени свойства CSS.

  • получитьпропертивалуе Интерфейс CSSStyleDeclaration.getPropertyValue() вернет DOMString, которая будет содержать предварительно запрошенную информацию о свойствах CSS.

lib-flexible

старая версия

Код старой версии №17

例如 ios
scale=0.5
innerWidth=750
device-width=375
innerWidth * scale = (device-width = layout-viewport-width)

Процесс выглядит следующим образом:

  1. Сначала возьмите dpr (dpr = window.devicePixelRatio)
  2. Затем установите масштаб = 1/dpr
  3. Затем идет innerWidth, innerWidth = 375/scale = 750px (device-width = document.documentElement.clientWidth)
  4. Наконец, разделите innerWidth на 10rem, размер шрифта = innerWidth / 10 = 75px.
;(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 = {});
    
    if (metaEl) {
        console.warn('将根据已有的meta标签来设置缩放比例');
        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) {
        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;
    }

    docEl.setAttribute('data-dpr', dpr);
    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(){
        // 动态设置的缩放大小会影响布局视口的尺寸, 设备物理像素大小
        // 设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio * scale)
        var width = docEl.getBoundingClientRect().width; // iphone6 => 750
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        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);

    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'] = {}));

новая версия

Новый код версии 2.0

Метатег фиксируется как

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no”>

Логика кода такова: берем ширину и делим на 10rem, font-size = ширина/10

Примечание: Мобильная домашняя страница Taobao 2019-01-16, это тоже решение, но ширина = 3,75рем, размер шрифта = 100px, по оценкам, это для удобства удаления

код, добавьте комментарии

(function flexible (window, document) {
  var docEl = document.documentElement
  var dpr = window.devicePixelRatio || 1

  // adjust body font size
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px' 
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();

  // set 1rem = viewWidth / 3.6, 当设计稿360px, 更好计算
  function setRemUnit () {
    // var rem = docEl.clientWidth / 10 // 原始代码
    var rem = docEl.clientWidth / 3.6  // 修改后代码
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  // reset rem unit on page resize
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    // 参考: https://juejin.cn/post/6844904002103033870
    // 页面从浏览器的缓存中读取该属性返回 ture, 优化方案 window.performance.navigation.type
    // if (e.persisted) {  // 原始代码
    //   setRemUnit()
    // }
    if (e.persisted || (window.performance && window.performance.navigation.type === 2)) { // 修改后代码
      setRemUnit()
    }
  })

  // detect 0.5px supports 检测是否支持0.5px, 用于1px问题
  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))

vw/vh (новые свойства css3)

  • Viewport Height (vh): This unit is based on the height of the viewport.
  • Viewport Width (vw): This unit is based on the width of the viewport
  • 1vw: 1% ширины области просмотра, то есть 1% ширины области просмотра.
  • 1vh: 1% высоты области просмотра, то есть 1% высоты области просмотра
  • vmin: 1% от меньшего размера области просмотра, то есть взять наименьший Math.min(vw, vh) из vw и vh
  • vmax: 1% от большего размера окна просмотра, то есть взять максимальное значение Math.max(vw, vh) из vw и vh.

выполнить:

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
设计图尺寸:设计图元素尺寸 = 100vw:Y // Y 表示css样式中设计图某元素的大小, 单位vw

недостаток:

  • Нет максимального/минимального предела, когда экран слишком мал, шрифт или содержимое слишком малы для четкого просмотра, слишком большой - то же самое.
  • Совместимость: ios8/andorid4.4 и выше (частично поддерживается ios6/7) См. https://caniuse.com/#feat=viewport-units

vw + rem

преимущество:

  1. Реализация проста, не зависит от плагинов и сторонних библиотек и может быть достигнута с помощью нескольких строк кода CSS.
  2. Легко разрабатывать и легко конвертировать
  3. Не влияет на использование px, отлично совместим со сторонними библиотеками компонентов
  4. Нет проблем с совместимостью, таких как форматированный текст и фреймы.

выполнить: Следующая реализация делит экран на 10 равных частей, то есть ширина экрана равна 10rem, исходя из соотношения между rem и vw: rem:vw = 10:1 или 1rem = 10vw100vw === 10 rem === document.documentElementпомещение:<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />

  1. Размер шрифта html равен 1/10 ширины окна просмотра (т.е. 1rem = 1/10 * 100vw => эквивалентно document.documentElement.style.fontSize = clientWidth/10 в lib-flexible) [1/10 здесь, так как это значение также берется в схеме Taobao, для лучшего расчета можно использовать и другие значения]
// $vw_design: 设计图尺寸
// $vw_fontsize: 设计图尺寸 / 10  假设把设计图分为10份, 每份的大小(设计图的1rem), 并以此为基数
html {
  font-size: ($vw_fontsize / $vw_design) * 100vw; // 直接写 10vw

  // 同时,通过Media Queries 限制根元素最大最小值
  @media screen and (max-width: 320px) {
    font-size: 32px;
  }
  @media screen and (min-width: 540px) {
    font-size: 54px;
  }
}
  1. Рассчитать с помощью функции scss: размер элемента дизайна / (размер дизайна / 10) * 1rem
// $basesize: 设计图元素尺寸
@function rem($basesize) {
  @return ($basesize / $vw_fontsize) * 1rem; 
}

//简化
@function rem($basesize) {
  @return ($basesize / $vw_design) * 10rem; 
}

Принцип расчета:

假设设计图某元素所占视口大小为 X, 单位为: vw

设计图某元素尺寸 / 设计图尺寸 = (X)vw / 100vw 
=> (X)vw = (设计图元素尺寸 / 设计图尺寸) * 100vw 
// 转化为以rem单位的数值Y
由于 (Y)rem = (X)vw / 10 (平局分成10份,vw:rem = 10:1
=> (Y)rem = (设计图元素尺寸 / 设计图尺寸) * 10vw 

Обратите внимание на окончательный вывод, чтобы его также можно было понять следующим образом:

$design_width: 750
$divideNum: 10 //屏幕平均分成份数
@function px2rem($design_dom) {
    @return #{$design_dom/$design_width * $divideNum}rem
}

html {
    font-size: (100 / $divideNum)vw;
    //同时,通过Media Queries 限制根元素最大最小值
    @media screen and (max-width: 320 ) {
        font-size: 32;
    }
    @media screen and (min-width: 640 ) {
        font-size: 64;
    }
}

Ссылаться на:nuggets.capable/post/684490…

rem + js

js динамически устанавливает html {font-size: (clientWidth/средняя доля экрана)px}

$design_width: 750
@function px2rem($dom) {
    @return #{$dom/$design_width * 屏幕分成份数}rem
}

После предотвращения использования rem элементы без font-size наследуют font-zsize корневого элемента, сбрасывают размер шрифта тела на значение по умолчанию (обычно 16 пикселей) или используют адаптивный шрифт медиазапроса (320, 480). , 640 мобильный терминал) размер)

body {
    font-size: 16px;
}

Суммировать

Адаптивная схема макета

Увеличить макет Пользовательский опыт совместимость зависит от js Поддержка большого экрана Нужно исправить шрифт
rem+media-query Могу IOS4.1 AN2.1 ×
rem+js хорошо IOS4.1 AN2.1
rem+vw превосходно IOS6.1 AN4.4 ×
vw превосходно IOS6.1 AN4.4 × × ×

Суммировать:

  1. рем-совместимость: ios4.1/android2.1
  2. vw-совместимость: ios6.1/android4.4
  3. Когда экран большой, rem может управлять максимальным/маленьким значением размера шрифта с помощью медиа-запроса.
  4. В схеме rem нужно исправить шрифт body

разное

1px реализация

.hairlines li{
  height: 50px;
  line-height: 50px;
  border:none;
  text-align: center;
  position: relative;
  margin-top: 10px;
}
.hairlines li:after{
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  border: 1px solid #cccccc;
  // border-radius: 26px;
  width: 200%;
  height: 200%;
  -webkit-transform: scale(0.5);
  transform: scale(0.5);
  -webkit-transform-origin: left top;
  transform-origin: left top;
}

процентный расчет

  1. Используйте проценты высоты или ширины дочернего элемента относительно непосредственного родительского элемента дочернего элемента.
  2. Процент, используемый в верхней/нижней|левой/правой части дочернего элемента, относится к высоте|ширине родительского элемента, который расположен непосредственно нестационарно (позиционирование по умолчанию).
  3. Процент, используемый в отступах/марже дочернего элемента, относится к ширине непосредственного родительского элемента дочернего элемента.
  4. Процент, используемый в border-radius/translate/background-size дочернего элемента, относится к его собственной ширине | высоте

Ссылаться на:GitHub.com/Сун Маобинь/Да…