Appearance
UniApp CSS 语法
1. 页面样式与布局
uni-app 有 vue 页面、nvue 页面、uvue 页面。
- vue 页面是 webview 渲染的
- app-nvue 页面是原生渲染的,其样式比 web 会限制更多,另见 nvue 的 css
- app-uvue 页面是原生渲染的,是 web 的 css 子集,另见 uvue 的 css
uni-app 的 css 与 web 的 css 基本一致。本文没有讲解 css 的用法。在你了解 web 的 css 的基础之上,本文讲述一些样式相关的注意事项。
本文重点介绍 vue 页面,也就是 webview 中的样式注意事项。
2. css 预处理器支持
uni-app 支持 less、sass、scss、stylus 等预处理器。
参考:css 预处理器。
2.1. vue2 开发者 sass 预处理注意
sass 的预处理器,早年使用 node-sass,也就是 vue2 最初默认的编译器。
sass 官方推出了 dart-sass 来替代。node-sass 已经停维很久了。
vue3 默认使用的是 dart-sass。
另外 node-sass 不支持 arm cpu,也即 Apple 的 M 系列 CPU,导致 HBuilderX 的 arm 版只能使用 dart-sass。
node-sass 有些淘汰的写法,在 dart-sass 里已不再支持。
所以开发者在从 vue2 升 vue3 时,使用 HBuilderX arm 版时,会发现老的 vue2 项目如果写了废弃 scss 语法,会编译报错。
这种分裂也导致插件生态混乱,导致多人协作时,比如一个项目有人用 arm 专版,有人使用 intel 版,造成协作障碍。
DCloud 推荐开发者尽快升级到 vue3,改用 dart-sass。
从 HBuilderX 4.56+,vue2 项目也将默认使用 dart-sass 预编译器。
如果您希望继续使用 node-sass,可以在
manifest.json根节点配置:"sassImplementationName": "node-sass";可选值"dart-sass"、"node-sass"。sassImplementationName配置仅限 uni-app(vue2)项目且非 HBuilderX Mac Arm 版本,HBuilder Mac Arm 版本以及 uni-app vue3 和 uni-app x 项目仅支持 dart-sass。
node-sass 升级 dart-sass 常见问题及改进方法:
SassError: expected selector. /deep/解决方案:
/deep/替换成::v-deepWARNING: Using / for division is deprecated and will be removed in Dart Sass 2.0.0.解决方案:使用
math.div()替换除法运算符(详情),如果遇到@use 'sass:math';编译报错,可以在uni.scss中定义,详情。SassError: xxx and xxx are incompatible.解决方案:
calc在特定情况需要带单位,比如:width: calc(100% - 215)修改为:width: calc(100% - 215px)。
3. 尺寸单位
uni-app 支持的通用 css 单位包括 px、rpx。
px即屏幕像素。rpx即响应式px,一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx恰好为屏幕宽度。屏幕变宽,rpx实际显示效果会等比放大,但在 App(vue2 不含 nvue)端和 H5(vue2)端屏幕宽度达到960px时,默认将按照375px的屏幕宽度进行计算,具体配置参考:rpx计算配置。
vue 页面支持下面这些普通 H5 单位,但在 nvue 里不支持:
rem 根字体大小可以通过 page-meta 配置抖音小程序和飞书小程序:屏幕宽度 / 20、百度小程序:
16px、支付宝小程序:50px。vh viewpoint height,视窗高度,
1vh等于视窗高度的 1%。vw viewpoint width,视窗宽度,
1vw等于视窗宽度的 1%。
nvue 还不支持百分比单位。
App 端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。注意此时不支持 rpx。
nvue 中,uni-app 模式(nvue 不同编译模式介绍)可以使用 px、rpx,表现与 vue 中基本一致,另外启用 dynamicRpx 后可以适配屏幕大小动态变化。weex 模式目前遵循 weex 的单位,它的单位比较特殊:
px:以 750 宽的屏幕为基准动态计算的长度单位,与 vue 页面中的rpx理念相同。(一定要注意 weex 模式的px,和 vue 里的px逻辑不一样)wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的px理念相同。
下面对 rpx 详细说明:
设计师在提供设计图时,一般只提供一个分辨率的图。
严格按设计图标注的 px 做开发,在不同宽度的手机上界面很容易变形。
而且主要是宽度变形。高度一般因为有滚动条,不容易出问题。由此,引发了较强的动态宽度单位需求。
微信小程序设计了 rpx 解决这个问题。uni-app 在 App 端、H5 端都支持了 rpx,并且可以配置不同屏幕宽度的计算方式,具体参考:rpx 计算配置。
rpx 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。uni-app 规定屏幕基准宽度 750rpx。
开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下:
换言之,页面元素宽度在 uni-app 中的宽度计算公式:
举例说明:
若设计稿宽度为
750px,元素 A 在设计稿上的宽度为100px,那么元素 A 在 uni-app 里面的宽度应该设为: ,结果为:100rpx。若设计稿宽度为
640px,元素 A 在设计稿上的宽度为100px,那么元素 A 在 uni-app 里面的宽度应该设为: ,结果为:117rpx。若设计稿宽度为
375px,元素 B 在设计稿上的宽度为200px,那么元素 B 在 uni-app 里面的宽度应该设为: ,结果为:400rpx。
Tips:
注意
rpx是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用px单位。如果开发者在字体或高度中也使用了
rpx,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用px。rpx不支持动态横竖屏切换计算,使用rpx建议锁定屏幕方向。设计师可以用 iPhone6 作为视觉稿的标准。
如果设计稿不是
750px,HBuilderX 提供了自动换算的工具,详见:HBuilderX 中自动转换px为upx。App 端,在
pages.json里的titleNView或页面里写的 plus api 中涉及的单位,只支持px,不支持rpx。早期 uni-app 提供了
upx,目前已经推荐统一改为rpx了,详见。
4. 样式导入
使用 @import 语句可以导入外联样式表,@import 后跟需要导入的外联样式表的相对路径,用 ; 表示语句结束。
示例代码:
HTML
<style>
@import "../../common/uni.css";
.uni-card {
box-shadow: none;
}
</style>5. 内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。
style:静态的样式统一写到class中。style接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进style中,以免影响渲染速度。HTML<view :style="{color:color}" />class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。HTML<view class="normal_view" />
6. 选择器
目前支持的选择器有:
| 选择器 | 样例 | 样例描述 |
|---|---|---|
.class | .intro | 选择所有拥有 class="intro" 的组件 |
#id | #firstname | 选择拥有 id="firstname" 的组件 |
element | view | 选择所有 view 组件 |
element, element | view, checkbox | 选择所有文档的 view 组件和所有的 checkbox 组件 |
::after | view::after | 在 view 组件后边插入内容,仅 vue 页面生效 |
::before | view::before | 在 view 组件前边插入内容,仅 vue 页面生效 |
警告
在 uni-app 中不能使用
*选择器;微信小程序自定义组件中仅支持
class选择器;page相当于body节点,例如:CSS/* 设置页面背景颜色,使用 scoped 会导致失效 */ page { background-color: #ccc; }Web 端可以使用
html、body、:root等选择器。由于页面的 CSS 样式隔离,且html节点并未添加data-xxx属性,html、:root写在页面style内无效,只能写在App.vue内。
7. 全局样式与局部样式
定义在 App.vue 中的样式为全局样式,作用于每一个页面。在 pages 目录下的 vue 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue 中相同的选择器。
注意:
App.vue中通过@import语句可以导入外联样式,一样作用于每一个页面;- nvue 页面暂不支持全局样式;
8. CSS 变量
uni-app 提供内置 CSS 变量:
| CSS 变量 | 描述 | App | 小程序 | H5 |
|---|---|---|---|---|
--status-bar-height | 系统状态栏高度 | 系统状态栏高度、nvue 注意见下 | 25px | 0 |
--window-top | 内容区域距离顶部的距离 | 0 | 0 | NavigationBar 的高度 |
--window-bottom | 内容区域距离底部的距离 | 0 | 0 | TabBar 的高度 |
注意:
var(--status-bar-height)此变量在微信小程序环境为固定25px,在 App 里为手机实际状态栏高度。当设置
"navigationStyle": "custom"取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置。此时可以使用一个高度为var(--status-bar-height)的view放在页面顶部,避免页面内容出现在状态栏。由于在 H5 端,不存在原生导航栏和
tabbar,也是前端div模拟。如果设置了一个固定位置的居底view,在小程序和 App 端是在tabbar上方,但在 H5 端会与tabbar重叠。此时可使用--window-bottom,不管在哪个端,都是固定在tabbar上方。目前 nvue 在 App 端,还不支持
--status-bar-height变量,替代方案是在页面onLoad时通过uni.getSystemInfoSync().statusBarHeight获取状态栏高度,然后通过style绑定方式给占位view设定高度。
信息
快速书写 css 变量的方法是:在 css 中敲 hei,在候选助手中即可看到 3 个 css 变量。(HBuilderX 1.9.6 以上支持)
示例 1:普通页面使用 css 变量:
HTML<template> <!-- HBuilderX 2.6.3+ 新增 page-meta, 详情:https://uniapp.dcloud.io/component/page-meta --> <page-meta> <navigation-bar /> </page-meta> <view> <view class="status_bar"> <!-- 这里是状态栏 --> </view> <view>状态栏下的文字</view> </view> </template> <style> .status_bar { height: var(--status-bar-height); width: 100%; } </style>HTML<template> <view> <view class="toTop"> <!-- 这里可以放一个向上箭头,它距离底部 tabbar 上浮 10px--> </view> </view> </template> <style> .toTop { bottom: calc(var(--window-bottom) + 10px); } </style>示例 2:nvue 页面获取状态栏高度
HTML<template> <view class="content"> <view :style="{ height: iStatusBarHeight + 'px' }"></view> </view> </template> <script> export default { data() { return { iStatusBarHeight: 0, }; }, onLoad() { this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight; }, }; </script>
9. 固定值
uni-app 中以下组件的高度是固定的,不可修改:
| 组件 | 描述 | App | H5 |
|---|---|---|---|
| NavigationBar | 导航栏 | 44px | 44px |
| TabBar | 底部选项卡 | HBuilderX 2.3.4 之前为 56px,2.3.4 起和 H5 调为一致,统一为 50px。(但可以自主更改高度) | 50px |
各小程序平台,包括同小程序平台的 iOS 和 Android 的高度也不一样。
10. Flex 布局
为支持跨平台,框架建议使用 Flex 布局,关于 Flex 布局可以参考外部文档 A Complete Guide to Flexbox、阮一峰的 flex 教程等。
11. 背景图片
uni-app 支持使用在 css 里设置背景图片,使用方式与普通 web 项目大体相同,但需要注意以下几点:
支持 base64 格式图片。
支持网络路径图片。
小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
使用本地路径背景图片需注意:
为方便开发者,在背景图片小于
40kb时,uni-app 编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式;图片大于等于
40kb,会有性能问题,不建议使用太大的背景图,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用。本地背景图片的引用路径推荐使用以
~@开头的绝对路径。CSS.test2 { background-image: url("~@/static/logo.png"); }
警告
微信小程序不支持相对路径(真机不支持,开发工具支持)。
12. 字体图标
uni-app 支持使用字体图标,使用方式与普通 web 项目相同,需要注意以下几点:
支持 base64 格式字体图标。
支持网络路径字体图标。
小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
网络路径必须加协议头
https。从 http://www.iconfont.cn 上拷贝的代码,默认是没加协议头的。
从 http://www.iconfont.cn 上下载的字体文件,都是同名字体(字体名都叫 iconfont,安装字体文件时可以看到),在 nvue 内使用时需要注意,此字体名重复可能会显示不正常,可以使用工具修改。
使用本地路径图标字体需注意:
为方便开发者,在字体文件小于
40kb时,uni-app 会自动将其转化为 base64 格式;字体文件大于等于
40kb,仍转换为 base64 方式使用的话可能有性能问题,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用;字体文件的引用路径推荐使用以
~@开头的绝对路径。CSS@font-face { font-family: test1-icon; src: url("~@/static/iconfont.ttf"); }
nvue 中不可直接使用 css 的方式引入字体文件,需要使用以下方式在 js 内引入。nvue 内不支持本地路径引入字体,请使用网络链接或者 base64 形式。src 字段的 url 的括号内一定要使用单引号。
JavaScript
var domModule = weex.requireModule("dom");
domModule.addRule("fontFace", {
fontFamily: "fontFamilyName",
src: "url('https://...')",
});示例:
HTML
<template>
<view>
<view>
<text class="test"></text>
<text class="test"></text>
<text class="test"></text>
</view>
</view>
</template>
<style>
@font-face {
font-family: "iconfont";
src: url("https://at.alicdn.com/t/font_865816_17gjspmmrkti.ttf") format("truetype");
}
.test {
font-family: iconfont;
margin-left: 20rpx;
}
</style>