Python NiceGUI 样式 Props、Classes、Style 完全解析
在 NiceGUI 2.20.0 中,样式控制被清晰地分为三个层次,理解这个架构是关键:
┌─────────────────────────────────────────┐
│ CSS 样式三层架构 │
├─────────────────────────────────────────┤
│ 1. 组件参数 (Component Props) │ ← 组件自有样式
│ 2. Quasar Props │ ← Quasar框架样式
│ 3. Classes & Style │ ← 自定义样式
└─────────────────────────────────────────┘
# Props 是什么?
# 1. Quasar UI 框架的组件属性
# 2. Vue.js 的组件props
# 3. 主要用于控制组件的行为和Quasar内置样式
# 基本特征:
# - 字符串格式:'prop1=value1 prop2 prop3=value3'
# - 多个props用空格分隔
# - 布尔props只需写名称(如 'disabled' 而不是 'disabled=true')
# Classes 是什么?
# 1. CSS 类名
# 2. 可以是Tailwind CSS、Quasar CSS或自定义CSS
# 3. 用于应用预定义或自定义的样式规则
# 基本特征:
# - 字符串格式:'class1 class2 class3'
# - 多个类用空格分隔
# - 支持响应式类、状态类等
# Style 是什么?
# 1. 内联CSS样式
# 2. 直接作用于元素的style属性
# 3. 最高优先级(除!important外)
# 基本特征:
# - 字符串格式:'property1: value1; property2: value2;'
# - 也可以是字典:{'property1': 'value1', 'property2': 'value2'}
开始选择样式方式
↓
┌─────────────────┐
│ 要改变什么? │
└──────┬──────────┘
↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 组件行为/状态 │ │ 布局/间距 │ │ 自定义视觉 │
│ (禁用、加载) │ │ (边距、对齐) │ │ (颜色、背景) │
└──────┬────────┘ └──────┬───────┘ └──────┬───────┘
↓ ↓ ↓
使用 Props 使用 Classes 使用 Style
↓ ↓ ↓
'disabled loading''q-mt-md q-pa-sm''color: red;'
# 情况1:控制组件状态和行为
ui.button('提交', props='disabled loading')
# 情况2:使用Quasar预设样式变体
ui.input(label='姓名', props='filled outlined') # Quasar的filled样式
# 情况3:传递Vue组件属性
ui.button('链接', props='href="https://example.com" target="_blank"')
# 情况4:绑定Vue指令
ui.input(props='v-model="text" @keyup.enter="submit"')
# 情况5:Quasar特有的配置
ui.date(props='mask="YYYY-MM-DD" today-btn')
# 正确示例
ui.button('测试', props='color=primary outline rounded')
# 错误示例
# ui.button('测试', props={'color': 'primary'}) # 2.20.0不再推荐字典格式
# ui.button('测试', props='color="primary"') # 不需要引号
# Props 格式规则:
# 1. 字符串形式,空格分隔
# 2. 键值对用等号连接:key=value
# 3. 布尔值只需键名:disabled(不是 disabled=true)
# 4. 多单词属性用连字符:first-day-of-week=1
# 1. 状态类 Props
'disabled'# 禁用
'loading'# 加载中
'readonly'# 只读
'selected'# 选中
'active'# 激活
# 2. 样式变体 Props(Quasar特有)
'filled'# 填充样式
'outlined'# 轮廓样式
'flat'# 扁平样式
'glossy'# 光泽效果
'rounded'# 圆角
'square'# 方形
# 3. 尺寸 Props
'size="xs|sm|md|lg|xl"'
'dense'# 紧凑模式
# 4. 颜色 Props
'color="primary|secondary|accent|positive|negative|info|warning"'
'text-color="white"'
# 5. 功能 Props
'clearable'# 可清除(输入框)
'multiple'# 多选(选择器)
'range'# 范围选择(日期)
from nicegui import ui
# 示例1:按钮的各种状态
ui.button('普通按钮')
ui.button('禁用按钮', props='disabled')
ui.button('加载中', props='loading')
ui.button('轮廓按钮', props='outline')
ui.button('圆角按钮', props='rounded')
# 示例2:输入框变体
ui.input('填充样式', props='filled')
ui.input('轮廓样式', props='outlined')
ui.input('突出样式', props='standout')
ui.input('无边框', props='borderless')
# 示例3:复杂组合
ui.button('高级按钮',
props='color=primary outline rounded size=lg glossy')
# 情况1:控制布局和间距
ui.button('按钮', classes='q-mt-md q-pa-sm') # 使用Quasar间距工具类
# 情况2:使用Tailwind CSS
ui.button('按钮', classes='bg-blue-500 text-white hover:bg-blue-600')
# 情况3:应用自定义CSS类
ui.button('按钮', classes='my-custom-class special-button')
# 情况4:响应式设计
ui.button('按钮', classes='text-sm md:text-lg lg:text-xl')
# 情况5:状态类
ui.button('按钮', classes='active:scale-95 hover:shadow-lg')
# 边距 (margin)
'q-ma-xs|sm|md|lg|xl'# 所有方向
'q-mt-*''q-mb-*''q-ml-*''q-mr-*'# 特定方向
'q-mx-*''q-my-*'# 水平和垂直
# 内边距 (padding)
'q-pa-xs|sm|md|lg|xl'
'q-pt-*''q-pb-*''q-pl-*''q-pr-*'
'q-px-*''q-py-*'
# 文本
'text-h1|h2|h3|h4|h5|h6'# 标题级别
'text-body1|body2|caption|overline'# 文本样式
'text-weight-thin|light|regular|medium|bold|bolder'# 字重
'text-italic'# 斜体
'text-no-wrap'# 不换行
'text-strike'# 删除线
'text-uppercase|lowercase|capitalize'# 大小写
# 颜色
'text-primary|secondary|accent|positive|negative|info|warning|dark|light'
'bg-primary|secondary|...'
'text-white|black|red|pink|purple|...'
# 对齐
'text-left|center|right|justify'
'self-start|center|end|stretch|baseline'
'items-start|center|end|stretch|baseline'
'justify-start|center|end|between|around|evenly'
# 显示
'hidden'# 隐藏
'inline|block|inline-block|flex|inline-flex'
# 背景颜色
'bg-blue-500''bg-red-300''bg-gradient-to-r from-blue-500 to-purple-600'
# 文本
'text-white''text-lg''font-bold''text-center'
# 边框
'border''border-2''border-blue-500''rounded-lg''rounded-full'
# 阴影
'shadow''shadow-md''shadow-lg''shadow-xl''shadow-2xl'
# 悬停状态
'hover:bg-blue-600''hover:text-white''hover:shadow-lg'
# 响应式
'sm:text-sm''md:text-base''lg:text-lg''xl:text-xl'
# 1. 先定义CSS
ui.add_head_html('''
<style>
.my-button {
background: linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%);
color: white;
border-radius: 12px;
transition: transform 0.3s;
}
.my-button:hover {
transform: translateY(-2px);
}
</style>
''')
# 2. 使用自定义类
ui.button('自定义按钮', classes='my-button')
from nicegui import ui
# 示例1:布局控制
with ui.row().classes('items-center justify-between gap-4'):
ui.button('左').classes('q-mr-auto')
ui.button('中')
ui.button('右').classes('q-ml-auto')
# 示例2:文本样式
ui.label('标题').classes('text-h4 text-primary text-weight-bold q-mb-md')
ui.label('正文').classes('text-body1 text-grey-8')
# 示例3:卡片样式
with ui.card().classes('q-pa-lg shadow-5 rounded-borders'):
ui.label('卡片标题').classes('text-h6 q-mb-sm')
ui.label('卡片内容').classes('text-body2')
# 示例4:响应式设计
ui.button('响应式按钮',
classes='text-sm sm:text-base md:text-lg w-full md:w-auto')
# 示例5:状态交互
ui.button('交互按钮',
classes='bg-blue-500 hover:bg-blue-600 active:bg-blue-700 '
'text-white transition-colors duration-200')
# 情况1:动态样式计算
color = 'red'
ui.button('动态颜色', style=f'background-color: {color};')
# 情况2:内联特定样式
ui.button('按钮', style='border-radius: 20px; font-weight: 900;')
# 情况3:需要最高优先级样式
ui.button('按钮', style='color: red !important;')
# 情况4:CSS变量或复杂值
ui.button('渐变按钮',
style='background: linear-gradient(45deg, #FE6B8B, #FF8E53);')
# 情况5:临时调试样式
ui.button('调试', style='border: 2px dashed red;')
# 字符串格式(推荐)
ui.button('按钮', style='color: red; background: blue; font-size: 16px;')
# 字典格式(也支持)
ui.button('按钮', style={'color': 'red', 'background': 'blue'})
# 多行字符串(复杂样式)
ui.button('按钮', style='''
background: linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%);
color: white;
border-radius: 12px;
font-weight: bold;
transition: all 0.3s ease;
''')
# 盒模型
'width: 100px; height: 50px;'
'margin: 10px; padding: 15px;'
'border: 2px solid #ccc; border-radius: 8px;'
# 定位
'position: absolute|relative|fixed|sticky;'
'top: 0; left: 0; right: 0; bottom: 0;'
'z-index: 10;'
# 颜色和背景
'color: #333; background-color: #f0f0f0;'
'background: linear-gradient(to right, #ff7e5f, #feb47b);'
'background-image: url("image.jpg");'
# 文字
'font-size: 16px; font-weight: bold;'
'text-align: center; line-height: 1.5;'
'text-transform: uppercase;'
# 变换和动画
'transform: translateX(10px) rotate(45deg);'
'transition: all 0.3s ease;'
'animation: fadeIn 1s;'
# 布局(Flexbox)
'display: flex; justify-content: center; align-items: center;'
'flex-direction: column; gap: 10px;'
from nicegui import ui
# 示例1:基础样式
ui.button('基础样式',
style='background-color: #4CAF50; color: white; padding: 12px 24px;')
# 示例2:复杂背景
ui.button('渐变按钮',
style='''
background: linear-gradient(45deg, #2196F3, #21CBF3);
color: white;
border: none;
border-radius: 25px;
padding: 12px 30px;
font-size: 16px;
font-weight: bold;
''')
# 示例3:动态样式
for i, color in enumerate(['#FF5252', '#4CAF50', '#2196F3', '#FF9800']):
ui.button(f'按钮 {i+1}',
style=f'background-color: {color}; color: white; margin: 5px;')
# 示例4:Flex布局
with ui.row().style('display: flex; gap: 10px; align-items: center;'):
ui.label('标签').style('font-weight: bold;')
ui.input(placeholder='输入框').style('flex: 1;')
ui.button('搜索')
# 示例5:自定义动画
ui.add_head_html('''
<style>
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
</style>
''')
ui.button('动画按钮',
style='''
animation: pulse 2s infinite;
background-color: #9C27B0;
color: white;
''')
# 优先级从高到低:
# 1. Inline Style (style属性) ← 最高优先级
# 2. Component Props (color, size等)
# 3. Quasar Props (filled, outline等)
# 4. CSS Classes (包括Tailwind和Quasar类) ← 最低优先级
# 示例:冲突解决
ui.button('测试',
color='red', # 组件参数
props='color=blue', # Quasar props - 被覆盖
classes='text-green', # CSS类 - 可能被覆盖
style='color: yellow;') # 内联样式 - 最高优先级
# 最终颜色:黄色(style优先级最高)
from nicegui import ui
# 示例:一个完整的按钮
ui.button(
'提交表单',
# 1. 组件参数 - 基础配置
color='primary',
icon='send',
# 2. Quasar Props - Quasar特有样式和行为
props='''
outline # Quasar样式变体
rounded # Quasar圆角
size=lg # Quasar尺寸
:loading="isSubmitting" # Vue绑定
''',
# 3. Classes - 布局和自定义样式
classes='''
q-mt-lg # Quasar间距
q-px-xl # Quasar内边距
shadow-3 # Quasar阴影
hover:shadow-5 # Quasar悬停效果
w-full md:w-auto # Tailwind响应式宽度
''',
# 4. Style - 特定内联样式
style='''
min-width: 120px; # 最小宽度
transition: all 0.3s ease; # 过渡动画
'''
)
# 示例:表单输入框
ui.input(
# 组件参数
label='邮箱地址',
placeholder='user@example.com',
# Quasar Props
props='''
filled # Quasar填充样式
clearable # Quasar可清除
type=email # HTML5类型
:rules="[val => /.+@.+/.test(val) || '请输入有效邮箱']" # 验证
''',
# Classes
classes='''
q-mb-md # 底部间距
w-full # 全宽
''',
# Style(通常不需要,除非特殊需求)
# style=''
)
from nicegui import ui
defcreate_primary_button(text, **kwargs):
"""创建主要按钮的标准化封装"""
return ui.button(
text,
color='primary',
props='rounded',
classes='q-pa-sm q-ma-xs',
**kwargs
)
defcreate_card(title, content):
"""创建标准化卡片"""
with ui.card().classes('q-pa-md shadow-2 rounded-borders').props('flat bordered'):
ui.label(title).classes('text-h6 q-mb-sm')
ui.label(content).classes('text-body2')
from nicegui import ui
# 响应式按钮
ui.button('响应式按钮',
classes='''
text-xs sm:text-sm md:text-base # 响应式文字大小
w-full sm:w-auto # 移动端全宽,桌面端自适应
q-pa-xs sm:q-pa-sm md:q-pa-md # 响应式内边距
''')
# 响应式网格
with ui.row().classes('''
flex flex-col # 移动端垂直排列
sm:flex-row sm:flex-wrap # 平板端开始横向排列
gap-2 sm:gap-4 # 响应式间距
'''):
for i in range(6):
ui.card().classes('''
w-full # 移动端全宽
sm:w-1/2 # 平板端一半宽度
lg:w-1/3 # 桌面端三分之一宽度
''')
from nicegui import ui
# 定义主题变量
theme = {
'primary': '#2196F3',
'secondary': '#4CAF50',
'spacing': '16px',
}
# 使用主题
ui.button('主题按钮',
style=f'background-color: {theme["primary"]}; '
f'margin: {theme["spacing"]};')
# 动态主题切换
defapply_dark_theme():
ui.query('body').classes('bg-gray-900 text-white')
defapply_light_theme():
ui.query('body').classes('bg-white text-gray-900')
from nicegui import ui
# 1. 使用浏览器开发者工具
# 右键点击元素 → 检查 → 查看应用的样式
# 2. 添加调试类
ui.button('调试按钮',
classes='debug-border',
props='outline',
style='color: red;')
ui.add_head_html('''
<style>
.debug-border {
border: 2px dashed red !important;
}
</style>
''')
# 3. 临时高亮
ui.button('高亮',
style='box-shadow: 0 0 0 3px rgba(255,0,0,0.5);')
from nicegui import ui
# 问题:样式不生效?
# 检查顺序:
# 1. 优先级:style > props > classes
# 2. 特异性:内联样式最高
# 3. !important 标志
# 示例调试
ui.button('测试',
color='red', # 被覆盖
props='color=blue', # 被覆盖
classes='text-green', # 被覆盖
style='color: purple !important;') # 最终生效
"""
Props: Quasar组件属性,控制组件行为和Quasar内置样式
Classes: CSS类名,用于应用预定义样式规则
Style: 内联样式,用于直接设置CSS属性,优先级最高
简单记法:
- 用 Props 控制"组件怎么工作"
- 用 Classes 控制"元素怎么布局"
- 用 Style 控制"元素长什么样"
"""
"""
决策流程:
1. 如果是Quasar组件自带的功能/样式 → 用 Props
- 如:disabled, loading, filled, outline
2. 如果是布局、间距、响应式 → 用 Classes
- 如:q-mt-md, flex, grid, w-full
3. 如果是特定、动态或高优先级样式 → 用 Style
- 如:color: red;, background: linear-gradient(...)
4. 如果不确定 → 先用Classes,不行再试Style
"""
# 可以!而且这是最佳实践
ui.button(
'完整示例',
# Props - Quasar功能
props='outline rounded',
# Classes - 布局和工具类
classes='q-mt-md q-pa-sm flex items-center',
# Style - 特定样式
style='min-width: 100px;'
)
# 注意:如果有冲突,优先级:Style > Props > Classes
"""
学习资源:
1. Quasar Props: https://quasar.dev/vue-components/button#qbtn-api
2. Quasar CSS类: https://quasar.dev/style/shadows#shadow-1-24
3. Tailwind CSS: https://tailwindcss.com/docs
4. NiceGUI文档: https://nicegui.io/documentation
记忆技巧:
- Props: 记住常用几个(filled, outline, rounded, dense)
- Classes: 记住模式(q-{属性}-{值})
- Style: 和普通CSS一样
"""
| 用途 | |||
| 格式 | |||
| 优先级 | |||
| 学习成本 | |||
| 性能 | |||
| 推荐度 | |||
| 何时使用 |
口诀:
"Props 管功能,Classes 管布局,Style 管特殊"
今天就聊到这里,通过本文解析,开发者可以清晰地区分和使用 NiceGUI 中的 Props、Classes 和 Style 了。
作者简介:码上工坊,探索用编程为己赋能,定期分享编程知识和项目实战经验。持续学习、适应变化、记录点滴、复盘反思、成长进步。
重要提示:本文主要是记录自己的学习与实践过程,所提内容或者观点仅代表个人意见,只是我以为的,不代表完全正确,欢迎交流讨论。