news 2026/9/19 21:03:49

Textual 高度样式指南:深入理解 `height` 属性与 `<scalar>` 单位体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Textual 高度样式指南:深入理解 `height` 属性与 `<scalar>` 单位体系

Textual 高度样式指南:深入理解height属性与<scalar>单位体系

【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textual

height是 Textual 中控制组件(Widget)垂直尺寸的核心样式属性,它建立在<scalar>单位体系之上,支持固定单元格、百分比、比例(fr)、相对视口(vw/vh)等多种取值方式。本文以 docs/styles/height.md 为主干,结合 src/textual/css/scalar.py 等源码,完整讲解height的语法、每种单位的计算规则、CSS 与 Python 双路设置方式,以及它和box-sizingmin-heightmax-height的协作关系,让你能精确掌控 Textual 应用的纵向布局。

height属性是什么

height样式用于设置一个 Widget 的高度。它是 Textual 布局系统中与width对称的纵向尺寸属性,两者都接收一个<scalar>类型的值。

在 src/textual/css/styles.py 中,height被声明为:

height = ScalarProperty(percent_unit=Unit.HEIGHT) """Set the height of the widget."""

其中percent_unit=Unit.HEIGHT的含义是:当使用%百分比单位时,高度百分比默认相对于容器的高度计算(这一点与widthpercent_unit=Unit.WIDTH正好对应)。

语法

height: <scalar>;

box-sizing的关系

height默认设置的是**内容区(content area)的高度;只有当box-sizing被设置为border-box(Textual 的默认值)时,height设置的才是边框区(border area)**的高度。也就是说:

  • box-sizing: border-box(默认):height包含边框与内边距,加了paddingborder后组件整体尺寸不变,但内容空间被压缩;
  • box-sizing: content-boxheight只作用于内容区,paddingborder会在其基础上继续撑大组件。

<scalar>单位体系全解

height的取值本质是一个<scalar>长度值。完整的单位参考表(源自 docs/css_types/scalar.md)如下:

单位符号单位名称示例说明
(无)单元格 Cell10单元格(行/列)数量,唯一绝对单位
fr分数 Fraction1fr组件应占据的空间比例
%百分比 Percent75%相对于容器组件的长度
w宽度 Width25w相对于容器组件宽度的百分比
h高度 Height75h相对于容器组件高度的百分比
vw视口宽度 Viewport width25vw相对于视口宽度的百分比
vh视口高度 Viewport height75vh相对于视口高度的百分比
自动 Autoauto尝试计算恰好容纳内容、无需滚动的最优尺寸

对应到源码,这套单位被定义为 src/textual/css/scalar.py 中的Unit枚举,以及符号映射表UNIT_SYMBOL(scalar.py)。

