WordPress 5.8 附带了一种新机制来配置编辑器,从而实现更精细的控制,并引入了管理未来 WordPress 发布版本样式的第一步:theme.json 文件。

理由

区块编辑器 API 以不同的速度演变,存在一些成长痛楚,特别是在影响主题的领域。例如:能够通过编程方式控制编辑器,或是一个区块样式系统,该系统便于管理用户、主题和核心样式偏好。

本文描述了当前的努力,旨在将各种与样式相关的 API 整合到一个点——位于主题目录根目录内的 theme.json 文件。

区块编辑器的设置

与其泛滥的主题支持标志或替代方法相比,theme.json 文件提供了一种规范的方式来定义区块编辑器的设置。这些设置包括:

  • 应向用户显示或隐藏哪些自定义选项。
  • 向用户提供哪些默认颜色、字体大小等。
  • 定义编辑器的默认布局(宽度和可用对齐方式)。

设置可按区块控制

为了更细粒度,这些设置在 theme.json 中也适用于区块级别。

可以实现的效果示例包括:

  • 为某个区块(例如:表格)使用特定的预设,但其余区块使用通用预设。
  • 为所有区块启用字体大小 UI 控件,但标题区块除外。
  • 等等。

样式管理

通过使用 theme.json 文件以结构化方式设置样式属性,区块编辑器可以“管理”来自不同来源(用户、主题和核心 CSS)的 CSS。例如,如果主题和用户都设置了段落的字体大小,我们只加载来自用户的样式,而不是主题的样式。

一些优势包括:

  • 减少加载的 CSS 量。
  • 防止特异性战争。

CSS 自定义属性:预设与自定义

有些样式领域将从拥有可在整个站点中更改的共享值中受益。

为了满足这一需求,我们开始在以下位置试验 CSS 自定义属性(即 CSS 变量):

{
    "version": 3,
    "settings": {
        "color": {
            "palette": [
                {
                    "name": "Black",
                    "slug": "black",
                    "color": "#000000"
                },
                {
                    "name": "White",
                    "slug": "white",
                    "color": "#ffffff"
                }
            ]
        }
    }
}
body {
    --wp--preset--color--black: #000000;
    --wp--preset--color--white: #ffffff;
}
  • 自定义属性:还有一种机制可以创建您自己的 CSS 自定义属性。
{
    "version": 3,
    "settings": {
        "custom": {
            "line-height": {
                "body": 1.7,
                "heading": 1.3
            }
        }
    }
}
body {
    --wp--custom--line-height--body: 1.7;
    --wp--custom--line-height--heading: 1.3;
}

规范

此规范适用于使用此格式的三种不同来源:核心、主题和用户。主题可以通过创建一个名为 theme.json 的文件来覆盖核心的默认设置。用户通过站点编辑器,也将能够通过正在开发的用户界面覆盖主题或核心的偏好。

{
    "version": 3,
    "settings": {},
    "styles": {},
    "customTemplates": {},
    "templateParts": {}
}

版本

此字段描述了 theme.json 文件的格式。最新版本是版本 3,于 WordPress 6.6 中引入。

当需要进行破坏性更改时,会引入新版本。这允许主题作者选择何时接受破坏性更改,并将他们的 theme.json 文件迁移到新格式。

旧版本的 theme.json 向后兼容,将继续与较新版本的 WordPress 和 Gutenberg 插件一起工作。但是新功能将在最新版本上开发。

有关更新到最新版本的详细信息,请遵循迁移到新版本中的说明。

设置

Gutenberg 插件扩展了 WordPress 5.8 可用的设置,因此它们可用于其他 WordPress 版本,并在移植到核心之前经过成熟过程。

下面的选项卡显示了 WordPress 5.8 支持的设置以及 Gutenberg 插件支持的设置。

设置部分具有以下结构:

{
    "version": 3,
    "settings": {
        "border": {
            "radius": false,
            "color": false,
            "style": false,
            "width": false
        },
        "color": {
            "custom": true,
            "customDuotone": true,
            "customGradient": true,
            "duotone": [],
            "gradients": [],
            "link": false,
            "palette": [],
            "text": true,
            "background": true,
            "defaultGradients": true,
            "defaultPalette": true
        },
        "custom": {},
        "layout": {
            "contentSize": "800px",
            "wideSize": "1000px"
        },
        "spacing": {
            "margin": false,
            "padding": false,
            "blockGap": null,
            "units": [ "px", "em", "rem", "vh", "vw" ]
        },
        "typography": {
            "customFontSize": true,
            "lineHeight": false,
            "dropCap": true,
            "fluid": false,
            "fontStyle": true,
            "fontWeight": true,
            "letterSpacing": true,
            "textDecoration": true,
            "textTransform": true,
            "fontSizes": [],
            "fontFamilies": []
        },
        "blocks": {
            "core/paragraph": {
                "color": {},
                "custom": {},
                "layout": {},
                "spacing": {},
                "typography": {}
            },
            "core/heading": {},
            "etc": {}
        }
    }
}
{
    "version": 3,
    "settings": {
        "appearanceTools": false,
        "border": {
            "color": false,
            "radius": false,
            "style": false,
            "width": false
        },
        "color": {
            "background": true,
            "custom": true,
            "customDuotone": true,
            "customGradient": true,
            "defaultGradients": true,
            "defaultPalette": true,
            "duotone": [],
            "gradients": [],
            "link": false,
            "palette": [],
            "text": true
        },
        "custom": {},
        "dimensions": {
            "aspectRatio": false,
            "height": false,
            "minHeight": false,
            "minWidth": false,
            "width": false,
        },
        "layout": {
            "contentSize": "800px",
            "wideSize": "1000px"
        },
        "spacing": {
            "blockGap": null,
            "margin": false,
            "padding": false,
            "customSpacingSize": true,
            "units": [ "px", "em", "rem", "vh", "vw" ],
            "spacingScale": {
                "operator": "*",
                "increment": 1.5,
                "steps": 7,
                "mediumStep": 1.5,
                "unit": "rem"
            },
            "spacingSizes": []
        },
        "typography": {
            "customFontSize": true,
            "dropCap": true,
            "fluid": false,
            "fontFamilies": [],
            "fontSizes": [],
            "fontStyle": true,
            "fontWeight": true,
            "letterSpacing": true,
            "lineHeight": false,
            "textAlign": true,
            "textColumns": false,
            "textDecoration": true,
            "textIndent": true,
            "textTransform": true
        },
        "blocks": {
            "core/paragraph": {
                "border": {},
                "color": {},
                "custom": {},
                "layout": {},
                "spacing": {},
                "typography": {}
            },
            "core/heading": {},
            "etc": {}
        }
    }
}

每个区块都可以单独配置这些设置中的任何一项,从而对通过 add_theme_support 存在的内容提供更细粒度的控制。在顶层声明的设置会影响所有区块,除非某个特定区块对其进行覆盖。这是一种提供继承并一次性配置所有区块的方法。

但请注意,并非所有设置都适用于所有区块。设置部分为主题提供了加入/退出机制,但是否支持相关功能由区块自行决定。例如,如果某个区块未实现 dropCap 功能,则主题无法通过 theme.json 为该区块启用此功能。

启用 UI 控件

有一个特殊的设置属性 appearanceTools,它是一个布尔值,默认值为 false。主题可以使用此设置启用以下选项:

  • background: backgroundImage, backgroundSize
  • border: color, radius, style, width
  • color: link
  • dimensions: aspectRatio, height, minHeight, minWidth, width
  • position: sticky
  • spacing: blockGap, margin, padding
  • typography: lineHeight

与 add_theme_support 的向后兼容性

为了保持向后兼容性,现有的配置区块编辑器的 add_theme_support 声明会被适配到顶层部分的适当类别中。例如,如果主题使用 add_theme_support('disable-custom-colors'),则等同于将 settings.color.custom 设置为 false。如果 theme.json 包含任何设置,这些设置将优先于通过 add_theme_support 声明的值。这是完整的等价列表:

add_theme_supporttheme.json setting
custom-line-height将 typography.lineHeight 设置为 true。
custom-spacing将 spacing.padding 设置为 true。
custom-units通过 spacing.units 提供单位列表。
disable-custom-colors将 color.custom 设置为 false。
disable-custom-font-sizes将 typography.customFontSize 设置为 false。
disable-custom-gradients将 color.customGradient 设置为 false。
editor-color-palette通过 color.palette 提供颜色列表。
editor-font-sizes通过 typography.fontSizes 提供字体大小列表。
editor-gradient-presets通过 color.gradients 提供渐变列表。
editor-spacing-sizes通过 spacing.spacingSizes 提供间距大小列表。
appearance-tools将 appearanceTools 设置为 true。
border将 border: color, radius, style, width 设置为 true。
link-color将 color.link 设置为 true。

预设值

预设值是设置部分的一部分。它们是通过某些 UI 控件显示给用户的值。通过 theme.json 定义它们后,引擎可以为主题执行更多操作,例如自动翻译预设名称或加载相应的 CSS 类和自定义属性。

以下预设可以通过 theme.json 定义:

  • color.duotone:不生成类或自定义属性。
  • color.gradients:为每个预设值生成一个类和自定义属性。
  • color.palette:
    • 为每个预设值生成 3 个类:颜色、背景颜色和边框颜色。
    • 为每个预设值生成一个自定义属性。
  • spacing.spacingSizes>/spacing.spacingScale:为每个预设值生成一个自定义属性。
  • typography.fontSizes:为每个预设值生成一个类和自定义属性。
  • typography.fontFamilies:为每个预设值生成一个自定义属性。
  • typography.textShadowPresets:为每个预设值生成一个类和自定义属性。

