注册
web

前端适配:你一般用哪种方案?

前言


最近在公司改bug,突然发现上一个前端留下的毛病不少,页面存在各种适配问题,为此甲方爸爸时常提出宝贵意见!


你的页面是不是时常是这样:


侧边栏未收缩时:
image.png


收缩后:


image.png


这样(缩小挤成一坨):


image.png


又或是这样:


image.png


那么废话不多说,今天由我不是程序猿kk为大家讲解一些前端必备知识:适配工作。


流式布局


学会利用相对单位(例如百分比,vh或是vw),而不是只会用px一类固定单位设计布局,前言中提到的收缩后多出一大块空白,就是由于写死了宽度,例如1000px或是89vw,那么当侧边栏进行收缩,右边内容宽度还是只有89个vw,因此我们可以将其更改为100%,这样不论侧边栏是否收缩,内容都会占满屏幕的全部。


.map {
width: 100%;
height: 90vh;
position: relative;
}

image.png


image.png


rem和第三方插件


什么是rem


rem与em不同,rem会根据html的根节点字体大小进行变换,例如1rem就是一个字体大小那么大,比如根大小font size为12px,那么1rem即12px,大家可以在网上寻找单位换算工具进行换算(从设计稿的px到rem)或是下载相关插件例如gulp-px3rem,这样在不同分辨率,不同缩放比的电脑下都能够轻松应对了。


使用


第三方插件,例如做移动端适配的flexible.js,lib-flexible库,其核心原理就是rem,我们需要做的就是根据不同屏幕计算出不同的fontsize,而页面中元素都是用rem做单位,据此实现了自适应


源码:


;(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(){
var width = docEl.getBoundingClientRect().width;
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'] = {}));

大家如果对相关原理感兴趣,可以阅读:flexible.js如何实现rem自适应-前端开发博客


在实际开发中应用场景不同效果不同,因此不能写死px。


在PC端适配我们可以自动转换rem适配方案(postcss-pxtorem、amfe-flexible),这里以vue3+vite为例子。事实上amfe-flexible是lib-flexible的升级版。


注意: 行内样式px不会转化为rem


npm install postcss postcss-pxtorem --save-dev  // 我试过了反正我报错了,版本太高 大家可以指定5.1.1
npm install postcss-pxtorem@^5.1.1
npm i amfe-flexible --save

记得在main.js中引入amfe-flexible


import "amfe-flexible"

相关配置


image.png


媒体查询


通过查询不同的宽度来执行不同的css代码,最终以达到界面的配置。


在 CSS 中使用 @media 查询来检测屏幕宽度。当屏幕宽度小于 1024px 时,增加 margin-top 以向下移动表格。



.responsive-table {
transition: margin-top 0.3s; /* 添加过渡效果 */
}

@media (max-width: 1024px) {
.responsive-table {
margin-top: 200px; /* 向下移动的距离 */
}
}

弹性布局


创建一个响应式的卡片布局,当屏幕宽度减小时,卡片会自动换行。


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox Example</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
margin: 0;
height: 100vh;
background-color: #f0f0f0;
}

.card-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 90%;
}

.card {
background-color: white;
border: 1px solid #ccc;
border-radius: 5px;
padding: 20px;
margin: 10px;
flex: 1 1 300px; /* 基于300px,允许增长和收缩 */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s;
}

.card:hover {
transform: translateY(-5px);
}
</style>
</head>
<body>
<div class="card-container">
<div class="card">Card 1</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
<div class="card">Card 5</div>
</div>
</body>
</html>

小结


还是多提一嘴,应该不会有小伙伴把字体大小的单位也用rem吧?


作者:zykk
来源:juejin.cn/post/7431999862919446539

0 个评论

要回复文章请先登录注册