uni-app 样式开发
uni-app 的样式写法基本就是普通 CSS,但有两个移动端特有的重点,rpx 响应式单位和多端适配的布局方式,掌握了它们,一套样式就能在手机、平板、网页上都有合理的表现。
rpx 响应式单位
rpx(responsive pixel)是 uni-app 特有的尺寸单位,规则只有一条,750rpx 永远等于屏幕宽度。
换算公式,1rpx = 屏幕宽度 / 750。屏幕越宽,1rpx 对应的实际像素越多,所以同一套 rpx 尺寸在不同设备上会自动缩放。
举两个实际例子:
| 设备 | 屏幕宽度 | 375rpx 的实际宽度 |
|---|---|---|
| 手机(宽 375px) | 375px | 187.5px(正好一半) |
| 平板(宽 750px) | 750px | 375px(正好一半) |
无论什么设备,375rpx 都占屏幕的一半,这就是响应式。
常见单位对比
| 单位 | 说明 |
|---|---|
rpx |
响应式单位,750rpx = 屏幕宽度,布局首选 |
px |
固定像素,不随屏幕缩放,适合 1px 边框等场景 |
% |
相对父元素百分比,搭配 rpx 使用 |
vw/vh |
视口宽高的百分比,H5 端常用,小程序端支持有限 |
提示:字体大小也建议用 rpx 或固定 px,不要在字体上依赖 vw,不同端表现不一致。
Flex 弹性布局
移动端布局首选 Flex,uni-app 在所有平台都完整支持,不用担心兼容问题。
用之前那篇的商品卡片举例,横向排布用 flex-direction: row,纵向排布用 column:
.goods-card {
display: flex; /* 开启弹性布局 */
align-items: center; /* 子项垂直居中 */
justify-content: space-between; /* 子项两端对齐,中间留空 */
}
一个简单的口诀,父容器 display: flex 加方向,子元素用 flex: 1 占满剩余空间,绝大多数的布局都能搞定:
.goods-info {
flex: 1; /* 占据剩余全部空间 */
}
局部样式与全局样式
局部样式
组件里的 <style scoped> 只对当前组件生效,这是默认写法和最佳实践,避免类名冲突:
<style scoped>
.title {
color: #333;
}
</style>
全局样式
写在 App.vue 的 <style> 里,不写 scoped,所有页面都会生效,适合放公共工具类和全局字体:
<style>
page {
background-color: #f5f5f5;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
</style>
注意:page 是特殊选择器,相当于页面的根节点,设置页面背景色要靠它,直接给 view 设置背景色是盖不满整屏的。
pages.json 里的 globalStyle 不是 CSS
容易混淆的一点,pages.json 里的 globalStyle 配置的是窗口和导航栏外观,不是写 CSS 的地方:
{
"globalStyle": {
"navigationBarTitleText": "我的应用",
"navigationBarBackgroundColor": "#007AFF",
"navigationBarTextStyle": "white",
"backgroundColor": "#F5F5F5",
"enablePullDownRefresh": true
}
}
| 配置项 | 作用 |
|---|---|
navigationBarTitleText |
导航栏标题文字 |
navigationBarBackgroundColor |
导航栏背景色 |
navigationBarTextStyle |
导航栏文字颜色 |
backgroundColor |
下拉时露出的背景色 |
enablePullDownRefresh |
是否开启下拉刷新 |
uni.scss 全局样式变量
结构篇里介绍过 uni.scss,这里讲它的核心价值,全局变量共享。
在 uni.scss 中定义变量:
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-font-size-base: 28rpx;
任意组件的 <style lang="scss"> 里直接使用,不用 import:
<style lang="scss" scoped>
.btn {
background-color: $uni-color-primary;
font-size: $uni-font-size-base;
}
</style>
好处是主题色改一处,全应用生效。项目默认的 uni.scss 里已经带了一套官方变量($uni-color-primary 等),可以直接用。
动态样式
除了静态 class,还经常根据数据动态切换样式,两种写法:
<!-- 类名绑定 -->
<view :class="isVip ? 'vip' : 'normal'">会员状态</view>
<!-- 内联样式绑定 -->
<view :style="{ color: isVip ? '#f5a623' : '#333' }">会员状态</view>
注意动态样式建议用对象语法,单位用 rpx 时需要写成字符串:
<view :style="{ width: progress + 'rpx' }">进度条</view>
综合示例:商品列表页
用 rpx + Flex 做一个两列商品列表,验证多端适配效果:
<template>
<view class="page">
<view class="goods-grid">
<view class="goods-card" v-for="item in goodsList" :key="item.id">
<image class="goods-img" :src="item.img" mode="aspectFill"></image>
<text class="goods-name">{{ item.name }}</text>
<text class="goods-price">¥{{ item.price }}</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const goodsList = ref(
[1, 2, 3, 4].map((i) => ({
id: i,
name: '商品' + i,
price: 99 + i,
img: '/static/goods' + i + '.png'
}))
)
</script>
<style scoped>
.page {
padding: 20rpx;
background-color: #f5f5f5;
}
.goods-grid {
display: flex;
flex-wrap: wrap; /* 换行,两列布局的关键 */
justify-content: space-between;
}
.goods-card {
width: 345rpx; /* (750 - 20*2 - 20) / 2,正好两列 */
margin-bottom: 20rpx;
padding: 16rpx;
border-radius: 16rpx;
background-color: #fff;
}
.goods-img {
width: 100%;
height: 345rpx;
border-radius: 12rpx;
}
.goods-name {
display: block;
margin-top: 12rpx;
font-size: 28rpx;
color: #333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; /* 超长省略号 */
}
.goods-price {
display: block;
margin-top: 8rpx;
color: #ff5000;
font-size: 32rpx;
font-weight: bold;
}
</style>
width: 345rpx 是这么算的,屏幕 750rpx,左右内边距各 20rpx,两列间隔 20rpx,(750 - 40 - 20) / 2 = 345。在手机上看到两列,在更宽的设备上依然保持两列并自动放大,这就是 rpx 的适配效果。
总结
| 知识点 | 要点 |
|---|---|
| rpx | 750rpx = 屏幕宽度,布局尺寸首选 |
| Flex | 所有平台完整支持,移动端布局主力 |
| 局部样式 | 组件内 <style scoped>,默认做法 |
| 全局样式 | App.vue 的非 scoped style,page 设置背景色 |
| globalStyle | pages.json 里配导航栏外观,不是 CSS |
| uni.scss | 全局变量,主题色改一处全应用生效 |
| 动态样式 | :class 与 :style 对象语法 |
一句话总结:布局尺寸用 rpx,结构排布用 Flex,样式写在 scoped 里,公共的东西放 App.vue 和 uni.scss,动态变化用 :class 和 :style,这套组合能应对绝大多数移动端页面。