类和自定义属性的命名方案如下:

  • 自定义属性:--wp--preset--{preset-category}--{preset-slug},例如 --wp--preset--color--black
  • 类:.has-{preset-slug}-{preset-category},例如 .has-black-color。
{
    "version": 3,
    "settings": {
        "color": {
            "duotone": [
                {
                    "colors": [ "#000", "#FFF" ],
                    "slug": "black-and-white",
                    "name": "Black and White"
                }
            ],
            "gradients": [
                {
                    "slug": "blush-bordeaux",
                    "gradient": "linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%)",
                    "name": "Blush bordeaux"
                },
                {
                    "slug": "blush-light-purple",
                    "gradient": "linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%)",
                    "name": "Blush light purple"
                }
            ],
            "palette": [
                {
                    "slug": "strong-magenta",
                    "color": "#a156b4",
                    "name": "Strong magenta"
                },
                {
                    "slug": "very-dark-grey",
                    "color": "rgb(131, 12, 8)",
                    "name": "Very dark grey"
                }
            ]
        },
        "typography": {
            "fontFamilies": [
                {
                    "fontFamily": "-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell, \"Helvetica Neue\",sans-serif",
                    "slug": "system-font",
                    "name": "System Font"
                },
                {
                    "fontFamily": "Helvetica Neue, Helvetica, Arial, sans-serif",
                    "slug": "helvetica-arial",
                    "name": "Helvetica or Arial"
                }
            ],
            "fontSizes": [
                {
                    "slug": "big",
                    "size": 32,
                    "name": "Big"
                },
                {
                    "slug": "x-large",
                    "size": 46,
                    "name": "Large"
                }
            ]
        },
        "spacing": {
            "spacingScale": {
                "operator": "*",
                "increment": 1.5,
                "steps": 7,
                "mediumStep": 1.5,
                "unit": "rem"
            },
            "spacingSizes": [
                {
                    "slug": "40",
                    "size": "1rem",
                    "name": "Small"
                },
                {
                    "slug": "50",
                    "size": "1.5rem",
                    "name": "Medium"
                },
                {
                    "slug": "60",
                    "size": "2rem",
                    "name": "Large"
                }
            ]
        },
        "blocks": {
            "core/group": {
                "color": {
                    "palette": [
                        {
                            "slug": "black",
                            "color": "#000000",
                            "name": "Black"
                        },
                        {
                            "slug": "white",
                            "color": "#ffffff",
                            "name": "White"
                        }
                    ]
                }
            }
        }
    }
}
/* 顶层自定义属性 */
body {
    --wp--preset--color--strong-magenta: #a156b4;
    --wp--preset--color--very-dark-grey: #444;
    --wp--preset--gradient--blush-bordeaux: linear-gradient( 135deg, rgb( 254, 205, 165 ) 0%, rgb( 254, 45, 45 ) 50%, rgb( 107, 0, 62 ) 100% );
    --wp--preset--gradient--blush-light-purple: linear-gradient( 135deg, rgb( 255, 206, 236 ) 0%, rgb( 152, 150, 240 ) 100% );
    --wp--preset--font-size--x-large: 46;
    --wp--preset--font-size--big: 32;
    --wp--preset--font-family--helvetica-arial: Helvetica Neue, Helvetica, Arial, sans-serif;
    --wp--preset--font-family--system: -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell, \"Helvetica Neue\",sans-serif;
    --wp--preset--spacing--20: 0.44rem;
    --wp--preset--spacing--30: 0.67rem;
    --wp--preset--spacing--40: 1rem;
    --wp--preset--spacing--50: 1.5rem;
    --wp--preset--spacing--60: 2.25rem;
    --wp--preset--spacing--70: 3.38rem;
    --wp--preset--spacing--80: 5.06rem;
}

/* 块级自定义属性(绑定到组块) */
.wp-block-group {
    --wp--preset--color--black: #000000;
    --wp--preset--color--white: #ffffff;
}

