You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用纯CSS解决含子UL的LI边距布局问题?无::text伪元素

纯CSS实现菜单布局需求

现有菜单布局中,Item 4和4.2包含子UL。希望仅为文本节点应用padding,但CSS暂不支持::text伪元素。尝试为子列表设置负margin,却无法让子列表横向填满LI元素。需要实现以下三点:

  • 所有菜单项宽度匹配最大可见项;
  • 所有水平内边距为--menu-padding;
  • 包含子UL的LI无水平内边距,但文本与其边框有视觉上等于--menu-padding的间距。

寻求纯CSS解决方案,不使用JavaScript且不修改HTML。目标效果示意图:
目标效果


现有代码

CSS

:root {
  --menu-clr-item-bk:#84744dff;
  --menu-clr-item-tx:#ddddddff;
  --menu-clr-item-tx-hov:#84744dff;
  --menu-clr-item-bk-hov:#ddddddff;
  --menu-clr-item-tx-clildhov:#ccccccff;
  --menu-clr-item-bk-clildhov:#847b65ff;
  --menu-h-clr-tile-bk:#ddddddff;
  --menu-h-clr-item-bk:var(--menu-clr-item-bk);
  --menu-h-clr-item-bk-hov:var(--menu-clr-item-bk-hov);
  --menu-h-clr-item-tx:var(--menu-clr-item-tx);
  --menu-h-clr-item-tx-hov:var(--menu-clr-item-tx-hov);
  --menu-h-separator:0;
  --menu-h-shadow:none;
  --menu-v-clr-tile-bk:#ddddddff;
  --menu-v-clr-item-bk:var(--menu-clr-item-bk);
  --menu-v-clr-item-bk-hov:var(--menu-clr-item-bk-hov);
  --menu-v-clr-item-tx:var(--menu-clr-item-tx);
  --menu-v-clr-item-tx-hov:var(--menu-clr-item-tx-hov);
  --menu-v-separator:1px;
  --menu-v-shadow:0.1em 0.1em 0.1em #0008;
  --menu-padding:0.5em;
  --menu-checkmargin:0.5em;
  --menu-checksize:1em; }

* {
  box-sizing: border-box; }

body, html {
  height: 100%; }

nav > h1 {
  display: none; }

/* all menues and items */
nav ul {
  position: absolute;
  white-space: nowrap;
  display: flex;
  width: fit-content;
  list-style-type: none;
  margin: 0;
  padding: 0; }
  nav ul > li:has(> a) {
    padding: 0; }
    nav ul > li:has(> a) > a {
      display: inline-block;
      padding: var(--menu-padding); }
  nav ul li:focus-within > ul {
    display: flex; }