各单位的计算规则

  • Cell(无符号):高度方向上一格即一行。例如height: 10表示组件高度为 10 行。支持整数与浮点数,但浮点数最终会被截断为整数。
  • Fraction(fr:比例分配剩余空间。例如两个并排组件分别设height: 1frheight: 3fr,后者的高度就是前者的 3 倍。
  • Percent(%:相对于容器可用空间的比例。height: 50%表示组件高度为容器高度的 50%。
  • w单位:相对于容器宽度的比例。height: 25w表示组件高度 = 容器宽度 × 25%。若容器宽 100 格,则该组件高 25 格。
  • h单位:相对于容器高度的比例。height: 75h表示组件高度 = 容器高度 × 75%。
  • vw单位:相对于视口宽度的比例,无视中间容器。视口宽度 = 终端宽度减去左右 dock 组件的宽度。height: 6.25vw即视口宽度的 6.25%。
  • vh单位:相对于视口高度的比例,无视中间容器。视口高度 = 终端高度减去上下 dock 组件的高度。height: 75vh即视口高度的 75%。
  • auto:自动计算恰好容纳内容的最优高度。例如一个内容只有一行的Labelheight: auto时其高度就是 1 行。

快速上手:基础示例

原文档附带的入门示例位于 docs/examples/styles/height.py:

from textual.app import App from textual.widget import Widget class HeightApp(App): CSS_PATH = "height.tcss" def compose(self): yield Widget() if __name__ == "__main__": app = HeightApp() app.run()

配套样式表 docs/examples/styles/height.tcss:

Screen > Widget { background: green; height: 50%; color: white; }

运行后,屏幕上会出现一个绿色背景、高度正好占屏幕 50% 的组件。由于Screen(屏幕)是它的直接容器,height: 50%最终解析为「屏幕高度的一半」。

实战对照:所有高度格式一次看全

原文档的进阶示例用 9 个占位组件把全部单位放在同一个界面中对比,演示脚本是 docs/examples/styles/height_comparison.py:

from textual.app import App from textual.containers import VerticalScroll from textual.widgets import Label, Placeholder, Static class Ruler(Static): def compose(self): ruler_text = "·\n·\n·\n·\n•\n" * 100 yield Label(ruler_text) class HeightComparisonApp(App): CSS_PATH = "height_comparison.tcss" def compose(self): yield VerticalScroll( Placeholder(id="cells"), Placeholder(id="percent"), Placeholder(id="w"), Placeholder(id="h"), Placeholder(id="vw"), Placeholder(id="vh"), Placeholder(id="auto"), Placeholder(id="fr1"), Placeholder(id="fr2"), ) yield Ruler() if __name__ == "__main__": app = HeightComparisonApp() app.run()

每个Placeholderid标明其所用的单位,右侧还有一个 dock 的垂直标尺方便目测高度。完整的样式表 docs/examples/styles/height_comparison.tcss 如下:

#cells { height: 2; } #percent { height: 12.5%; } #w { height: 5w; } #h { height: 12.5h; } #vw { height: 6.25vw; } #vh { height: 12.5vh; } #auto { height: auto; } #fr1 { height: 1fr; } #fr2 { height: 2fr; } Screen { layers: ruler; overflow: hidden; } Ruler { layer: ruler; dock: right; width: 1; background: $accent; }

假设终端为 80×24,文档中对每个高度的注释(对应 height_comparison.tcss 中的(1)!(9)!)逐条解释了计算过程:

  1. height: 2—— 固定 2 行高。
  2. height: 12.5%—— 容器(VerticalScroll)高 24 行,12.5% × 24 = 3 行。
  3. height: 5w—— 直接容器宽 80,5% × 80 = 4 行高(注意这里用的是容器的宽度)。
  4. height: 12.5h—— 直接容器高 24,12.5% × 24 = 3 行高(用的是容器的高度)。
  5. height: 6.25vw—— 视口宽 80,6.25% × 80 = 5 行高。
  6. height: 12.5vh—— 视口高 24,12.5% × 24 = 3 行高。
  7. height: auto—— 内容仅一行,因此高度解析为 1。
  8. height: 1fr—— 占据 1 份比例空间,高度是2fr组件的一半。
  9. height: 2fr—— 占据 2 份比例空间,高度是1fr组件的两倍。

这组例子清楚展示了w/hvw/vh的区别:前两者相对直接容器的宽/高计算,后两者相对视口的宽/高计算,与中间容器无关。

CSS 与 Python 双路设置

CSS 方式

/* 显式单元格高度 */ height: 10; /* 百分比高度 */ height: 50%; /* 自动高度 */ height: auto

Python 方式

self.styles.height = 10 # 显式单元格高度,可以是 int self.styles.height = "50%" self.styles.height = "auto"

从源码看,ScalarProperty.__set__(src/textual/css/_style_properties.py)对 Python 侧的赋值做了三种归一化处理:

  • 传入int/float:直接封装为Unit.CELLS单元格单位;
  • 传入字符串:调用Scalar.parse()解析,解析失败会抛出带帮助信息的StyleValueError
  • 传入Scalar对象:原样采用。

无论哪种途径,只要规则真正发生变化,都会触发refresh(layout=True)触发布局重算,保证界面立即响应。

源码级原理:Scalar 的解析与解析

height之所以能支持如此多样的单位,核心在于 src/textual/css/scalar.py 中的Scalar类型(一个由「数值 + 单位 + 百分比基准单位」组成的三元组),其解析正则如下(scalar.py):

_MATCH_SCALAR = re.compile(r"^(-?\d+\.?\d*)(fr|%|w|h|vw|vh)?$").match

Scalar.parse()会先特判auto,其余情况按正则拆分数值与单位符号,再映射为Unit枚举成员;随后resolve()根据单位在RESOLVE_MAP(scalar.py)中选择对应的解析函数:

  • _resolve_cells:直接返回数值本身;
  • _resolve_fraction:返回fraction_unit × 数值
  • _resolve_width数值 × 容器宽度 / 100
  • _resolve_height数值 × 容器高度 / 100
  • _resolve_view_width/_resolve_view_height:分别以视口宽度、视口高度为基准换算。

一个值得注意的细节:Scalar内部还保存了percent_unit(百分比基准单位)。height在声明时传入了Unit.HEIGHT,因此在resolve()中遇到%单位时会先用percent_unit替换后再查RESOLVE_MAP,最终按容器高度计算——这正是「height: 12.5%相对容器高度」这一行为在源码中的落点。

与 min-height、max-height、width 的配合

height不是孤立属性,它通常与以下属性协同工作:

  • min-heightmax-height:限制组件高度的下限与上限。在 styles.py 中,它们同样以ScalarProperty(percent_unit=Unit.HEIGHT)声明,但通过allow_auto=False禁用了auto取值——也就是说min-height/max-height不能写auto
  • width:设置组件宽度,与height共同构成组件的二维尺寸。

常见用法:给一个百分比高度的组件加min-height兜底,避免终端窗口缩小时组件被压得过矮而不可用。

小结

height是 Textual 布局体系中最常用的纵向尺寸属性,其核心在于<scalar>单位的灵活组合:

  • 精确控制用单元格height: 10);
  • 响应式布局用百分比height: 50%)或相对视口的vh
  • 弹性分配空间用fr
  • 自适应内容用auto

