跳到主要内容

7 篇博文 含有标签「CSS」

查看所有标签

修复通用 hover 选择器穿透嵌套 Group 导致的卡片悬浮错乱

· 阅读需 3 分钟

在为客户开发 WordPress FSE Block Theme 时发现:博客列表页的卡片悬浮时文字区域发生偏移,但卡片外框不动,视觉上非常违和。记录根因与解法。

TL;DR

通用卡片 hover 选择器 .wp-block-columns .wp-block-column > .wp-block-group:hover 会匹配到卡片内部嵌套的文字 group,导致悬浮时内层文字偏移而外层卡片不动。修复方式:用 .wp-block-post-template 前缀重置内层 group 的 hover 效果。

问题现象

博客列表页使用卡片式布局(外层 border group 包裹图片 + 文字 group)。鼠标悬浮卡片时:

  • 内部的标题和摘要文字产生 translateY(-4px) 位移
  • 外层卡片的 border 和 shadow 没有任何变化
  • 视觉效果像文字"飘出"了卡片

根因

FSE 中卡片 pattern 的 HTML 结构是嵌套的:

<!-- 外层卡片 group (有 border) -->
<div class="wp-block-group has-border-color ...">
<img ... /> <!-- 特色图片 -->

<!-- 内层文字 group -->
<div class="wp-block-group" style="padding:...">
<h2>文章标题</h2>
<p>摘要文字...</p>
</div>
</div>

主题中定义了一个通用 hover 特效:

.wp-block-columns .wp-block-column > .wp-block-group:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
}

这个选择器的本意是让整张卡片悬浮上移。但在博客列表页中,post-template 块内部的卡片也被 wp-block-columns 包裹,导致选择器同时命中了内层文字 group(它也是 .wp-block-column > .wp-block-group)。

由于内层 group 没有 border 和 shadow,只表现为文字位移,而外层卡片没有位移效果。

解决方案

分两步处理:重置内层 + 给外层单独加 hover

1. 重置内层 group 的 hover

.wp-block-post-template 前缀提高优先级,把内层 group 的所有 hover 效果清零:

/* Reset hover for inner groups inside post template cards */
.wp-block-post-template .wp-block-columns .wp-block-column > .wp-block-group {
transition: none;
}
.wp-block-post-template .wp-block-columns .wp-block-column > .wp-block-group:hover {
transform: none;
box-shadow: none;
}

2. 给外层卡片加独立的 hover

外层卡片有 .has-border-color 类,用它做精确匹配:

/* Blog card (outer bordered group) -- hover lift + shadow */
.wp-block-post-template .wp-block-group.has-border-color {
transition:
transform 0.3s ease-out,
box-shadow 0.3s ease-out;
}
.wp-block-post-template .wp-block-group.has-border-color:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
}

为什么不直接缩小通用选择器范围?

通用选择器被多个 pattern 共享(features-grid、pricing、testimonial 等),这些 pattern 的 group 只有一层,不存在嵌套穿透问题。缩小通用选择器反而会破坏其他 pattern 的 hover 效果。

重置内层比限制外层更可靠,因为:

  • 不影响其他使用通用 hover 的 pattern
  • 精确针对有嵌套问题的场景
  • CSS 层面完全隔离,不需要修改任何 HTML/PHP

经验总结

在 FSE Block Theme 中添加 hover 特效前,务必:

  1. 检查 pattern 的实际 HTML 嵌套结构
  2. 确认选择器只命中目标元素(外层容器),不会穿透到内部 group
  3. 如果多个 pattern 共享同一选择器,优先用"重置内层"而非"限制外层"

对类似需求感兴趣?联系合作

修复 CSS ::before 伪元素装饰纹理覆盖按钮的问题

· 阅读需 3 分钟

TL;DR

::before 伪元素实现容器背景装饰纹理(圆点/网格)时,必须同时设置 opacitypointer-events: nonez-index: -1。缺少 opacity 导致纹理 100% 不透明,缺少 z-index 导致纹理覆盖按钮等子元素。

问题现象

FSE 主题的 CTA 横幅区域使用 ::before 伪元素渲染装饰性圆点纹理。预期效果是微妙的背景点缀,实际效果是圆点以完全不透明状态覆盖在按钮表面:

/* 问题代码 — 纹理完全不透明且覆盖子元素 */
.has-dots-pattern::before {
content: "";
position: absolute;
inset: 0;
background-image: radial-gradient(circle, currentColor 1px, transparent 1px);
background-size: 20px 20px;
pointer-events: none;
/* 缺少 opacity — 纹理 100% 不透明 */
/* 缺少 z-index — 纹理覆盖子内容 */
}

按钮表面出现密集的白色圆点,CTA 区域的渐变背景上也布满了明显的网格线。

根因

::before 伪元素实现装饰纹理时有三个关键属性,缺一不可:

1. opacity — 控制纹理透明度

radial-gradient 生成的是实心圆点,currentColor 继承文本颜色。在深色背景上,白色实心圆点会非常醒目。缺少 opacity 时默认值为 1,纹理完全不透明。

2. z-index: -1 — 将纹理推到子元素后方

::before 设置了 position: absolute,在默认层叠上下文中,定位元素的绘制顺序晚于正常流元素。当容器是 position: relative 时,z-index: -1 将伪元素推到容器背景之后、子内容之前,确保按钮等子元素显示在纹理之上。

3. pointer-events: none — 防止拦截点击

这是最容易被记住的一个,因为它直接影响交互。没有它,纹理层会拦截点击事件。

同一个项目中存在正确实现的对照代码,说明是复制时遗漏了属性:

/* 正确实现 — 独立元素方式 */
.cclee-dots-pattern {
position: absolute;
inset: 0;
background-image: radial-gradient(circle, currentColor 1px, transparent 1px);
background-size: 24px 24px;
opacity: 0.08; /* 有 */
pointer-events: none;
/* 独立元素由 HTML 层级控制层叠,无需 z-index */
}

解决方案

::before 伪元素补上 opacityz-index: -1

/* 修复后 */
.has-dots-pattern {
position: relative;
}
.has-dots-pattern::before {
content: "";
position: absolute;
inset: 0;
background-image: radial-gradient(circle, currentColor 1px, transparent 1px);
background-size: 20px 20px;
opacity: 0.08; /* 添加:8% 不透明度 */
pointer-events: none;
z-index: -1; /* 添加:退到子内容后方 */
}

网格纹理同理:

.has-grid-pattern {
position: relative;
}
.has-grid-pattern::before {
content: "";
position: absolute;
inset: 0;
background-image:
linear-gradient(currentColor 1px, transparent 1px),
linear-gradient(90deg, currentColor 1px, transparent 1px);
background-size: 40px 40px;
opacity: 0.05; /* 网格更淡,5% 不透明度 */
pointer-events: none;
z-index: -1;
}

装饰纹理伪元素的完整检查清单

属性作用缺失后果
opacity: 0.05~0.1控制纹理透明度纹理完全不透明,喧宾夺主
z-index: -1层叠在子元素后方纹理覆盖按钮等子内容
pointer-events: none不拦截鼠标事件点击穿透失败

三个属性必须同时存在,这是 ::before 装饰纹理的固定模式。


对类似需求感兴趣?联系合作

修复 FSE Group 块 layout 属性覆盖自定义 CSS 的问题

· 阅读需 3 分钟

TL;DR

WordPress FSE Group 块的 layout 属性会自动生成 is-layout-* CSS 类,这些类的样式优先级高于普通自定义 CSS,导致尺寸设置失效。解决方案:1) 块注释中使用 "layout":{"type":"default"} 避免生成额外布局类;2) CSS 中使用 !important 强制覆盖;3) 关键:添加 padding: 0 !important 清除 Group 块默认内边距。

问题现象

Timeline 组件的年份圆点应显示为 80px 正圆,实际却呈现为椭圆:

<!-- 块注释中的尺寸设置 -->
<!-- wp:group {"style":{"dimensions":{"width":"80px","height":"80px"}},"layout":{"type":"flex",...}} -->
/* 自定义 CSS */
.cclee-timeline-dot {
width: 80px;
height: 80px;
border-radius: 50%;
}

无论调整 CSS 还是块属性,圆点始终被拉伸变形。

根因

WordPress FSE 的 Group 块会根据 layout 属性自动添加布局相关的 CSS 类:

<div class="wp-block-group cclee-timeline-dot is-layout-flow">

这些 is-layout-* 类来自 WordPress 核心样式表,其样式规则会覆盖自定义 CSS。同时,Group 块存在默认 padding,会撑大元素导致尺寸计算偏差。

