WordPress 子主题样式不加载
子主题的 style.css 没有加载,是因为 WordPress 不会替你把它排入队列。子主题的样式表必须在子主题的 functions.php 里手动注册
发布于
你的子主题 style.css 没有加载,是因为 WordPress 不会替你把它排入队列(enqueue)。子主题的样式表必须在子主题的 functions.php 里手动注册,而这段 enqueue 代码几乎总是犯下两个错误之一:要么根本就没写,要么加载时没有把父主题样式表声明为依赖,于是你的样式规则在层叠(cascade)中排错了位置,被父主题覆盖掉。把 enqueue 修好,样式就回来了。你多半是从某篇 2013 年的老教程里抄来的那个 @import 老招数,是错误的修法。
为什么会这样
一个标准的子主题由两个必需文件组成:一个带有声明父主题头部信息的 style.css,以及一个 functions.php。头部的 Template: 这一行告诉 WordPress 从哪个父主题继承模板。这是 WordPress 唯一会自动处理的事情。它读取头部信息,接好模板回退机制,然后就停了。它绝不会在前端把你的子主题 style.css 排入队列。
与此同时,父主题会从它自己的 functions.php 里、挂载在 wp_enqueue_scripts 上,把它自己的样式表排入队列。你的子主题 functions.php 先运行,然后是父主题的,接着挂在这个钩子上的所有内容才依次触发。如果你的子主题从没为自己的文件调用 wp_enqueue_style,浏览器就永远不会去请求它。页面看起来就像未经修改的父主题,因为它本来就是。
第二种失败更隐蔽。你把子主题样式表排入了队列,它也加载了,但你的覆盖规则不起作用。这是加载顺序的问题。当两条规则的优先级(specificity)相等时,后加载的那条胜出。如果你的子主题 CSS 在父主题之前加载,那么每次打平都是父主题赢。wp_enqueue_style 上的依赖数组正是用来强制顺序的。
还有一件大家容易搞错的事:get_template_directory_uri() 指向的是父主题文件夹,而 get_stylesheet_directory_uri() 指向的是当前启用的(子)主题文件夹。把这两个搞反,你就会把父主题的 style.css 又排队加载了一遍,而根本没碰到子主题的。
修复步骤,按顺序来
第一步,确认实际加载了什么。 打开出问题的页面,查看源代码,搜索你的子主题文件夹名。WordPress 会把排入队列的样式渲染成 <link id="handle-css" href="..."> —— 这个 id 就是你的句柄(handle)加上 -css。如果你的子主题 style.css 根本不在 <head> 里,说明 enqueue 没有运行。如果它在那里但样式不生效,那就是依赖/顺序的问题。这一个检查就能告诉你,你遇到的是两个错误中的哪一个。
第二步,找出父主题真正的句柄。 大多数现代主题(Astra、GeneratePress、Twenty-* 系列主题)都已经用一个特定的句柄把自己的样式表排入了队列 —— 比如 astra-theme-css、generate-style-css、twenty-twenty-four-style 等等。你需要那个精确的字符串。在父主题里用 grep 搜索,或者从查看源代码里的 <link id="...-css"> 上读出来(去掉末尾的 -css)。
第三步,写这段 enqueue。 对于父主题已经加载了自己样式表这种常见情况,你不要重新排队父主题。你只排队子主题,并把父主题的句柄列为依赖,这样你的样式表就会在它之后加载:
<?php
add_action( 'wp_enqueue_scripts', 'child_enqueue_styles', 20 );
function child_enqueue_styles() {
wp_enqueue_style(
'child-style',
get_stylesheet_directory_uri() . '/style.css',
array( 'astra-theme-css' ), // <-- the parent's REAL handle
wp_get_theme()->get( 'Version' )
);
}
如果父主题没有把自己的样式表排入队列(一些较老的或极简的主题依赖 @import),那就两个都排队,并让子主题依赖父主题:
<?php
add_action( 'wp_enqueue_scripts', 'child_enqueue_styles' );
function child_enqueue_styles() {
wp_enqueue_style(
'parent-style',
get_template_directory_uri() . '/style.css'
);
wp_enqueue_style(
'child-style',
get_stylesheet_directory_uri() . '/style.css',
array( 'parent-style' ),
wp_get_theme()->get( 'Version' )
);
}
wp_get_theme()->get('Version') 这个参数是你的缓存清除器(cache-buster)。修改子主题 style.css 头部里的 Version: 这一行,浏览器就会重新获取。省掉它,你就会一边改 CSS 一边发誓什么都没变,其实只是缓存了而已。
如果 functions.php 有语法错误,整个文件会悄无声息地挂掉,你所有的 enqueue 都不会运行 —— 这看起来正好就是”样式不加载”的样子。打开 WP_DEBUG,或者把你的 debug.log 粘贴到我们的 WordPress 错误日志解读工具里,快速找出那个致命错误。
不要这样做
不要用 @import。 Codex 时代的建议是在子主题 style.css 顶部放上 @import url("../parenttheme/style.css");。它能用,但很慢 —— 浏览器必须先解析完子主题 CSS 才能开始下载父主题 CSS,于是两个请求变成串行而不是并行。WordPress 官方手册多年来一直不推荐这样做。如果你的教程叫你这么干,那篇教程正是你样式卡顿的原因。
不要硬编码句柄 'parent-style' 然后盲目把父主题文件排入队列。 那段著名的 Codex 代码片段干的正是这件事,而对任何已经用别的句柄注册了样式表的主题来说,这都是错的。你最终会把父主题 CSS 加载两遍,而你的依赖指向的是一个可能根本不存在的句柄。
不要在 functions.php 的顶层直接调用 wp_enqueue_style。 它必须在一个挂载到 wp_enqueue_scripts 的函数内部运行。调用得太早,它什么都不会做。
不要把父主题整个 functions.php 复制到子主题里。 两个都会加载;子主题的先运行。复制它会导致函数重复声明并引发致命错误。
一点提醒:以上说的全都是针对经典(PHP 模板)主题的。如果你的父主题是区块主题(block theme),样式大多是通过 theme.json 和站点编辑器来处理的,style.css 的覆盖行为也不一样 —— 这种情况我不太敢打包票,建议你直接实测,而不要想当然地以为这段 enqueue 就是解药。
还是搞不定?
确认子主题 style.css 头部的 Template: 这一行与父主题的文件夹名完全一致、区分大小写 —— 不是父主题的显示名称。然后重新查看源代码:句柄在不在、是否在父主题之后加载、版本查询字符串有没有更新。如果 <link> 在那里、最后加载、而 CSS 依然不生效,那它就不再是 enqueue 的问题了 —— 而是优先级的问题,修复的重心要转移到规则本身上去。