湫羽 發表於 2026-2-28 15:20:00

display: contents 详解

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<blockquote>
<p><code>display: contents</code>&nbsp;是一个相对较新的 CSS 属性值,它会让元素自身不生成任何盒子,但它的子元素和伪元素仍然正常生成。简单说:元素本身从渲染树中消失,但它的孩子还在。</p>
</blockquote>
<h2 data-id="heading-0">基本概念</h2>
<h3 data-id="heading-1">工作原理</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;div class="parent"&gt;
&lt;div class="child"&gt;内容&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/* 正常情况下 */
.parent {
display: block;/* parent 生成一个块级盒子 */
}

/* 使用 contents 后 */
.parent {
display: contents;/* parent 不生成盒子,child 直接"上升"到 parent 的位置 */
}</pre>
</div>
<h3 data-id="heading-2">直观对比</h3>
<p>应用前:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;main&gt;
&lt;div class="grid-container"&gt;&lt;!-- 这个元素只是个包装 --&gt;
    &lt;div&gt;Item 1&lt;/div&gt;
    &lt;div&gt;Item 2&lt;/div&gt;
    &lt;div&gt;Item 3&lt;/div&gt;
&lt;/div&gt;
&lt;/main&gt;</pre>
</div>
<p>应用后:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;main&gt;
&lt;!-- grid-container 元素消失了,但它的子元素还在 --&gt;
&lt;div&gt;Item 1&lt;/div&gt;
&lt;div&gt;Item 2&lt;/div&gt;
&lt;div&gt;Item 3&lt;/div&gt;
&lt;/main&gt;</pre>
</div>
<h2 data-id="heading-3">主要用途</h2>
<h3 data-id="heading-4">1.&nbsp;语义化与布局分离</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;!-- 想要使用 ul,但又需要 flex 布局 --&gt;
&lt;ul style="display: contents;"&gt;
&lt;li&gt;项目1&lt;/li&gt;
&lt;li&gt;项目2&lt;/li&gt;
&lt;li&gt;项目3&lt;/li&gt;
&lt;/ul&gt;
</pre>
</div>
<p>  </p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">ul {
display: contents;/* ul 本身不生成盒子 */
}

/* li 直接参与父容器的布局 */
.parent-of-ul {
display: flex;/* li 会成为 flex 项目,而不是 ul */
}</pre>
</div>
<h3 data-id="heading-5">2.&nbsp;网格布局中的包装器</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}

/* 包装器不破坏网格布局 */
.wrapper {
display: contents;
/* 这个元素不生成盒子,它的子元素直接成为 grid 项目 */
}</pre>
</div>
<p>html</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;div class="grid-container"&gt;
&lt;div&gt;直接项目1&lt;/div&gt;
&lt;div class="wrapper"&gt;&lt;!-- 这个元素不占位置 --&gt;
    &lt;div&gt;包装的项目2&lt;/div&gt;
    &lt;div&gt;包装的项目3&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;直接项目4&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
<h3 data-id="heading-6">3.&nbsp;Flexbox 中的包装器</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.flex-container {
display: flex;
}

.group {
display: contents;/* 子元素直接成为 flex 项目 */
}
</pre>
</div>
<p>  </p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;div class="flex-container"&gt;
&lt;div&gt;项目1&lt;/div&gt;
&lt;div class="group"&gt;&lt;!-- 这个 div 不生成盒子 --&gt;
    &lt;div&gt;组内项目1&lt;/div&gt;&lt;!-- 直接成为 flex 项目 --&gt;
    &lt;div&gt;组内项目2&lt;/div&gt;&lt;!-- 直接成为 flex 项目 --&gt;
&lt;/div&gt;
&lt;div&gt;项目3&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
<h2 data-id="heading-7">实际应用场景</h2>
<h3 data-id="heading-8">场景1:表格布局优化</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;table&gt;
&lt;tr style="display: contents;"&gt;&lt;!-- tr 不生成盒子 --&gt;
    &lt;td&gt;单元格1&lt;/td&gt;
    &lt;td&gt;单元格2&lt;/td&gt;
    &lt;td&gt;单元格3&lt;/td&gt;
    &lt;!-- td 直接成为 table 的子元素 --&gt;
&lt;/tr&gt;
&lt;/table&gt;</pre>
</div>
<h3 data-id="heading-9">场景2:避免多余的 DOM 层级</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/* 原本需要额外 div 来添加样式 */
.card {
display: flex;
}