/* 顶层类 */
.has-strong-magenta-color { color: #a156b4 !important; }
.has-strong-magenta-background-color { background-color: #a156b4 !important; }
.has-strong-magenta-border-color { border-color: #a156b4 !important; }
.has-very-dark-grey-color { color: #444 !important; }
.has-very-dark-grey-background-color { background-color: #444 !important; }
.has-very-dark-grey-border-color { border-color: #444 !important; }
.has-blush-bordeaux-background { background: linear-gradient( 135deg, rgb( 254, 205, 165 ) 0%, rgb( 254, 45, 45 ) 50%, rgb( 107, 0, 62 ) 100% ) !important; }
.has-blush-light-purple-background { background: linear-gradient( 135deg, rgb( 255, 206, 236 ) 0%, rgb( 152, 150, 240 ) 100% ) !important; }
.has-big-font-size { font-size: 32; }
.has-normal-font-size { font-size: 16; }

/* 块级类(绑定到组块,使用 :where() 以保持与顶层类相同的优先级) */
:where(.wp-block-group).has-black-color { color: #a156b4 !important; }
:where(.wp-block-group).has-black-background-color { background-color: #a156b4 !important; }
:where(.wp-block-group).has-black-border-color { border-color: #a156b4 !important; }
:where(.wp-block-group).has-white-color { color: #444 !important; }
:where(.wp-block-group).has-white-background-color { background-color: #444 !important; }
:where(.wp-block-group).has-white-border-color { border-color: #444 !important; }

为了保持向后兼容性,通过 add_theme_support 声明的预设也会生成 CSS 自定义属性。如果 theme.json 包含任何预设,这些将优先于通过 add_theme_support 声明的预设。

预设类是通过某些用户操作附加到帖子内容的。这就是为什么引擎会向这些添加 !important,因为用户样式应优先于主题样式。

自定义

除了为预设创建 CSS 自定义属性外,theme.json 还允许主题创建自己的属性,因此无需单独加载。任何在 custom 字段中声明的值都将按照此命名模式转换为 CSS 自定义属性:--wp--custom--<variable-name>。

例如:

{
    "version": 3,
    "settings": {
        "custom": {
            "baseFont": 16,
            "lineHeight": {
                "small": 1.2,
                "medium": 1.4,
                "large": 1.8
            }
        },
        "blocks": {
            "core/group": {
                "custom": {
                    "baseFont": 32
                }
            }
        }
    }
}
body {
    --wp--custom--base-font: 16;
    --wp--custom--line-height--small: 1.2;
    --wp--custom--line-height--medium: 1.4;
    --wp--custom--line-height--large: 1.8;
}
.wp-block-group {
    --wp--custom--base-font: 32;
}

请注意,变量名称是通过在每个嵌套级别之间添加 -- 创建的,并且 camelCase 字段被转换为 kebab-case。

设置示例

  • 仅针对段落块启用自定义颜色:
{
    "version": 3,
    "settings": {
        "color": {
            "custom": false
        },
        "blocks": {
            "core/paragraph": {
                "color": {
                    "custom": true
                }
            }
        }
    }
}
  • 禁用按钮块的圆角:
{
    "version": 3,
    "settings": {
        "blocks": {
            "core/button": {
                "border": {
                    "radius": false
                }
            }
        }
    }
}
  • 为组块提供与其他部分不同的调色板:
{
    "version": 3,
    "settings": {
        "color": {
            "palette": [
                {
                    "slug": "black",
                    "color": "#000000",
                    "name": "Black"
                },
                {
                    "slug": "white",
                    "color": "#FFFFFF",
                    "name": "White"
                },
                {
                    "slug": "red",
                    "color": "#FF0000",
                    "name": "Red"
                },
                {
                    "slug": "green",
                    "color": "#00FF00",
                    "name": "Green"
                },
                {
                    "slug": "blue",
                    "color": "#0000FF",
                    "name": "Blue"
                }
            ]
        },
        "blocks": {
            "core/group": {
                "color": {
                    "palette": [
                        {
                            "slug": "black",
                            "color": "#000000",
                            "name": "Black"
                        },
                        {
                            "slug": "white",
                            "color": "#FFF",
                            "name": "White"
                        }
                    ]
                }
            }
        }
    }
}

样式

Gutenberg 插件扩展了 WordPress 5.8 提供的样式,因此它们可用于其他 WordPress 版本,并在移植到核心之前经过成熟过程。

下方的选项卡显示了 WordPress 5.8 支持的样式以及 Gutenberg 插件支持的样式。

每个块都声明它通过 块支持机制 暴露哪些样式属性。支持声明用于在编辑器中自动为块生成 UI 控件。主题可以通过 theme.json 使用任何样式属性应用于任何块——验证其是否根据块标记等正常工作是主题的责任。

{
    "version": 3,
    "styles": {
        "border": {
            "radius": "value",
            "color": "value",
            "style": "value",
            "width": "value"
        },
        "filter": {
            "duotone": "value"
        },
        "color": {
            "background": "value",
            "gradient": "value",
            "text": "value"
        },
        "spacing": {
            "blockGap": "value",
            "margin": {
                "top": "value",
                "right": "value",
                "bottom": "value",
                "left": "value",
            },
            "padding": {
                "top": "value",
                "right": "value",
                "bottom": "value",
                "left": "value"
            }
        },
        "typography": {
            "fontSize": "value",
            "fontStyle": "value",
            "fontWeight": "value",
            "letterSpacing": "value",
            "lineHeight": "value",
            "textDecoration": "value",
            "textTransform": "value"
        },
        "elements": {
            "link": {
                "border": {},
                "color": {},
                "spacing": {},
                "typography": {}
            },
            "h1": {},
            "h2": {},
            "h3": {},
            "h4": {},
            "h5": {},
            "h6": {}
        },
        "blocks": {
            "core/group": {
                "border": {},
                "color": {},
                "spacing": {},
                "typography": {},
                "elements": {
                    "link": {},
                    "h1": {},
                    "h2": {},
                    "h3": {},
                    "h4": {},
                    "h5": {},
                    "h6": {}
                }
            },
            "etc": {}
        }
    }
}
{
    "version": 3,
    "styles": {
        "border": {
            "color": "value",
            "radius": "value",
            "style": "value",
            "width": "value"
        },
        "color": {
            "background": "value",
            "gradient": "value",
            "text": "value"
        },
        "dimensions": {
            "aspectRatio": "value",
            "height": "value"
            "minHeight": "value"
            "minWidth": "value"
            "width": "value"
        },
        "filter": {
            "duotone": "value"
        },
        "spacing": {
            "blockGap": "value",
            "margin": {
                "top": "value",
                "right": "value",
                "bottom": "value",
                "left": "value"
            },
            "padding": {
                "top": "value",
                "right": "value",
                "bottom": "value",
                "left": "value"
            }
        },
        "typography": {
            "fontFamily": "value",
            "fontSize": "value",
            "fontStyle": "value",
            "fontWeight": "value",
            "letterSpacing": "value",
            "lineHeight": "value",
            "textColumns": "value",
            "textDecoration": "value",
            "textTransform": "value"
        },
        "elements": {
            "link": {
                "border": {},
                "color": {},
                "spacing": {},
                "typography": {}
            },
            "h1": {},
            "h2": {},
            "h3": {},
            "h4": {},
            "h5": {},
            "h6": {},
            "heading": {},
            "button": {},
            "caption": {}
        },
        "blocks": {
            "core/group": {
                "border": {},
                "color": {},
                "dimensions": {},
                "spacing": {},
                "typography": {},
                "elements": {
                    "link": {},
                    "h1": {},
                    "h2": {},
                    "h3": {},
                    "h4": {},
                    "h5": {},
                    "h6": {}
                }
            },
            "etc": {}
        }
    }
}

顶层样式

位于顶层的样式将使用 body 选择器进行加载。

{
    "version": 3,
    "styles": {
        "color": {
            "text": "var(--wp--preset--color--primary)"
        }
    }
}
body {
    color: var( --wp--preset--color--primary );
}

区块样式

位于区块内的样式将使用区块选择器进行加载。

默认情况下,区块选择器是基于其名称生成的,例如 .wp-block-<blockname-without-namespace>。例如,对于 core/group 区块为 .wp-block-group。有些区块希望退出此默认行为。它们可以通过在 block.json 文件的 supports 部分的 __experimentalSelector 键中明确告诉系统使用哪个选择器来做到这一点。请注意,区块需要在服务器端注册,以便样式引擎可以使用 __experimentalSelector 字段。

{
    "version": 3,
    "styles": {
        "color": {
            "text": "var(--wp--preset--color--primary)"
        },
        "blocks": {
            "core/paragraph": {
                "color": {
                    "text": "var(--wp--preset--color--secondary)"
                }
            },
            "core/group": {
                "color": {
                    "text": "var(--wp--preset--color--tertiary)"
                }
            }
        }
    }
}
body {
    color: var( --wp--preset--color--primary );
}
p { /* The core/paragraph opts out from the default behaviour and uses p as a selector. */
    color: var( --wp--preset--color--secondary );
}
.wp-block-group {
    color: var( --wp--preset--color--tertiary );
}

引用样式

区块可以使用对根级别样式的引用来进行样式设置。此功能由 Gutenberg 支持。
如果您使用 styles.color.background 为根注册背景颜色:

"styles": {
        "color": {
            "background": "var(--wp--preset--color--primary)"
        }
    }

您可以使用 ref: "styles.color.background" 来重用该样式:

{
    "color": {
        "text": { "ref": "styles.color.background" }
    }
}

元素样式

除了顶层和区块级样式外,还有一种可以在两个地方使用的元素概念。有一个封闭的集合:

Gutenberg 支持:

  • button:映射到 wp-element-button CSS 类。也映射到 wp-block-button__link 以向后兼容。
  • caption:映射到 .wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption CSS 类。
  • heading:映射到所有标题,h1 to h6 CSS 选择器。

WordPress 支持:

  • h1:映射到 h1 CSS 选择器。
  • h2:映射到 h2 CSS 选择器。
  • h3:映射到 h3 CSS 选择器。
  • h4:映射到 h4 CSS 选择器。
  • h5:映射到 h5 CSS 选择器。
  • h6:映射到 h6 CSS 选择器。
  • link:映射到 a CSS 选择器。

如果它们在顶层找到,将使用元素选择器。如果它们在区块内找到,将使用的选择器将是附加到相应区块的元素。

{
    "version": 3,
    "styles": {
        "typography": {
            "fontSize": "var(--wp--preset--font-size--normal)"
        },
        "elements": {
            "h1": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--huge)"
                }
            },
            "h2": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--big)"
                }
            },
            "h3": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--medium)"
                }
            }
        },
        "blocks": {
            "core/group": {
                "elements": {
                    "h2": {
                        "typography": {
                            "fontSize": "var(--wp--preset--font-size--small)"
                        }
                    },
                    "h3": {
                        "typography": {
                            "fontSize": "var(--wp--preset--font-size--smaller)"
                        }
                    }
                }
            }
        }
    }
}
body {
    font-size: var( --wp--preset--font-size--normal );
}
h1 {
    font-size: var( --wp--preset--font-size--huge );
}
h2 {
    font-size: var( --wp--preset--font-size--big );
}
h3 {
    font-size: var( --wp--preset--font-size--medium );
}
.wp-block-group h2 {
    font-size: var( --wp--preset--font-size--small );
}
.wp-block-group h3 {
    font-size: var( --wp--preset--font-size--smaller );
}
元素伪选择器

Gutenberg 支持伪选择器 :hover、:focus、:focus-visible、:visited、:active、:link、:any-link。

"elements": {
        "link": {
            "color": {
                "text": "green"
            },
            ":hover": {
                "color": {
                    "text": "hotpink"
                }
            }
        }
    }

响应式样式

区块样式可以限定在两个命名断点:@mobile 和 @tablet。任何在区块或元素级别有效的样式属性都可以嵌套在这些键下的一个中。

KeyMedia query applied
@mobile@media (width <= 480px)
@tablet@media (480px < width <= 782px)

主题可以使用 settings.viewport.mobile 和 settings.viewport.tablet 覆盖默认断点宽度。断点值可以使用 px、em 或 rem 单位。

如果只配置了一个有效的断点,该断点保留其视口键并使用单个最大宽度查询。例如,只有 settings.viewport.tablet 的主题将使用 @media (width <= value) 暴露 @tablet 样式。

{
    "version": 3,
    "settings": {
        "viewport": {
            "mobile": "640px",
            "tablet": "960px"
        }
    }
}

响应式覆盖可以直接放在区块节点上:

{
    "version": 3,
    "styles": {
        "blocks": {
            "core/group": {
                "color": {
                    "text": "black"
                },
                "@mobile": {
                    "color": {
                        "text": "hotpink"
                    }
                }
            }
        }
    }
}
:root :where(.wp-block-group) { color: black; }
@media (width <= 480px) { :root :where(.wp-block-group) { color: hotpink; } }

断点也可以为块元素(包括其伪选择器)携带样式:

{
    "version": 3,
    "styles": {
        "blocks": {
            "core/group": {
                "elements": {
                    "link": {
                        "color": { "text": "blue" },
                        ":hover": {
                            "color": { "text": "navy" }
                        }
                    }
                },
                "@mobile": {
                    "elements": {
                        "link": {
                            "color": { "text": "red" },
                            ":hover": {
                                "color": { "text": "darkred" }
                            }
                        }
                    }
                }
            }
        }
    }
}
:root :where(.wp-block-group a:where(:not(.wp-element-button))) { color: blue; }
@media (width <= 480px) { :root :where(.wp-block-group a:where(:not(.wp-element-button))) { color: red; } }
:root :where(.wp-block-group a:where(:not(.wp-element-button)):hover) { color: navy; }
@media (width <= 480px) { :root :where(.wp-block-group a:where(:not(.wp-element-button)):hover) { color: darkred; } }

响应式覆盖样式始终输出在其覆盖的默认样式之后,因此无需增加特异性即可保留级联顺序。

变体(Variations)

块可以具有“样式变体”,如 block.json 规范 中所定义。主题作者可以使用 theme.json 文件为现有样式变体定义样式属性。未注册的样式变体的样式将被忽略。

请注意,变体是一个“块概念”——它们仅在绑定到块时存在。theme.json 规范尊重这一区别,仅允许在块级别(而非顶级)使用 variations。同样值得一提的是,只有由块的 block.json 文件或服务器上的 register_block_style 定义的变体才被视为 theme.json 样式目的的“已注册”变体。

例如,这是为 core/quote 块的现有 plain 变体提供样式的方法:

{
    "version": 3,
    "styles": {
        "blocks": {
            "core/quote": {
                "variations": {
                    "plain": {
                        "color": {
                            "background": "red"
                        }
                    }
                }
            }
        }
    }
}

生成的 CSS 输出为:

.wp-block-quote.is-style-plain {
    background-color: red;
}

多个块类型也可以共享相同的变体样式。定义此类共享样式有两种推荐方法:

  1. theme.json 部分文件
  2. 通过编程方式使用 register_block_style
变体 Theme.json 部分文件

与主题样式变体部分文件类似,块样式变体的部分文件位于主题的 /styles 目录中。但是,它们通过引入一个名为 blockTypes 的顶级属性而与主题样式变体区分开来。blockTypes 属性是一个数组,列出了已注册块样式变体的块类型。

此外,slug 属性可用于提供定义块样式变体的不同来源之间的一致性,并将 slug 与可翻译的 title 属性解耦。

以下是一个为 Group、Columns 和 Media & Text 块类型的“Variation A”块样式定义样式的 theme.json 部分示例:

{
    "$schema": "https://schemas.wp.org/trunk/theme.json",
    "version": 3,
    "title": "Variation A",
    "slug": "variation-a",
    "blockTypes": [ "core/group", "core/columns", "core/media-text" ],
    "styles": {
        "color": {
            "background": "#eed8d3",
            "text": "#201819"
        },
        "elements": {
            "heading": {
                "color": {
                    "text": "#201819"
                }
            }
        },
        "blocks": {
            "core/group": {
                "color": {
                    "background": "#825f58",
                    "text": "#eed8d3"
                },
                "elements": {
                    "heading": {
                        "color": {
                            "text": "#eed8d3"
                        }
                    }
                }
            }
        }
    }
}
通过编程方式注册变体样式

作为 theme.json 部分文件的替代方案,您可以通过 register_block_style 在注册变体本身的同时注册变体样式。这是通过为块类型数组注册块样式,同时在 style_data 选项中传递一个“样式对象”来实现的。

下面的示例为 Group 和 Columns 块注册了“Green”变体。请注意,通过 style_data 传递的样式对象遵循与 theme.json 部分文件的 styles 属性相同的形状。

register_block_style(
    array( 'core/group', 'core/columns' ),
    array(
        'name'       => 'green',
        'label'      => __( 'Green' ),
        'style_data' => array(
            'color'    => array(
                'background' => '#4f6f52',
                'text'       => '#d2e3c8',
            ),
            'blocks'   => array(
                'core/group' => array(
                    'color' => array(
                        'background' => '#739072',
                        'text'       => '#e3eedd',
                    ),
                ),
            ),
            'elements' => array(
                'link'   => array(
                    'color'  => array(
                        'text' => '#ead196',
                    ),
                    ':hover' => array(
                        'color' => array(
                            'text' => '#ebd9b4',
                        ),
                    ),
                ),
            ),
        ),
    )
);

customTemplates

WordPress 5.9 版本开始支持。

在此字段中,主题可以列出 templates 文件夹中的自定义模板。例如,对于名为 my-custom-template.html 的自定义模板,theme.json 可以声明哪些文章类型可以使用它以及要显示给用户的标题:

  • name:必需。
  • title:必需,可翻译。
  • postTypes:可选,默认仅适用于 page。
{
    "version": 3,
    "customTemplates": [
        {
            "name": "my-custom-template",
            "title": "The template title",
            "postTypes": [
                "page",
                "post",
                "my-cpt"
            ]
        }
    ]
}

templateParts

WordPress 5.9 版本开始支持。

在此字段中,主题可以列出 parts 文件夹中的模板部分。例如,对于名为 my-template-part.html 的模板部分,theme.json 可以声明负责在编辑器中渲染相应块变体(Header 块、Footer 块等)的模板部分实体的区域术语。在 json 中定义此区域术语将允许该设置在该模板部分实体的所有使用中持久存在,而不会像仅影响一个块的块属性那样。不建议将 area 定义为块属性,因为这仅在幕后使用,以有助于弥合占位符流和实体创建之间的差距。

目前,块变体存在于区域术语的“header”和“footer”值中,任何其他值和未在 json 中定义的模板部分都将默认为通用模板部分块。变体将在编辑器的界面中表示为特定图标,将默认为包装器对应的语义 HTML 元素(这也可以通过在模板部分块上设置的 tagName 属性覆盖),并将上下文化模板部分以允许未来编辑器改进中的更多自定义流。

  • name:必需。
  • title:可选,可翻译。
  • area:可选,默认设置为 uncategorized 并不会触发块变体。
{
    "version": 3,
    "templateParts": [
        {
            "name": "my-template-part",
            "title": "Header",
            "area": "header"
        }
    ]
}

patterns

支持自 WordPress 6.0 版本。

在此字段中,主题可以列出从Pattern Directory(图案目录)注册的图案。 patterns 字段是 Pattern Directory 中图案 slugs 的数组。图案 slugs 可以通过 Pattern Directory 中单个图案视图的 url 提取。例如,在此 url https://wordpress.org/patterns/pattern/partner-logos` 中,slug 是partner-logos`。

{
    "version": 3,
    "patterns": [ "short-text-surrounded-by-round-images", "partner-logos" ]
}

使用 theme.json 进行开发

在开发过程中,记住 theme.json 的设置和属性以及哪些版本的 WordPress 支持哪些设置可能很困难,因此使用提供的 theme.json JSON 架构可能会有所帮助。

许多代码编辑器支持 JSON 架构,并可以在编辑器中提供诸如工具提示、自动完成或架构验证等帮助。

每个 WordPress 版本的 theme.json 架构均可在 https://schemas.wp.org/wp/{{version}}/theme.json` 获取。例如,WordPress 5.8 的架构可在https://schemas.wp.org/wp/5.8/theme.json` 获取。为了确保您仅使用您的用户可用的功能,最好使用您的主题支持的最旧版本。

包含 Gutenberg 插件所有最新更改的最新架构可在 `https://schemas.wp.org/trunk/theme.json` 获取。

检查您的编辑器的文档以了解 JSON 架构支持情况。例如,在 Visual Studio Code 中,您需要将 "$schema": "https://schemas.wp.org/wp/x.x/theme.json" 作为 theme.json 文件的顶层属性添加,但其他编辑器可能配置不同。

使用架构进行验证的示例

常见问题解答

CSS 自定义属性的命名架构

您可能注意到系统创建的 CSS 自定义属性使用的命名架构,包括使用双连字符 -- 来分隔不同的“概念”。以下是以下示例。

预设值(如 --wp--preset--color--black)可以分为以下部分:

  • --wp:用于命名空间 CSS 变量的前缀。
  • preset:表示这是一个属于预设的 CSS 变量。
  • color:表示变量所属的预设类别。它可以是 color、font-size、gradients。
  • black:特定预设值的 slug。

自定义属性(如 --wp--custom--line-height--body),可以分为以下部分:

  • --wp:用于命名空间 CSS 变量的前缀。
  • custom:表示这是由主题创建的“自由形式”CSS 变量。
  • line-height--body:将“自定义”对象键转换为字符串的结果。

--作为分隔符有两个功能:

  • 可读性,供人类理解。可以将其视为类似于 BEM 命名架构,它分隔了“类别”。
  • 可解析性,供机器理解。使用定义的结构允许机器理解属性 --wp--preset--color--black 的含义:它是一个绑定到 slug 为“black”的颜色预设的值,这为我们提供了更多操作的空间。

为什么使用 — 作为分隔符?

我们可以使用任何其他分隔符,例如单个 -。

然而,这将是有问题的,因为除非我们强制主题作者不在其变量名中使用 -,否则将无法判断如何将 --wp-custom-line-height-template-header 转换回对象。

通过保留 -- 作为类别分隔符,并让主题作者在单词边界使用 -,命名更清晰:--wp--custom--line-height--template-header。

“custom”下的设置如何创建新的 CSS 自定义属性

从“custom”键下的设置创建 CSS 变量的算法工作方式如下:

这是为了清晰起见,同时也因为我们希望有一种机制将变量名(如 --wp--custom--line-height--body)解析回 theme.json 中的对象形式。我们对预设值也使用相同的分隔。

例如:

{
    "version": 3,
    "settings": {
        "custom": {
            "lineHeight": {
                "body": 1.7
            },
            "font-primary": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
        }
    }
}
body {
    --wp--custom--line-height--body: 1.7;
    --wp--custom--font-primary: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
}

关于此过程的一些说明:

  • camelCased 键转换为其 kebab-case 形式,以遵循 CSS 属性命名架构。示例:lineHeight 转换为 line-height。
  • 不同深度级别的键由 -- 分隔。这就是为什么 line-height 和 body 由 -- 分隔的原因。
  • 您不应在 custom 对象内的键名中使用 --。例如,不要这样做:
{
    "version": 3,
    "settings": {
        "custom": {
            "line--height": { // DO NOT DO THIS
                "body": 1.7
            }
        }
    }
}

全局样式表

在 WordPress 5.8 中,WordPress 定义的一些预设值(字体大小、颜色和渐变)的 CSS 对于大多数主题加载了两次:在 block-library 样式表中以及在全局样式表中。此外,这两个地方的 CSS 存在细微差异。

在 WordPress 5.9 版本中,预设值的 CSS 已合并到全局样式表中,现在所有主题都会加载该样式表。每个预设值生成一个 CSS 自定义属性和一个类,如下所示:

/* CSS Custom Properties for the preset values */
body {
  --wp--preset--<PRESET_TYPE>--<PRESET_SLUG>: <DEFAULT_VALUE>;
  --wp--preset--color--pale-pink: #f78da7;
  --wp--preset--font-size--large: 36px;
  /* etc. */
}

/* CSS classes for the preset values */
.has-<PRESET_SLUG>-<PRESET_TYPE> { ... }
.has-pale-pink-color { color: var(--wp--preset--color--pale-pink) !important; }
.has-large-font-size { font-size: var(--wp--preset--font-size--large) !important; }

主题若要覆盖默认值,可以使用 theme.json 并提供相同的 slug。不使用 theme.json 的主题仍可以通过加载一些 CSS 来设置相应的 CSS 自定义属性以覆盖默认值。

示例(为默认的大字体大小设置新值):

body {
 --wp--preset--font-size--large: <NEW_VALUE>;
}

用户提供的链接颜色的特异性

在 WordPress 5.8 中,当用户为特定块选择链接颜色时,我们为该块附加了一个类 .wp-element-<ID>,然后加载以下样式:

.wp-element-<ID> a { color: <USER_COLOR_VALUE> !important; }

虽然这始终保留了用户偏好,但特异性太强,与一些具有合法使用 HTML 元素(不应被视为链接)的块发生冲突。为了解决此问题,在 WordPress 5.9 版本中,移除了 !important,并更新了相应的块以使用高于用户链接颜色的特异性来样式化 a 元素,现在如下所示:

.wp-element-<ID> a { color: <USER_COLOR_VALUE>; }

由于此更改,现在是块作者和主题作者的责任,确保始终尊重用户选择,并且不会覆盖用户提供的链接颜色(特异性 011)。

什么是 blockGap 以及如何使用它?

对于包含内部块的块(如 Group、Columns、Buttons 和 Social Icons),blockGap 控制内部块之间的间距。要使 blockGap 生效,该块还必须加入layout 块支持,它提供可通过块间距控件调整的布局样式。根据块的布局,blockGap 值将输出为垂直边距或 gap 值。在编辑器中,blockGap 值的控件称为 Block spacing(块间距),位于 Dimensions panel(尺寸面板)中。

{
    "version": 3,
    "settings": {
        "spacing": {
            "blockGap": true,
        }
    },
    "styles": {
        "spacing": {
            "blockGap": "1.5rem"
        }
    }
}

blockGap 的设置值为布尔值或 null,默认值为 null。这允许对样式输出进行额外的控制层级。theme.json 文件中的 settings.spacing.blockGap 设置接受以下值:

  • true:启用在编辑器 UI 中显示“区块间距”控件,并输出 blockGap 样式。
  • false:禁用编辑器 UI 中的“区块间距”控件显示,但存储在 theme.json 中的 blockGap 样式仍会被渲染。这允许主题使用 blockGap 值,同时不允许用户在编辑器中进行修改。
  • null(默认):禁用“区块间距”控件显示,并阻止输出 blockGap 样式。

为根级 styles.spacing.blockGap 样式定义的值也会作为 CSS 属性输出,命名为 --wp--style--block-gap。

为什么在浏览器中更新样式需要这么久?

当你使用 theme.json 进行积极开发时,你可能会注意到更改在浏览器中显示需要 30 多秒,这是因为 theme.json 被缓存了。要消除此缓存问题,请在你的 wp-config.php 中将 WP_DEBUG 或 SCRIPT_DEBUG 设置为 'true'。这会告诉 WordPress 跳过缓存并始终使用最新数据。