Vuetify 组件尺寸与密度(Size & Density)完全指南
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
本文基于 Vuetify 官方文档《Density and sizing》展开,系统讲解size与density两个核心布局属性的取值语义、适用组件、底层实现原理与组合使用技巧。读完本文,你将掌握如何用size精确控制组件的宽高与字号、用density压缩垂直内边距以适配密集型界面(如工具栏、数据表格),并能结合源码理解这两个属性在 Vuetify 内部是如何生成 CSS 类与样式变量的。原文档与配套可运行示例位于 density-and-sizing.md。
Size:控制组件的宽、高与字号
size属性用于增大或缩小组件整体占用的宽度和高度,同时会影响font-size(字号)。它通常应用于按钮、Chip、图标、头像、评分等具有明显尺寸比例的组件。
支持的取值
size提供了一套五档的预定义标尺:
x-small(特小)small(小)default(默认)large(大)x-large(特大)
从源码看,这套预定义值定义在 size.ts 中:
const predefinedSizes = ['x-small', 'small', 'default', 'large', 'x-large']自定义数值尺寸
值得注意的一点是:size的 prop 类型是String | Number,默认值为'default'。也就是说,除了使用上述五档预设值,你还可以直接传入任意数字或长度字符串,将其作为组件的像素宽高:
<v-avatar :size="64"></v-avatar> <v-avatar size="6rem"></v-avatar>对应 size.ts 的实现逻辑:
if (includes(predefinedSizes, size)) { sizeClasses = `${name}--size-${size}` } else if (size) { sizeStyles = { width: convertToUnit(size), height: convertToUnit(size), } }即:命中预设值时输出形如v-btn--size-large的类名;传入自定义值时则通过convertToUnit转换为 CSS 单位,直接以内联样式(width/height)作用于组件。
实操示例
官方示例 size.vue 通过一个v-btn-toggle在五档尺寸间切换,并同步应用到按钮、Chip、评分与头像上:
<v-btn :size="size" class="me-2 mb-2" text="Export" ></v-btn> <v-chip :size="size" class="me-2 mb-2" text="Completed" ></v-chip> <v-rating :size="size" label="Customer Satisfaction" length="3" ></v-rating> <v-avatar :size="size" class="mb-2 me-2" image="https://cdn.vuetifyjs.com/docs/images/avatars/dark.png" ></v-avatar>其中size为绑定在切换按钮上的响应式变量(默认'default'):
const size = shallowRef('default')Density:压缩垂直空间
density属性用于减少组件的垂直内边距(vertical padding),部分组件还会同步缩小字号。对于方形或圆形组件(如图标),它同时会减少水平内边距。这是让密集列表、表格、工具栏等高信息量界面更紧凑的主要手段。
支持的取值
density提供三档密度:
default(默认)comfortable(舒适)compact(紧凑)
对应的类型定义与校验逻辑位于 density.ts:
const allowedDensities = [null, 'default', 'comfortable', 'compact'] as const export type Density = null | 'default' | 'comfortable' | 'compact' export const makeDensityProps = propsFactory({ density: { type: String as PropType<Density>, default: 'default', validator: (v: any) => allowedDensities.includes(v), }, }, 'density')可以看到,Vuetify 对传入值做了白名单校验(validator),不合法的取值会被框架拒绝。
类名生成机制
useDensity组合式函数会基于组件实例名与当前密度值生成一个响应式类名:
export function useDensity (props: DensityProps, name = getCurrentInstanceName()) { const densityClasses = toRef(() => { return `${name}--density-${props.density}` }) return { densityClasses } }因此,一个v-btn在density="compact"时会得到v-btn--density-compact类,Sass 样式据此调整内边距与高度。
实操示例
官方示例 density.vue 演示了密度对按钮、Chip、工具栏与文本输入框的影响:
<v-btn :density="density" class="me-2 mb-2" text="Submit" ></v-btn> <v-chip :density="density" class="me-2 mb-2" text="In Progress" ></v-chip> <v-toolbar :density="density" class="mb-2" elevation="1" title="Daily Reports" ></v-toolbar> <v-text-field :density="density" label="Search Query" model-value="Data tables" prepend-inner-icon="mdi-magnify" variant="solo" ></v-text-field>组合使用:Size × Density
size与density是两个正交的属性:size决定整体尺度(宽、高、字号),density决定内部留白密度。二者可以自由组合,一次性调整组件的整体观感,例如「大尺寸 + 紧凑密度」可以在保持醒目字号的同时尽量减少占用的垂直空间。
官方示例 density-and-size.vue 使用两个滑块分别驱动size与density,并同时应用到按钮、Chip 与头像上:
<v-btn :density="densities[density]" :size="sizes[size]" class="me-2 mb-2" prepend-icon="$vuetify" text="Default Button" ></v-btn>对应脚本中的取值映射:
const size = shallowRef(2) const density = shallowRef(2) const densities = ['compact', 'comfortable', 'default'] const sizes = ['x-small', 'small', 'default', 'large', 'x-large']这种「双滑块 + 组件实时预览」的模式非常适合在设计阶段快速比对不同组合的视觉密度。
底层原理:Sass 混入如何计算尺寸与密度
从源码层面看,size与density的最终效果由各组件自身的 Sass 混入(mixin)实现。以按钮为例,VBtn/_mixins.scss 中:
@mixin button-sizes ($map: $button-sizes, $immediate: false) { @each $sizeName, $multiplier in settings.$size-scales { $size: map.get($map, 'font-size') + math.div(2 * $multiplier, 16); $height: map.get($map, 'height') + (settings.$size-scale * $multiplier); $selector: '.v-btn--size-#{$sizeName}'; #{$selector} { --v-btn-size: #{$size}; --v-btn-height: #{$height}; font-size: var(--v-btn-size); min-width: tools.roundEven($height * map.get($map, 'width-ratio')); padding: 0 tools.roundEven(math.div($height, map.get($map, 'padding-ratio'))); } } }可以看到,每一档size都会依据全局尺寸标尺(settings.$size-scales、settings.$size-scale)计算并暴露--v-btn-size、--v-btn-height两个 CSS 变量,再派生font-size、min-width与水平padding。
密度部分则基于高度变量做增量计算:
@mixin button-density ($properties, $densities) { @each $density, $multiplier in $densities { $value: calc(var(--v-btn-height) + #{$multiplier * settings.$spacer}); &.v-btn--density-#{$density} { // 将 $value 应用到 height / padding 等属性 } } }即:density通过「基础高度 + 密度增量 × 全局 spacer」的公式得到最终高度与内边距,compact对应负增量,default为零增量,comfortable为正增量。同样的模式也出现在 Chip(见 VChip/_mixins.scss)等组件中,只是各自维护一套$size-scales与$densities映射。
注意事项
- 并非所有组件都有高度过渡动画:官方文档明确提示——当动态切换
density时,不是所有组件都带有默认的「高度变化过渡」动画。这意味着在运行时切换密度可能出现高度瞬间跳变,若需要平滑动画,应自行添加transition样式。 density的覆盖范围:density主要作用于内边距与字号,不改变组件的整体宽度与字体排版的水平尺度;comfortable与compact之间的差异通常为几个像素的垂直留白,请根据界面信息密度按需选用。- 自定义
size的局限:传入数值/长度字符串时,size以等宽等高(正方形)方式生成内联样式,适用于头像、图标、评分等方形组件;对按钮等需要保持宽高比例的组件,建议使用五档预设值。
相关组件与继续探索
size与density被大量组件以组合式函数方式复用。通过makeDensityProps/makeSizeProps的引用关系(见 composables 与 size.ts),可以看到支持这两个属性的组件包括但不限于:VBtn、VChip、VAvatar、VRating、VTabs、VTable、VList、VInput/VTextField、VToolbar、VAlert、VCard、VPagination、VTimeline、VTreeview等(具体组件实现分布在 packages/vuetify/src/components 下各自的*.tsx文件中)。
如果需要为某个具体组件查看可用的密度档位与尺寸标尺,可直接阅读该组件目录下的_mixins.scss与variables.scss,例如按钮的样式入口为 VBtn.sass。官方文档中与本节主题强相关的组件还包括按钮、Chip、列表等,可在文档导航的对应组件页中找到更多组合示例。
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考