.card-extra {
display: contents;/* 这个 div 只用于逻辑分组,不影响布局 */
}

/* 现在可以更灵活地组织代码 */</pre>
</div>
<h3 data-id="heading-10">场景3:响应式设计中的重组</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;div class="responsive-grid"&gt;
&lt;!-- 移动端:堆叠显示 --&gt;
&lt;!-- 桌面端:网格显示 --&gt;
&lt;div class="group" style="display: contents;"&gt;
    &lt;div&gt;项目A&lt;/div&gt;
    &lt;div&gt;项目B&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
<h2 data-id="heading-11">注意事项和限制</h2>
<h3 data-id="heading-12">1.&nbsp;对可访问性的影响</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/* ⚠️ 注意:元素本身消失,但语义还在吗? */
.button-group {
display: contents;
role: group;/* 虽然设置了 ARIA 角色,但元素不生成盒子,可能无效 */
}</pre>
</div>
<h3 data-id="heading-13">2.&nbsp;对事件处理的影响</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// ⚠️ 元素不生成盒子,点击事件可能无法在元素上触发
document.querySelector('.contents-element').addEventListener('click', () =&gt; {
// 这个元素在视觉上不存在,点击区域是子元素的
});</pre>
</div>
<h3 data-id="heading-14">3.&nbsp;对背景和边框的影响</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.contents-element {
display: contents;
background: red;    /* ❌ 不会显示,因为元素没有盒子 */
border: 1px solid;/* ❌ 不会显示 */
padding: 10px;      /* ❌ 不会显示 */
margin: 10px;       /* ❌ 不会显示 */
width: 100px;       /* ❌ 不会显示 */
height: 100px;      /* ❌ 不会显示 */
}</pre>
</div>
<h3 data-id="heading-15">4.&nbsp;对伪元素的影响</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.contents-element {
display: contents;
}

.contents-element::before {
content: "✨";/* ✅ 伪元素仍然会显示,成为第一个子元素 */
}</pre>
</div>
<h3 data-id="heading-16">5.&nbsp;浏览器兼容性</h3>
<ul>
<li>Chrome/Edge: 完全支持</li>
<li>Firefox: 完全支持</li>
<li>Safari: 支持但有部分问题</li>
<li>IE: 不支持</li>
</ul>
<h2 data-id="heading-17">调试技巧</h2>
<h3 data-id="heading-18">如何检查 display: contents 的效果</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/* 在开发者工具中检查元素布局 */
.contents-element {
display: contents;
outline: 2px solid red;/* 不会显示,帮助理解元素确实消失了 */
}</pre>
</div>
<h3 data-id="heading-19">临时禁用调试</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.contents-element {
display: contents;
/* 临时查看元素范围 */
display: block;/* 临时改为 block 查看原始位置 */
}</pre>
</div>
<h2 data-id="heading-20">实际案例</h2>
<h3 data-id="heading-21">案例:卡片布局</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;div class="card-grid"&gt;
&lt;!-- 想要分组但不破坏网格 --&gt;
&lt;div class="card-group" style="display: contents;"&gt;
    &lt;div class="card"&gt;卡片1&lt;/div&gt;
    &lt;div class="card"&gt;卡片2&lt;/div&gt;
&lt;/div&gt;
&lt;div class="card-group" style="display: contents;"&gt;
    &lt;div class="card"&gt;卡片3&lt;/div&gt;
    &lt;div class="card"&gt;卡片4&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">.card-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}

/* card-group 不破坏网格,所有卡片直接成为 grid 项目 */</pre>
</div>
<div>
<div>
<h2 data-id="heading-22">总结</h2>
<p><strong>优点:</strong></p>
<ul>
<li>✅ 保持 HTML 语义化</li>
<li>✅ 避免多余的包装元素</li>
<li>✅ 更灵活的布局控制</li>
<li>✅ 减少不必要的 DOM 层级</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>❌ 元素样式(背景、边框等)失效</li>
<li>❌ 事件绑定可能受影响</li>
<li>❌ 可访问性需要考虑</li>
<li>❌ 调试相对困难</li>
</ul>
<p><strong>最佳实践:</strong></p>
<ul>
<li>主要用于布局分组</li>
<li>配合 Grid/Flex 使用效果最好</li>
<li>注意不要依赖元素的样式属性</li>
<li>测试可访问性表现</li>
</ul>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19652567
頁: [1]
查看完整版本: display: contents 详解