理解每种单位相对「直接容器」还是「视口」计算(对应源码中sizeviewport两个入参),再配合box-sizingmin-height/max-height,即可在终端与浏览器两种运行环境下都获得稳定、可预期的纵向布局效果。更多相关样式可参考 docs/styles/index.md 的完整样式目录。

【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 21:01:24

matplotlib动画实战:FuncAnimation绘制小人发射爱心

简介&#xff1a;使用Python的turtle模块绘制“小人发射爱心”图形&#xff0c;是这份PDF教程的核心内容。资源面向Python初学者与趣味编程爱好者&#xff0c;通过一个完整可运行的示例&#xff0c;演示了如何利用标准库turtle实现图形绘制&#xff1a;从定义go_to、head、leg、…

作者头像 李华
网站建设 2026/9/19 21:01:20

美林时钟量化油价:商品属性与金融属性双因子定价模型

简介&#xff1a;本资源是一份聚焦宏观经济周期与能源价格联动机制的专业研究报告&#xff0c;面向金融从业者、大宗商品投资者及经济研究学习者&#xff0c;帮助理解美林时钟模型在油价分析中的实际应用逻辑与当前阶段判断。报告以28页PDF形式呈现&#xff0c;完整覆盖疫情以来…

作者头像 李华
网站建设 2026/9/19 20:55:38

智能服装核心技术拆解:石墨烯发热、AI算法与充气调温工程实践

1. 从一场行业大会看智能服装的底层逻辑第一次看到SG2026第十三届北京国际智能服装服饰产业大会的嘉宾名单时&#xff0c;我正蹲在实验室里给一件石墨烯加热马甲做第17次温升曲线测试。名单上那些大咖专家和领军企业的名字&#xff0c;让我想起五年前刚入行时&#xff0c;整个团…

作者头像 李华