CSS 命名页面:page: chapter_name 实现不同章节应用不同页眉页脚
大家好,今天我们来探讨一个在网页设计中非常实用的技巧:如何利用 CSS 的 page 选择器和自定义属性,结合不同的章节名称,来实现不同章节应用不同的页眉页脚。这个方法的核心在于,我们可以为每个章节的页面赋予一个特定的名称,然后通过 CSS 选择器来针对这些页面进行样式定制。这种方法不仅可以提高代码的可维护性,还能让我们的网页在视觉上更加清晰,方便用户阅读。
1. 理解 @page 规则
首先,我们需要了解 CSS 中的 @page 规则。@page 规则用于定义打印文档时页面的样式,包括页面大小、边距、页眉页脚等。它通常用于设置打印样式的布局,但我们也可以巧妙地利用它来影响屏幕显示,尤其是在一些特定的单页应用或者富文档展示场景中。
@page 规则的基本语法如下:
@page {
size: A4; /* 页面大小 */
margin: 2cm; /* 页面边距 */
/* 页眉 */
@top-left {
content: "页眉左侧内容";
}
@top-right {
content: "页眉右侧内容";
}
/* 页脚 */
@bottom-left {
content: "页脚左侧内容";
}
@bottom-right {
content: "页脚右侧内容";
}
}
这段代码定义了所有页面的默认样式:A4 纸张大小,2cm 的边距,以及简单的页眉页脚内容。我们需要注意的是,@top-left、@top-right、@bottom-left、@bottom-right 这些是 CSS Paged Media 规范中的区域描述符,它们允许我们精确控制页眉页脚的内容和位置。
2. 利用 page 选择器和自定义属性
关键在于如何针对不同的章节应用不同的页眉页脚。这时,page 选择器就派上用场了。page 选择器允许我们根据页面的名称来选择页面。但是,默认情况下,所有的页面都只有一个默认名称,我们需要一种方法来为不同的章节页面赋予不同的名称。
这里,我们引入自定义属性(CSS variables)的概念。我们可以通过 JavaScript 动态地为每个章节的 <body> 元素设置一个自定义属性,例如 data-chapter,然后利用 CSS 的 attr() 函数来读取这个属性的值,并将其作为 page 的名称。
HTML 结构示例:
<!DOCTYPE html>
<html>
<head>
<title>CSS 命名页面示例</title>
<link rel="stylesheet" href="style.css">
</head>
<body data-chapter="introduction">
<div class="content">
<h1>Introduction</h1>
<p>This is the introduction chapter.</p>
</div>
</body>
</html>
CSS 代码示例 (style.css):
@page {
size: A4;
margin: 2cm;
}
@page :left {
margin-right: 3cm; /* 左侧页面的右边距更大 */
}
@page :right {
margin-left: 3cm; /* 右侧页面的左边距更大 */
}
/* 默认页眉页脚 */
@page {
@top-right {
content: "Default Header";
font-size: 10pt;
}
@bottom-right {
content: "Page " counter(page); /* 显示页码 */
font-size: 10pt;
}
}
/* 根据 data-chapter 属性设置不同的页眉页脚 */
@page introduction {
@top-left {
content: "Chapter 1: Introduction";
font-weight: bold;
font-size: 12pt;
}
@bottom-left {
content: "Introduction Footer";
font-size: 10pt;
}
}
@page methodology {
@top-left {
content: "Chapter 2: Methodology";
font-weight: bold;
font-size: 12pt;
}
@bottom-left {
content: "Methodology Footer";
font-size: 10pt;
}
}
body[data-chapter="introduction"] {
page: introduction;
}
body[data-chapter="methodology"] {
page: methodology;
}
在这个例子中,我们首先定义了 @page 的默认样式,包括页面大小、边距和默认的页眉页脚。然后,我们定义了两个名为 introduction 和 methodology 的页面样式,分别对应 Introduction 和 Methodology 两个章节。
关键在于 body[data-chapter="introduction"] { page: introduction; } 这行代码。它告诉浏览器,当 <body> 元素拥有 data-chapter="introduction" 属性时,该页面应该应用名为 introduction 的页面样式。 这样, Introduction 章节的页面就会显示 "Chapter 1: Introduction" 作为页眉,"Introduction Footer" 作为页脚。
3. 利用 JavaScript 动态设置 data-chapter 属性
为了使这个方案更加灵活,我们可以使用 JavaScript 动态地为每个章节的 <body> 元素设置 data-chapter 属性。这在单页应用或者动态生成内容的场景中非常有用。
JavaScript 代码示例:
document.addEventListener("DOMContentLoaded", function() {
const chapters = document.querySelectorAll(".chapter");
chapters.forEach(chapter => {
const chapterName = chapter.getAttribute("data-chapter-name");
if (chapterName) {
chapter.parentNode.setAttribute("data-chapter", chapterName); // 将 data-chapter 设置到 body 上
}
});
});
对应的 HTML 结构可能是这样:
<!DOCTYPE html>
<html>
<head>
<title>CSS 命名页面示例</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="chapter" data-chapter-name="introduction">
<div class="content">
<h1>Introduction</h1>
<p>This is the introduction chapter.</p>
</div>
</div>
<div class="chapter" data-chapter-name="methodology">
<div class="content">
<h1>Methodology</h1>
<p>This is the methodology chapter.</p>
</div>
</div>
</body>
</html>
在这个例子中,我们假设每个章节都包含在一个带有 class="chapter" 的 <div> 元素中,并且该元素有一个 data-chapter-name 属性,用于指定章节的名称。JavaScript 代码会遍历所有 class="chapter" 的元素,读取 data-chapter-name 属性的值,然后将 data-chapter 属性设置到其父元素(通常是 <body> 元素)上。
4. 更复杂的样式控制
除了简单的文本内容,我们还可以利用 CSS 的其他特性来控制页眉页脚的样式,例如字体、颜色、背景等。
@page introduction {
@top-left {
content: "Chapter 1: Introduction";
font-weight: bold;
font-size: 12pt;
color: #007bff; /* 蓝色 */
background-color: #f0f8ff; /* 淡蓝色背景 */
padding: 5px;
border-bottom: 1px solid #ccc;
}
@bottom-left {
content: "Introduction Footer";
font-size: 10pt;
color: #6c757d; /* 灰色 */
}
}
这段代码为 Introduction 章节的页眉添加了蓝色字体、淡蓝色背景、内边距和下边框,使其更加醒目。
5. 实现章节页码连续
一个常见的需求是实现章节页码的连续性。例如,如果 Introduction 章节有 5 页,Methodology 章节从第 6 页开始。为了实现这个目标,我们需要使用 CSS 的 counter-reset 和 counter-increment 属性。
body {
counter-reset: page; /* 重置页码计数器 */
}
@page {
@bottom-right {
content: "Page " counter(page); /* 显示页码 */
font-size: 10pt;
}
}
@page introduction {
@bottom-right {
content: "Introduction - Page " counter(page);
}
}
@page methodology {
@bottom-right {
content: "Methodology - Page " counter(page);
}
}
/* 在每个页面递增页码计数器 */
@page {
counter-increment: page;
}
在这个例子中,我们在 <body> 元素上使用 counter-reset: page 来重置页码计数器。然后在 @page 规则中使用 counter(page) 来显示页码。关键是在 @page 规则中使用 counter-increment: page 来在每个页面递增页码计数器。这样,即使在不同的章节中,页码也会保持连续。
6. 响应式设计考虑
在实际应用中,我们还需要考虑响应式设计。@page 规则主要针对打印样式,对于屏幕显示,我们可能需要使用媒体查询来调整页眉页脚的样式,使其在不同的屏幕尺寸下都能正常显示。
@media screen {
/* 屏幕显示样式 */
.header {
/* 页眉样式 */
}
.footer {
/* 页脚样式 */
}
}
@media print {
/* 打印样式 */
@page {
/* 页眉页脚样式 */
}
}
我们可以使用 @media screen 来定义屏幕显示样式,使用 @media print 来定义打印样式。这样,我们就可以针对不同的设备和场景,分别设置不同的页眉页脚样式。
7. 兼容性考虑
@page 规则和 CSS 自定义属性的兼容性相对较好,大多数现代浏览器都支持它们。但是,为了确保在旧版本的浏览器中也能正常显示,我们可以使用一些 polyfill 或者降级方案。例如,对于不支持 CSS 自定义属性的浏览器,我们可以使用 JavaScript 来设置页眉页脚的样式。
总的来说,虽然 @page 最初设计用于打印样式,但通过与 CSS 自定义属性和 JavaScript 结合使用,我们可以将其应用于屏幕显示,实现更加灵活和可定制的页面布局。
8. 示例代码汇总
为了方便大家理解,这里提供一个完整的示例代码:
HTML (index.html):
<!DOCTYPE html>
<html>
<head>
<title>CSS 命名页面示例</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="chapter" data-chapter-name="introduction">
<div class="content">
<h1>Introduction</h1>
<p>This is the introduction chapter. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="chapter" data-chapter-name="methodology">
<div class="content">
<h1>Methodology</h1>
<p>This is the methodology chapter. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="chapter" data-chapter-name="results">
<div class="content">
<h1>Results</h1>
<p>This is the results chapter. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
CSS (style.css):
@page {
size: A4;
margin: 2cm;
}
@page :left {
margin-right: 3cm;
}
@page :right {
margin-left: 3cm;
}
body {
counter-reset: page;
}
@page {
@top-right {
content: "Default Header";
font-size: 10pt;
}
@bottom-right {
content: "Page " counter(page);
font-size: 10pt;
}
}
@page introduction {
@top-left {
content: "Chapter 1: Introduction";
font-weight: bold;
font-size: 12pt;
color: #007bff;
background-color: #f0f8ff;
padding: 5px;
border-bottom: 1px solid #ccc;
}
@bottom-left {
content: "Introduction Footer";
font-size: 10pt;
color: #6c757d;
}
@bottom-right {
content: "Introduction - Page " counter(page);
}
}
@page methodology {
@top-left {
content: "Chapter 2: Methodology";
font-weight: bold;
font-size: 12pt;
color: #28a745;
background-color: #e9ecef;
padding: 5px;
border-bottom: 1px solid #ccc;
}
@bottom-left {
content: "Methodology Footer";
font-size: 10pt;
color: #6c757d;
}
@bottom-right {
content: "Methodology - Page " counter(page);
}
}
@page results {
@top-left {
content: "Chapter 3: Results";
font-weight: bold;
font-size: 12pt;
color: #dc3545;
background-color: #f8d7da;
padding: 5px;
border-bottom: 1px solid #ccc;
}
@bottom-left {
content: "Results Footer";
font-size: 10pt;
color: #6c757d;
}
@bottom-right {
content: "Results - Page " counter(page);
}
}
/* 在每个页面递增页码计数器 */
@page {
counter-increment: page;
}
/* 辅助样式,使内容更易读 */
.content {
padding: 20px;
}
h1 {
margin-bottom: 20px;
border-bottom: 2px solid #ccc;
padding-bottom: 10px;
}
JavaScript (script.js):
document.addEventListener("DOMContentLoaded", function() {
const chapters = document.querySelectorAll(".chapter");
chapters.forEach(chapter => {
const chapterName = chapter.getAttribute("data-chapter-name");
if (chapterName) {
chapter.parentNode.setAttribute("data-chapter", chapterName);
chapter.parentNode.style.page = chapterName; // 设置 page 属性以配合 @page 选择器
}
});
});
这个示例展示了如何使用 CSS page 选择器、自定义属性和 JavaScript 来为不同的章节设置不同的页眉页脚。代码包含了 HTML 结构、CSS 样式和 JavaScript 脚本,可以复制粘贴到本地进行测试。
9. 总结
通过利用 CSS 的 @page 规则,结合 page 选择器和自定义属性,以及 JavaScript 动态设置属性,我们可以实现针对不同章节应用不同页眉页脚的功能。这种方法不仅可以提高代码的可维护性,还能让网页在视觉上更加清晰和专业。 结合 CSS 和 JavaScript,自定义页眉页脚,页面更清晰。
更多IT精英技术系列讲座,到智猿学院