关键问题点:

  1. layout: {"type": "flex"} 生成 is-layout-flex 类,子元素受 flexbox 拉伸影响
  2. 块注释中的 style.dimensions 转为 inline style,但被布局类样式覆盖
  3. Group 块默认 padding 增加了元素实际尺寸

解决方案

1. 修改块注释,使用 default layout

<!-- wp:group {"className":"cclee-timeline-dot","style":{"border":{"radius":"50%"}},"backgroundColor":"accent","textColor":"base","layout":{"type":"default"}} -->
<div class="wp-block-group cclee-timeline-dot has-base-color has-accent-background-color has-text-color has-background" style="border-radius:50%">

移除 style.dimensions 和复杂的 flex layout,改用 "layout":{"type":"default"}

2. CSS 强制覆盖 + 清除默认 padding

/* Timeline: Fixed circle dot */
.wp-block-group.cclee-timeline-dot {
width: 80px !important;
height: 80px !important;
min-width: 80px !important;
min-height: 80px !important;
flex-shrink: 0 !important;
aspect-ratio: unset !important;
border-radius: 50% !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
align-self: center !important;
box-sizing: border-box !important;
text-align: center !important;
padding: 0 !important; /* 关键:清除默认 padding */
}

.wp-block-group.cclee-timeline-dot p {
margin: 0 !important;
white-space: nowrap !important;
line-height: 1 !important;
overflow: visible !important;
}

3. 使用 :has() 控制父容器

防止父级 Column 被 flexbox 拉伸:

.wp-block-columns .wp-block-column:has(.cclee-timeline-dot) {
flex-shrink: 0 !important;
flex-basis: 100px !important;
width: 100px !important;
}

关键发现

padding: 0 !important 是最终解决方案。Group 块的默认 padding 会撑大元素,即使设置了 width/height,实际渲染尺寸仍会超出预期。


对类似需求感兴趣?联系合作

用 Flex 布局对齐 Docusaurus 文档页标题图标

· 阅读需 3 分钟

TL;DR

Docusaurus 文档页标题中的 SVG 图标与文字对齐,推荐使用 display: flex + align-items: center + gap,配合 .theme-doc-markdown 选择器精准隔离 docs 页面,不影响 blog。

问题现象

在 Docusaurus 文档中使用内联 SVG 图标作为标题装饰:

## 🚀 快速开始

或通过 MDX 组件:

## <RocketIcon /> 快速开始

默认情况下,SVG 图标与文字基线对齐,视觉效果偏上:

🚀 快速开始     ← 图标偏上,与文字顶部对齐

传统解法是 vertical-align: middle + margin-right,但存在以下问题:

  1. 图标大小变化时需要调整 margin
  2. 行高变化时对齐可能失效
  3. 多行标题时对齐表现不一致

根因

SVG 默认是 inline 元素,参与行内布局。vertical-align: middle 基于当前行的 x-height 计算,受字体、行高、图标尺寸等多因素影响,难以精确控制。

更深层的问题是选择器作用范围。Docusaurus 的 .markdown 类同时作用于 docs 和 blog 页面,直接修改会影响全局。

解决方案

1. 使用 Flex 布局

Flex 的 align-items: center 基于容器高度计算,与字体无关,对齐更稳定:

/* 文档页标题图标对齐 */
.theme-doc-markdown h1,
.theme-doc-markdown h2,
.theme-doc-markdown h3,
.theme-doc-markdown h4 {
display: flex;
align-items: center;
gap: 0.75rem;
}

2. 重置 SVG 原有样式

覆盖全局 .markdownmargin-rightvertical-align

.theme-doc-markdown h1 svg,
.theme-doc-markdown h2 svg,
.theme-doc-markdown h3 svg,
.theme-doc-markdown h4 svg {
margin-right: 0;
vertical-align: baseline;
flex-shrink: 0; /* 防止图标被压缩 */
}

3. 选择器隔离

Docusaurus 提供了页面特定的类名:

选择器作用范围
.markdowndocs + blog 全局
.theme-doc-markdown仅 docs 文档页
article仅 blog 文章页

使用 .theme-doc-markdown 精准修改文档页,blog 页保持原有样式。

完整代码

/* ========== Docs 文档页样式 ========== */

