样式和CSS - 让你的小程序更好看
🎨 颜值即正义!今天我们来学习如何让小程序变得更加美观
1. UniApp样式基础
支持的CSS特性
scss
// UniApp支持大部分CSS3特性
.example {
// 基础属性
width: 100px;
height: 100px;
background-color: #007aff;
// 圆角
border-radius: 8px;
// 阴影
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
// 渐变
background: linear-gradient(45deg, #007aff, #5ac8fa);
// 变换
transform: scale(1.1) rotate(45deg);
// 过渡动画
transition: all 0.3s ease;
// Flex布局
display: flex;
justify-content: center;
align-items: center;
}
尺寸单位
scss
.size-demo {
// px - 像素单位
width: 100px;
// rpx - 响应式像素(推荐)
width: 200rpx; // 在375px宽度设备上等于100px
// % - 百分比
width: 50%;
// vh/vw - 视口单位
height: 100vh; // 视口高度
width: 100vw; // 视口宽度
}
2. SCSS预处理器
变量定义
scss
// uni.scss - 全局变量文件
$primary-color: #007aff;
$success-color: #4cd964;
$warning-color: #ff9500;
$error-color: #ff3b30;
$font-size-small: 24rpx;
$font-size-base: 28rpx;
$font-size-large: 32rpx;
$border-radius: 8rpx;
$spacing: 20rpx;
混合器(Mixins)
scss
// 常用混合器
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@mixin button-style($bg-color, $text-color: white) {
background-color: $bg-color;
color: $text-color;
border: none;
border-radius: $border-radius;
padding: 20rpx 40rpx;
&:active {
opacity: 0.8;
}
}
// 使用混合器
.my-button {
@include button-style($primary-color);
}
.center-box {
@include flex-center;
height: 200rpx;
}
.text-ellipsis {
@include ellipsis;
width: 200rpx;
}
3. 响应式设计
使用rpx实现适配
vue
<template>
<view class="responsive-demo">
<view class="card">
<image src="/static/avatar.png" class="avatar" />
<view class="info">
<text class="name">用户名称</text>
<text class="desc">这是用户描述信息</text>
</view>
<button class="follow-btn">关注</button>
</view>
</view>
</template>
<style lang="scss">
.responsive-demo {
padding: 30rpx;
}
.card {
background: white;
border-radius: 20rpx;
padding: 30rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
margin-right: 30rpx;
}
.info {
flex: 1;
}
.name {
font-size: 32rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.desc {
font-size: 26rpx;
color: #666;
}
.follow-btn {
background: $primary-color;
color: white;
border: none;
border-radius: 40rpx;
padding: 16rpx 32rpx;
font-size: 26rpx;
}
</style>
媒体查询
scss
// 针对不同屏幕尺寸的适配
.responsive-layout {
padding: 20rpx;
// 小屏幕(手机)
@media screen and (max-width: 750rpx) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
// 大屏幕(平板)
@media screen and (min-width: 750rpx) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
}
4. 主题切换
实现暗黑模式
vue
<template>
<view class="theme-demo" :class="{ 'dark-theme': isDark }">
<view class="header">
<text class="title">主题切换演示</text>
<switch :checked="isDark" @change="toggleTheme" />
</view>
<view class="content">
<view class="card">
<text class="card-title">卡片标题</text>
<text class="card-content">这是卡片内容,支持主题切换</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
isDark: false
}
},
onLoad() {
// 读取用户主题偏好
const theme = uni.getStorageSync('theme')
this.isDark = theme === 'dark'
},
methods: {
toggleTheme(e) {
this.isDark = e.detail.value
// 保存主题偏好
uni.setStorageSync('theme', this.isDark ? 'dark' : 'light')
}
}
}
</script>
<style lang="scss">
// 浅色主题变量
$light-bg: #ffffff;
$light-text: #333333;
$light-card-bg: #f8f9fa;
// 深色主题变量
$dark-bg: #1a1a1a;
$dark-text: #ffffff;
$dark-card-bg: #2d2d2d;
.theme-demo {
min-height: 100vh;
background: $light-bg;
color: $light-text;
transition: all 0.3s ease;
&.dark-theme {
background: $dark-bg;
color: $dark-text;
.card {
background: $dark-card-bg;
}
}
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.content {
padding: 30rpx;
}
.card {
background: $light-card-bg;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
transition: background 0.3s ease;
}
.card-title {
font-size: 32rpx;
font-weight: bold;
display: block;
margin-bottom: 20rpx;
}
.card-content {
font-size: 28rpx;
line-height: 1.6;
}
</style>
5. 动画效果
CSS动画
scss
// 淡入动画
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
// 弹跳动画
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-20rpx);
}
60% {
transform: translateY(-10rpx);
}
}
// 旋转动画
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
.bounce {
animation: bounce 1s infinite;
}
.loading-spin {
animation: spin 1s linear infinite;
}
过渡效果
vue
<template>
<view class="transition-demo">
<view
class="hover-card"
:class="{ active: isActive }"
@click="toggleActive"
>
<text>点击我</text>
</view>
<view class="slide-menu" :class="{ show: showMenu }">
<text>侧边菜单</text>
</view>
<button @click="toggleMenu">切换菜单</button>
</view>
</template>
<script>
export default {
data() {
return {
isActive: false,
showMenu: false
}
},
methods: {
toggleActive() {
this.isActive = !this.isActive
},
toggleMenu() {
this.showMenu = !this.showMenu
}
}
}
</script>
<style lang="scss">
.hover-card {
width: 200rpx;
height: 200rpx;
background: $primary-color;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
color: white;
transition: all 0.3s ease;
transform: scale(1);
&.active {
transform: scale(1.1);
background: $success-color;
border-radius: 50rpx;
}
}
.slide-menu {
position: fixed;
top: 0;
left: -300rpx;
width: 300rpx;
height: 100vh;
background: white;
box-shadow: 2rpx 0 10rpx rgba(0, 0, 0, 0.1);
transition: left 0.3s ease;
z-index: 1000;
&.show {
left: 0;
}
}
</style>
6. 实战案例:美化登录页面
vue
<template>
<view class="login-page">
<!-- 背景装饰 -->
<view class="bg-decoration">
<view class="circle circle-1"></view>
<view class="circle circle-2"></view>
<view class="circle circle-3"></view>
</view>
<!-- 登录表单 -->
<view class="login-form">
<view class="logo-section">
<image src="/static/logo.png" class="logo" />
<text class="app-name">我的应用</text>
<text class="welcome-text">欢迎回来</text>
</view>
<view class="form-section">
<view class="input-group">
<view class="input-wrapper">
<text class="input-icon">📱</text>
<input
v-model="phone"
placeholder="请输入手机号"
class="form-input"
type="number"
/>
</view>
</view>
<view class="input-group">
<view class="input-wrapper">
<text class="input-icon">🔒</text>
<input
v-model="password"
placeholder="请输入密码"
class="form-input"
type="password"
/>
</view>
</view>
<button
class="login-btn"
:class="{ loading: isLoading }"
@click="handleLogin"
>
<text v-if="!isLoading">登录</text>
<view v-else class="loading-content">
<view class="loading-spinner"></view>
<text>登录中...</text>
</view>
</button>
<view class="form-footer">
<text class="link-text">忘记密码?</text>
<text class="link-text">立即注册</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
phone: '',
password: '',
isLoading: false
}
},
methods: {
async handleLogin() {
if (!this.phone || !this.password) {
uni.showToast({
title: '请填写完整信息',
icon: 'error'
})
return
}
this.isLoading = true
try {
// 模拟登录请求
await new Promise(resolve => setTimeout(resolve, 2000))
uni.showToast({
title: '登录成功',
icon: 'success'
})
// 跳转到首页
uni.reLaunch({
url: '/pages/index/index'
})
} catch (error) {
uni.showToast({
title: '登录失败',
icon: 'error'
})
} finally {
this.isLoading = false
}
}
}
}
</script>
<style lang="scss">
.login-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow: hidden;
}
.bg-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
.circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
&.circle-1 {
width: 200rpx;
height: 200rpx;
top: 10%;
right: -50rpx;
animation: float 6s ease-in-out infinite;
}
&.circle-2 {
width: 150rpx;
height: 150rpx;
top: 60%;
left: -30rpx;
animation: float 8s ease-in-out infinite reverse;
}
&.circle-3 {
width: 100rpx;
height: 100rpx;
top: 30%;
left: 20%;
animation: float 10s ease-in-out infinite;
}
}
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20rpx);
}
}
.login-form {
position: relative;
z-index: 1;
padding: 100rpx 60rpx;
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100vh;
}
.logo-section {
text-align: center;
margin-bottom: 80rpx;
.logo {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
margin-bottom: 30rpx;
}
.app-name {
font-size: 48rpx;
font-weight: bold;
color: white;
display: block;
margin-bottom: 10rpx;
}
.welcome-text {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}
}
.form-section {
.input-group {
margin-bottom: 40rpx;
}
.input-wrapper {
background: rgba(255, 255, 255, 0.9);
border-radius: 50rpx;
display: flex;
align-items: center;
padding: 0 30rpx;
backdrop-filter: blur(10rpx);
}
.input-icon {
font-size: 32rpx;
margin-right: 20rpx;
}
.form-input {
flex: 1;
height: 100rpx;
font-size: 32rpx;
border: none;
background: transparent;
}
.login-btn {
width: 100%;
height: 100rpx;
background: linear-gradient(45deg, #ff6b6b, #ff8e8e);
color: white;
border: none;
border-radius: 50rpx;
font-size: 36rpx;
font-weight: bold;
margin-top: 40rpx;
box-shadow: 0 10rpx 30rpx rgba(255, 107, 107, 0.3);
transition: all 0.3s ease;
&:active {
transform: translateY(2rpx);
box-shadow: 0 5rpx 15rpx rgba(255, 107, 107, 0.3);
}
&.loading {
background: #ccc;
box-shadow: none;
}
}
.loading-content {
display: flex;
align-items: center;
justify-content: center;
.loading-spinner {
width: 40rpx;
height: 40rpx;
border: 4rpx solid rgba(255, 255, 255, 0.3);
border-top: 4rpx solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 20rpx;
}
}
.form-footer {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
.link-text {
color: rgba(255, 255, 255, 0.8);
font-size: 28rpx;
}
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
小结
今天我们学习了:
- ✅ UniApp样式基础和支持的CSS特性
- ✅ SCSS预处理器的使用
- ✅ 响应式设计和rpx单位
- ✅ 主题切换的实现
- ✅ CSS动画和过渡效果
- ✅ 实战案例:美化登录页面
样式开发要点:
- 优先使用rpx实现响应式适配
- 合理使用SCSS提高开发效率
- 注意性能,避免过度使用动画
- 保持设计的一致性
下一篇预告
下一篇我们将学习《数据绑定和事件处理 - 让页面动起来》,深入了解Vue.js在UniApp中的应用。
好看的界面是成功的一半,用心设计每一个细节,用户会感受到你的用心!