Windi CSS display 工具类简写对照表
| 简写 | 属性值 |
|---|---|
block | display: block |
inline-block | display: inline-block |
inline | display: inline |
contents | display: contents |
hidden | display: none |
visible | visibility: visible |
invisible | visibility: hidden |
list-item | display: list-item |
表里少了几个日常用得最多的,补齐:
| 简写 | 属性值 |
|---|---|
flex | display: flex |
inline-flex | display: inline-flex |
grid | display: grid |
inline-grid | display: inline-grid |
table | display: table |
table-cell | display: table-cell |
table-row | display: table-row |
flow-root | display: flow-root |
hidden 和 invisible 的区别
这是表里两个最容易混用的类,但行为差别很大:
hidden(display: none):元素不参与布局,不占空间,后面的元素会顶上来。子元素也一并消失。invisible(visibility: hidden):元素仍然占位,只是画不出来。相当于留了一个透明的坑。
选哪个取决于是否希望布局跟着变:
<!-- 加载态占位,不希望内容出现时页面跳动 -->
<div class="invisible">占位内容</div>
<!-- 条件渲染,希望彻底移除空间 -->
<div class="hidden md:block">只在中屏以上显示</div>
invisible 还有个特点:它是可继承的,但子元素可以用 visible 反向覆盖,父元素隐藏而某个子元素显示是可以做到的。hidden 做不到,父元素 display: none 之后子元素怎么设都不会出现。
两者都会让元素无法被点击和获得焦点。要「看不见但能交互」得用 opacity-0;要「看不见、不占位、但对屏幕阅读器可见」得用 sr-only:
<!-- 屏幕上看不到,屏幕阅读器能读到,无障碍必备 -->
<span class="sr-only">关闭对话框</span>
sr-only 生成的是 position: absolute; width: 1px; height: 1px; clip: rect(0,0,0,0) 这一套,而不是 display: none——后者会让辅助技术也读不到。给纯图标按钮加文字说明时应该用它,直接 hidden 等于没加。
响应式和状态前缀
display 类配前缀是它最主要的用法。Windi 的默认断点和 Tailwind 一致,都是 min-width:
<!-- 移动端隐藏,md(768px)以上显示 -->
<nav class="hidden md:flex"></nav>
<!-- 反过来:移动端显示,md 以上隐藏 -->
<button class="block md:hidden">菜单</button>
<!-- 只在某个区间显示 -->
<div class="hidden md:block lg:hidden">只在 768~1024 之间</div>
断点默认值:sm 640px、md 768px、lg 1024px、xl 1280px、2xl 1536px。
因为是 min-width 逐级覆盖,写「只在小屏显示」必须用 block md:hidden 这种「先给再收」的写法,不能只写一个 sm:block 就指望大屏自动不显示。这是原子化 CSS 里最容易搞错的思路。
Windi 额外提供了 <sm、<md 这类max-width 变体,Tailwind 里对应的是 max-md::
<!-- Windi:小于 md 时隐藏 -->
<div class="<md:hidden"></div>
组合类前缀也能用在 display 上:
<!-- hover 时才出现的操作按钮 -->
<div class="group">
<span class="hidden group-hover:inline-block">编辑</span>
</div>
注意 group-hover:inline-block 生效的前提是被 hover 的祖先带 group 类。这也说明 hidden 和 hover 的组合不能直接写在同一个元素上——元素 display: none 之后本身接收不到 hover 事件。
contents 的实际用途
display: contents 让元素自身的盒子消失,但子元素保留并直接参与祖父的布局。它的用处集中在 flex / grid 场景:包一层组件之后布局塌了,因为多出来的这层 wrapper 变成了唯一的 flex item。
<div class="grid grid-cols-3">
<!-- 没有 contents 时,这个 wrapper 是 1 个网格项,3 个 span 挤在一格里 -->
<div class="contents">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
</div>
用它有两个注意点:一是 contents 元素上的 background、border、padding 全部失效(盒子没了);二是过去在 Safari 和部分浏览器上它会破坏 <table> 和列表的无障碍语义(元素被移出无障碍树),现在主流浏览器已修复,但涉及语义标签时值得多测一下。
flow-root 与 table-cell 的用途
这两个不常见但各有一个不可替代的场景。
flow-root 创建一个新的块级格式化上下文(BFC),专门用来清除浮动和阻止外边距塌陷。相比 overflow-hidden 的好处是不会裁掉溢出内容:
<!-- 包住浮动子元素,父容器高度正常撑开,且子元素的阴影/下拉不会被裁 -->
<div class="flow-root">
<img class="float-left" src="..." />
</div>
table-cell 配 table 用,能做出「等高列」和「宽度自适应内容」的效果,这两件事 flex 做起来反而要绕:
<!-- 两列自动等高,左列宽度贴合内容 -->
<div class="table w-full">
<div class="table-cell w-1 whitespace-nowrap bg-gray-100 p-2">标签</div>
<div class="table-cell p-2">很长的内容……</div>
</div>
w-1 配 whitespace-nowrap 是表格布局的一个惯用技巧:宽度给一个极小值,表格算法会把它收缩到内容的最小宽度。

还没有留言,来发表第一条吧~