/* 文档页标题图标对齐 */
.theme-doc-markdown h1,
.theme-doc-markdown h2,
.theme-doc-markdown h3,
.theme-doc-markdown h4 {
display: flex;
align-items: center;
gap: 0.75rem;
}

.theme-doc-markdown h1 svg,
.theme-doc-markdown h2 svg,
.theme-doc-markdown h3 svg,
.theme-doc-markdown h4 svg {
margin-right: 0;
vertical-align: baseline;
flex-shrink: 0;
}

FAQ

Q: Docusaurus 中 .markdown 和 .theme-doc-markdown 有什么区别?

.markdown 是 Docusaurus 全局内容样式类,同时应用于 docs 文档页和 blog 博客页。.theme-doc-markdown 是文档页专用容器类,仅作用于 /docs/* 路径下的页面,适合做文档页专属样式。

Q: 为什么用 gap 而不是 margin-right?

gap 是 Flexbox/Grid 的间距属性,与 align-items: center 配合更自然,不依赖元素自身的 margin。当图标隐藏或不存在时,gap 不会产生多余空白,而 margin-right 会。

Q: flex-shrink: 0 有什么作用?

防止 flex 子项在容器空间不足时被压缩。SVG 图标通常有固定尺寸,压缩会导致变形模糊。设置 flex-shrink: 0 确保图标保持原始大小。

修复 Tailwind Preflight 重置 Docusaurus 面包屑样式

· 阅读需 2 分钟

TL;DR

Docusaurus 引入 Tailwind 后,Preflight 的 CSS Reset 会重置 <ul> 元素的 list-stylemarginpadding,导致面包屑导航样式丢失。解决方法是在 custom.css 中添加显式覆盖样式。

问题现象

在 Docusaurus 项目中引入 Tailwind CSS 后,文档页的面包屑导航(Breadcrumbs)样式异常:

  • 列表样式丢失(list-style 被重置为 none
  • 间距消失(marginpadding 被重置为 0)
  • 布局可能错乱(display 可能被影响)

查看浏览器开发者工具,发现 .breadcrumbs 的计算样式中,这些属性被 Preflight 重置:

/* Tailwind Preflight 重置 */
ul, ol {
list-style: none;
margin: 0;
padding: 0;
}

根因

Tailwind Preflight 是一套基于 modern-normalize 的 CSS Reset,它在 @tailwind base 阶段注入,目的是提供一致的跨浏览器样式基准。

问题在于:Docusaurus 的 .breadcrumbs 组件使用 <ul> 元素,依赖浏览器默认的 flex 布局和间距。Preflight 的重置规则优先级较高,覆盖了 Docusaurus 的默认样式。

由于 Preflight 是全局注入的,任何使用 <ul>/<ol> 的第三方组件都可能受影响。

解决方案

src/css/custom.css 中添加显式覆盖样式,使用 !important 确保优先级:

/* ========== Breadcrumbs 面包屑 ========== */
.theme-doc-breadcrumbs {
margin-bottom: 1.5rem;
}

.breadcrumbs {
display: flex !important;
flex-wrap: wrap;
align-items: center;
list-style: none;
margin: 0;
padding: 0;
}

.breadcrumbs__item {
display: flex !important;
align-items: center;
gap: 0.5rem;
}

关键点

  1. .breadcrumbs 使用 display: flex !important 确保水平布局
  2. list-style: none 是预期行为(面包屑不需要圆点)
  3. .breadcrumbs__item 添加 gap: 0.5rem 控制元素间距

FAQ

Q: 为什么需要 !important?

Tailwind Preflight 在 @tailwind base 阶段注入,其选择器权重可能与 Docusaurus 默认样式相当。使用 !important 可以确保自定义样式生效,避免优先级战争。

Q: 除了面包屑,还有哪些组件可能受影响?

任何使用 <ul>/<ol> 的组件都可能受影响,例如:

  • 导航菜单
  • 分页组件
  • 自定义列表

检查方法:在浏览器开发者工具中搜索 list-style: none 的来源,确认是否来自 Preflight。

Q: 可以禁用 Preflight 吗?

可以,但不推荐。在 tailwind.config.js 中设置:

module.exports = {
corePlugins: {
preflight: false,
},
}

禁用后需要自行处理跨浏览器样式一致性,可能导致更多问题。