nav li {
  position: relative;
  align-items: left;
  display: flex;
  box-sizing: border-box;
  justify-content: space-between;
  line-height: 1;
  padding: var(--menu-padding); }
  nav li:has(ul:hover):hover {
    color: #999;
    background: #444; }
  nav li:hover {
    color: #fff;
    background: #000; }

nav ul:not(nav ul ul) {
  position: relative;
  text-align: left;
  flex-direction: column;
  white-space-collapse: collapse;
  left: 0;
  row-gap: var(--menu-v-separator);
  background: var(--menu-v-clr-tile-bk);
  box-shadow: var(--menu-v-shadow); }
  nav ul:not(nav ul ul) > li:focus-within:has(ul) {
    flex-direction: column;
    justify-content: space-between; }
  nav ul:not(nav ul ul) > li {
    display: flex; }
  nav ul:not(nav ul ul) > li > ul {
    bottom: calc(-1 * var(--menu-padding)); }
  nav ul:not(nav ul ul) ul {
    position: relative; }

nav ul:not(nav ul ul) > li {
  width: 100%;
  color: var(--menu-v-clr-item-tx);
  background: var(--menu-v-clr-item-bk); }

nav ul ul {
  display: none;
  position: relative;
  text-align: left;
  flex-direction: column;
  white-space-collapse: collapse;
  row-gap: var(--menu-v-separator);
  background: var(--menu-v-clr-tile-bk);
  box-shadow: var(--menu-v-shadow); }
  nav ul ul > li:focus-within:has(ul) {
    flex-direction: column;
    justify-content: space-between; }
  nav ul ul > li {
    display: flex; }
  nav ul ul > li > ul {
    bottom: calc(-1 * var(--menu-padding)); }
  nav ul ul ul {
    position: relative; }

nav li li {
  color: var(--menu-v-clr-item-tx);
  background: var(--menu-v-clr-item-bk); }

HTML

<!DOCTYPE html>
<html><head>
</head><body>
<nav>
<ul>
<li tabindex="0">[Item 1]</li>
<li tabindex="0">[Item 2]
<ul>
<li tabindex="0">[Item 2.1]</li>
<li>[Item 2.2] some</li>
<li tabindex="0">[Item 2.3]</li>
</ul>
</li>
<li tabindex="0">[Item 3]</li>
<li tabindex="0">[Item 4]
<ul tabindex="-1">
<li tabindex="0">[Item 4.1] some</li>
<li tabindex="0">[Item 4.2]
<ul tabindex="-1">
<li tabindex="0">[Item 4.2.1]
<ul tabindex="-1">
<li tabindex="0">[Item 4.2.1.1]</li>
<li tabindex="0">[Item 4.2.1.2]</li>
<li tabindex="0">[Item 4.2.1.3]</li>
</ul>
<li tabindex="0">[Item 4.2.2]</li>
<li><a href="">[Item 4.2.3]</a></li>
</ul>
</li>
<li tabindex="0">[Item 4.3]</li>
</ul>
</li>
<li tabindex="0">[Item 5]</li>
<li tabindex="0">[Item 6]
</li>
</ul>
</nav>
</body></html>

解决方案

通过Grid布局+伪间距列+负margin组合实现,无需修改HTML结构:

修改后的完整CSS

:root {
  --menu-clr-item-bk:#84744dff;
  --menu-clr-item-tx:#ddddddff;
  --menu-clr-item-tx-hov:#84744dff;
  --menu-clr-item-bk-hov:#ddddddff;
  --menu-clr-item-tx-clildhov:#ccccccff;
  --menu-clr-item-bk-clildhov:#847b65ff;
  --menu-h-clr-tile-bk:#ddddddff;
  --menu-h-clr-item-bk:var(--menu-clr-item-bk);
  --menu-h-clr-item-bk-hov:var(--menu-clr-item-bk-hov);
  --menu-h-clr-item-tx:var(--menu-clr-item-tx);
  --menu-h-clr-item-tx-hov:var(--menu-clr-item-tx-hov);
  --menu-h-separator:0;
  --menu-h-shadow:none;
  --menu-v-clr-tile-bk:#ddddddff;
  --menu-v-clr-item-bk:var(--menu-clr-item-bk);
  --menu-v-clr-item-bk-hov:var(--menu-clr-item-bk-hov);
  --menu-v-clr-item-tx:var(--menu-clr-item-tx);
  --menu-v-clr-item-tx-hov:var(--menu-clr-item-tx-hov);
  --menu-v-separator:1px;
  --menu-v-shadow:0.1em 0.1em 0.1em #0008;
  --menu-padding:0.5em;
  --menu-checkmargin:0.5em;
  --menu-checksize:1em; }

* {
  box-sizing: border-box; }

body, html {
  height: 100%; }

nav > h1 {
  display: none; }

/* 改用Grid确保菜单项宽度自动匹配最大项 */
nav ul {
  position: absolute;
  white-space: nowrap;
  display: grid;
  grid-template-columns: 1fr;
  width: fit-content;
  list-style-type: none;
  margin: 0;
  padding: 0; }

nav ul > li:has(> a) {
  padding: 0; }
nav ul > li:has(> a) > a {
  display: block;
  padding: var(--menu-padding); }

nav ul li:focus-within > ul {
  display: grid; }

/* 基础LI样式 */
nav li {
  position: relative;
  align-items: center;
  display: grid;
  box-sizing: border-box;
  line-height: 1;
  padding: var(--menu-padding); }

/* 含子菜单的LI:移除水平内边距,用三列网格模拟文本间距 */
nav li:has(> ul) {
  padding-left: 0;
  padding-right: 0;
  grid-template-columns: var(--menu-padding) 1fr var(--menu-padding);
}
nav li:has(> ul) > :first-child:not(ul) {
  grid-column: 2;
}

/* 子菜单横向填满父LI */
nav li > ul {
  grid-column: 1 / -1;
  margin-left: calc(-1 * var(--menu-padding));
  margin-right: calc(-1 * var(--menu-padding));
  width: calc(100% + 2 * var(--menu-padding)); }

/* 保留原有hover交互 */
nav li:has(ul:hover):hover {
  color: #999;
  background: #444; }
nav li:hover {
  color: #fff;
  background: #000; }

nav ul:not(nav ul ul) {
  position: relative;
  text-align: left;
  white-space-collapse: collapse;
  left: 0;
  row-gap: var(--menu-v-separator);
  background: var(--menu-v-clr-tile-bk);
  box-shadow: var(--menu-v-shadow); }
nav ul:not(nav ul ul) > li:focus-within:has(ul) {
  grid-template-columns: var(--menu-padding) 1fr var(--menu-padding); }
nav ul:not(nav ul ul) > li {
  display: grid; }
nav ul:not(nav ul ul) > li > ul {
  bottom: calc(-1 * var(--menu-padding)); }
nav ul:not(nav ul ul) ul {
  position: relative; }

nav ul:not(nav ul ul) > li {
  width: 100%;
  color: var(--menu-v-clr-item-tx);
  background: var(--menu-v-clr-item-bk); }

nav ul ul {
  display: none;
  position: relative;
  text-align: left;
  grid-template-columns: 1fr;
  white-space-collapse: collapse;
  row-gap: var(--menu-v-separator);
  background: var(--menu-v-clr-tile-bk);
  box-shadow: var(--menu-v-shadow); }
nav ul ul > li:focus-within:has(ul) {
  grid-template-columns: var(--menu-padding) 1fr var(--menu-padding); }
nav ul ul > li {
  display: grid; }
nav ul ul > li > ul {
  bottom: calc(-1 * var(--menu-padding)); }
nav ul ul ul {
  position: relative; }

nav li li {
  color: var(--menu-v-clr-item-tx);
  background: var(--menu-v-clr-item-bk); }

关键调整说明

  1. 宽度统一:所有菜单容器改用display: grid+grid-template-columns: 1fr,自动让菜单项宽度匹配最大内容项;
  2. 文本间距模拟:给含子UL的LI设置三列网格,文本放在中间列,左右列宽度等于--menu-padding,替代直接给LI加内边距;
  3. 子菜单填满宽度:子菜单设置grid-column: 1 / -1跨越所有列,再通过负margin和宽度计算横向填满父容器。

内容的提问来源于stack exchange,提问作者rhavin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:24:53