1. 视口(Viewport)设置
<!-- 标准视口设置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
2. 常用适配方案
2.1 rem 适配方案
/* 基准值设置 */
html {
font-size: 16px; /* 默认值 */
}
/* 媒体查询设置不同屏幕尺寸的基准值 */
@media screen and (min-width: 320px) {
html {
font-size: 16px;
}
}
@media screen and (min-width: 375px) {
html {
font-size: 18.75px;
}
}
@media screen and (min-width: 414px) {
html {
font-size: 20.7px;
}
}
/* 使用示例 */
.box {
width: 10rem; /* 在 375px 屏幕上为 187.5px */
height: 5rem; /* 在 375px 屏幕上为 93.75px */
font-size: 0.8rem; /* 在 375px 屏幕上为 15px */
}
2.2 vw/vh 适配方案
/* 使用 vw 单位 */
.box {
width: 50vw; /* 视口宽度的 50% */
height: 30vh; /* 视口高度的 30% */
font-size: 4vw; /* 视口宽度的 4% */
}
/* 结合 calc() 使用 */
.box {
width: calc(50vw - 20px);
height: calc(30vh + 10px);
}
2.3 百分比适配方案
.container {
width: 100%;
padding: 0 15px;
}
.box {
width: 50%; /* 父元素宽度的 50% */
height: 30%; /* 父元素高度的 30% */
margin: 2%; /* 父元素宽度的 2% */
}
3. 实际应用方案
3.1 淘宝 flexible.js 方案
// flexible.js 核心代码
(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()
// 监听页面大小变化
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
setRemUnit()
}
})
})(window, document)
3.2 postcss-pxtorem 方案
// postcss.config.js
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 37.5, // 设计稿宽度/10
propList: ['*'],
selectorBlackList: ['.norem'] // 过滤掉 .norem 开头的 class
}
}
}
3.3 混合使用方案
/* 混合使用 rem 和 vw */
.container {
width: 100%;
padding: 0 0.4rem; /* 使用 rem */
}
.box {
width: 50vw; /* 使用 vw */
height: 2rem; /* 使用 rem */
margin: 0.2rem; /* 使用 rem */
font-size: 0.28rem; /* 使用 rem */
}
/* 响应式布局 */
@media screen and (max-width: 320px) {
.box {
width: 100%;
}
}
4. 特殊场景处理
4.1 1px 边框问题
/* 使用伪元素 + transform 实现 1px 边框 */
.border-1px {
position: relative;
}
.border-1px::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background: #000;
transform: scaleY(0.5);
transform-origin: 0 0;
}
4.2 图片适配
/* 图片自适应 */
.img-container {
width: 100%;
height: 0;
padding-bottom: 56.25%; /* 16:9 比例 */
position: relative;
}
.img-container img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
4.3 文字大小适配
/* 使用 clamp() 函数控制文字大小范围 */
.text {
font-size: clamp(12px, 4vw, 16px);
}
/* 使用媒体查询控制文字大小 */
@media screen and (max-width: 320px) {
.text {
font-size: 12px;
}
}
@media screen and (min-width: 321px) and (max-width: 414px) {
.text {
font-size: 14px;
}
}
@media screen and (min-width: 415px) {
.text {
font-size: 16px;
}
}
5. 最佳实践建议
1 选择合适的适配方案
-
小型项目:使用媒体查询 + 百分比
-
中型项目:使用 rem + 媒体查询
-
大型项目:使用 flexible.js 或 postcss-pxtorem
2 统一设计稿尺寸
-
建议使用 375px 或 750px 作为设计稿基准宽度
-
保持设计稿与开发环境的一致性
3 合理使用单位
-
容器宽度:使用百分比或 vw
-
字体大小:使用 rem
-
间距:使用 rem
-
边框:使用 px
4. 注意性能优化
-
避免频繁的尺寸计算
-
使用 transform 代替位置变化
-
合理使用缓存
-
测试和调试
-
使用 Chrome 开发者工具模拟不同设备
-
使用真机测试
-
关注页面加载性能
6. 常见问题解决方案
6.1 横屏适配
/* 横屏样式调整 */
@media screen and (orientation: landscape) {
.container {
width: 100vh;
height: 100vw;
transform: rotate(90deg);
transform-origin: 0 0;
}
}
6.2 安全区域适配
/* 适配 iPhone X 等全面屏设备 */
.safe-area {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
6.3 高清屏适配
/* 使用媒体查询适配不同 DPR */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
.image {
background-image: url('image@2x.png');
}
}
@media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 3dppx) {
.image {
background-image: url('image@3x.png');
}
}
淘宝更改
(function flexible(window, document) {
var docEl = document.documentElement
var dpr = window.devicePixelRatio || 1
// 调整 body 标签的 font-size
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize()
// 设置 rem 单位
function setRemUnit() {
// 修改这里:将屏幕宽度分成 7.5 份,这样 1rem = 100px
var rem = docEl.clientWidth / 7.5
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// 监听页面大小变化
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
setRemUnit()
}
})
})(window, document)
/* 示例 */
.header {
height: 0.88rem; /* 设计稿 88px */
line-height: 0.88rem;
font-size: 0.28rem; /* 设计稿 28px */
padding: 0 0.3rem; /* 设计稿 30px */
}
.btn {
width: 3.2rem; /* 设计稿 320px */
height: 0.88rem; /* 设计稿 88px */
font-size: 0.32rem; /* 设计稿 32px */
border-radius: 0.44rem; /* 设计稿 44px */
}
使用 PostCSS 插件自动转换
为了进一步简化开发,可以使用 postcss-pxtorem 插件自动将 px 转换为 rem
// postcss.config.js
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 100, // 设计稿宽度/7.5
propList: ['*'],
selectorBlackList: ['.norem'] // 过滤掉 .norem 开头的 class
}
}
}