关于 Safari Reader 生成 HTML 的思考
在发布有关如何在网站上启用 Safari 阅读器的帖子后,我决定多尝试一下。 事实证明,每次单击那个闪亮的小阅读器按钮时,Safari 都会生成一个 HTML 文档并将其显示为原始文档的叠加层。 让我们看看这个过程中使用的 HTML 和 CSS,看看我们如何处理它。
Safari 阅读器生成以下 HTML:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<base href="{article URL}">
<title><!-- {article title} --></title>
<style id="article-content">
@media print {
.original-url {
display: none;
}
}
h1.title {
font-family: Palatino, Georgia, Times, "Times New Roman", serif;
font-weight: bold;
font-size: 1.33em;
line-height: 1.25em;
}
h1 {
font-size: 1.25em;
}
h2 {
font-size: 1.125em;
}
h3 {
font-size: 1.05em;
}
.page a {
text-decoration: none;
color: rgb(32, 0, 127);
}
.page a:visited {
color: rgb(32, 0, 127);
}
#article img {
/* Float images to the left, so that text will nicely flow around them. */
float: left;
margin-right: 12px;
}
#article img.reader-image-tiny {
/* Don't float very small images -- let them display where they occur in the text. */
float: none;
margin: 0;
}
#article img.reader-image-large {
float: none;
margin: auto;
display: block;
}
.float {
margin: 8px 0;
font-size: 65%;
line-height: 1.4;
text-align: left;
}
.float.left {
float: left;
margin-right: 20px;
}
.float.right {
float: right;
margin-left: 20px;
}
.float.full-width {
float: none;
display: block;
}
.page {
font: 20px Palatino, Georgia, Times, "Times New Roman", serif;
line-height: 160%;
text-align: justify;
}
.page:first-of-type .title {
display: block;
}
.page table {
font-size: 0.9em;
text-align: left;
}
.page.rtl table {
text-align: right;
}
.page-number {
display: none;
}
.title {
display: none;
}
</style>
<style id="reader-ui">
@media screen {
body {
margin: 0;
padding: 0;
background-color: transparent;
-webkit-user-select: none;
}
.cached embed,
.cached applet,
.cached object {
display: none !important;
}
#background {
background-color: rgba(0, 0, 0, 0.8);
-webkit-transform: translateZ(0);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#container {
margin-left: -431px;
left: 50%;
width: 862px;
height: 100%;
position: absolute;
pointer-events: none;
}
#centered {
position: absolute;
top: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.preloading #background {
opacity: 0;
}
.preloading #centered {
-webkit-transform: translate3d(0, 100%, 0);
}
.activating #background {
-webkit-transition: opacity 0.40s ease-out;
opacity: 1.0;
}
.activating #fade-top {
-webkit-animation-name: fadeTopActivationFadeIn;
-webkit-animation-duration: 0.40s;
-webkit-animation-timing-function: ease-out;
}
.activating.skip-transition #fade-top {
-webkit-animation: none !important;
}
@-webkit-keyframes fadeTopActivationFadeIn {
0% {
opacity: 0;
}
80% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.activating.skip-transition #background {
-webkit-transition: none !important;
}
.activating #centered {
-webkit-transition: -webkit-transform 0.40s ease-out;
-webkit-transform: translate3d(0, 0, 0);
}
.activating.skip-transition #centered {
-webkit-transition: none !important;
}
.deactivating #background {
-webkit-transition: opacity 0.40s ease-in;
opacity: 0;
}
.deactivating #fade-top {
opacity: 0;
}
.deactivating #fade-bottom {
-webkit-transition: opacity 0.40s ease-in;
opacity: 0;
}
.deactivating #centered {
-webkit-transition: -webkit-transform 0.40s ease-in;
-webkit-transform: translate3d(0, 100%, 0);
}
.deactivating #hud {
-webkit-transition: opacity 0.25s ease-in;
opacity: 0 !important;
}
#drop-shadow {
position: absolute;
top: 0;
bottom: 0;
width: 800px;
left: 10px;
border-width: 24px 24px;
-webkit-border-image: url(safari-resource:/ReaderDropShadow.png) 24 24 24 24 stretch stretch;
opacity: 0;
}
::-webkit-scrollbar {
width: 21px;
}
::-webkit-scrollbar:horizontal {
display: none;
}
::-webkit-scrollbar-track {
margin-top: 20px;
margin-bottom: 20px;
-webkit-border-image: url(safari-resource:/ReaderTrack.png) 21 0 21 0;
border-width: 21px 0;
}
::-webkit-scrollbar-track:disabled {
display: none;
}
::-webkit-scrollbar-thumb {
-webkit-border-image: url(safari-resource:/ReaderThumb.png) 19 0 19 0;
border-width: 19px 0;
min-height: 40px;
}
#hud {
position: fixed;
width: 314px;
height: 72px;
left: 50%;
margin-left: -157px;
bottom: 30px;
background: rgba(0, 0, 0, 0.75);
-webkit-border-radius: 12px;
z-index: 100;
opacity: 0;
-webkit-transition: opacity 0.75s;
pointer-events: auto;
zoom: reset;
}
#hud button {
display: block;
float: left;
width: 48px;
height: 48px;
padding: 0;
border: none;
margin: 12px 5px;
}
#hud button:first-of-type {
margin-left: 12px;
}
#hud button:last-of-type {
margin-right: 12px;
}
#hud-zoom-out {
background: url(safari-resource:/ReaderHUDZoomOutInactive.png) no-repeat;
}
#hud-zoom-out:active {
background: url(safari-resource:/ReaderHUDZoomOutActive.png) no-repeat;
}
#hud-zoom-in {
background: url(safari-resource:/ReaderHUDZoomInInactive.png) no-repeat;
}
#hud-zoom-in:active {
background: url(safari-resource:/ReaderHUDZoomInActive.png) no-repeat;
}
#hud-mail {
background: url(safari-resource:/ReaderHUDMailContentsInactive.png) no-repeat;
}
#hud-mail:active {
background: url(safari-resource:/ReaderHUDMailContentsActive.png) no-repeat;
}
#hud-print {
background: url(safari-resource:/ReaderHUDPrintInactive.png) no-repeat;
}
#hud-print:active {
background: url(safari-resource:/ReaderHUDPrintActive.png) no-repeat;
}
#hud-exit {
background: url(safari-resource:/ReaderHUDCloseInactive.png) no-repeat;
}
#hud-exit:active {
background: url(safari-resource:/ReaderHUDCloseActive.png) no-repeat;
}
#article {
/* The width of 819px here includes 19px for the WebKit scrollbar’s width. */
/* The padding-right of 8px separates the scrollbar from the article itself. */
position: absolute;
height: 100%;
left: 34px;
width: 819px;
padding-right: 8px;
overflow: scroll;
z-index: 0;
outline: none;
pointer-events: auto;
-webkit-user-select: auto;
-webkit-transform: translateZ(0);
}
.article-fade {
position: absolute;
left: 34px;
height: 36px;
width: 800px;
z-index: 10;
pointer-events: none;
}
#fade-top {
top: 0;
background: url(safari-resource:/ReaderFadeTop.png) repeat-x;
}
#fade-bottom {
bottom: 0;
background: url(safari-resource:/ReaderFadeBottom.png) repeat-x;
}
#resize-indicator {
position: fixed;
bottom: 0;
right: 0;
width: 12px;
height: 12px;
background: url(safari-resource:/TopSitesCornerResize.png);
}
.page:only-of-type .page-number {
display: none;
}
.page-number {
display: block;
font: bold 11px Helvetica, sans-serif;
margin-left: 12px;
color: #B2B2B2;
position: absolute;
right: 10px;
top: 10px;
-webkit-user-select: none;
}
.page:first-of-type {
margin-top: 22px;
}
.page:last-of-type {
margin-bottom: 22px;
}
.page {
width: 658px;
margin-left: auto;
margin-right: auto;
margin-top: 10px;
padding: 45px 70px;
color: black;
background: white;
border: 1px solid #c3c3c3;
position: relative;
overflow: hidden;
-webkit-transition: height .5s ease-out;
}
.page.rtl {
direction: rtl;
}
#incoming-page-placeholder {
height: 30px;
margin-bottom: 0;
}
#incoming-page-corner {
position: absolute;
right: 10px;
top: 8px;
}
#incoming-page-spinner {
width: 16px;
height: 16px;
float: right;
background: url(safari-resource:/ReaderSpinner.png);
}
#incoming-page-text {
float: right;
margin-top: 2px;
margin-left: 8px;
color: #B2B2B2;
font: bold 11px Helvetica, sans-serif;
-webkit-user-select: none;
}
#next-page-container {
position: absolute;
display: none;
}
.no-transition {
-webkit-transition: none !important;
}
/* These keyframes try to reproduce the 12 discrete steps seen in a standard system progress indicator. */
@-webkit-keyframes discreteSpinner {
0% {
-webkit-transform: rotate(0deg);
}
8.332% {
-webkit-transform: rotate(0deg);
}
8.333% {
-webkit-transform: rotate(30deg);
}
16.665% {
-webkit-transform: rotate(30deg);
}
16.666% {
-webkit-transform: rotate(60deg);
}
24.999% {
-webkit-transform: rotate(60deg);
}
25.000% {
-webkit-transform: rotate(90deg);
}
33.332% {
-webkit-transform: rotate(90deg);
}
33.333% {
-webkit-transform: rotate(120deg);
}
41.665% {
-webkit-transform: rotate(120deg);
}
41.666% {
-webkit-transform: rotate(150deg);
}
49.999% {
-webkit-transform: rotate(150deg);
}
50.000% {
-webkit-transform: rotate(180deg);
}
58.332% {
-webkit-transform: rotate(180deg);
}
58.333% {
-webkit-transform: rotate(210deg);
}
66.665% {
-webkit-transform: rotate(210deg);
}
66.666% {
-webkit-transform: rotate(240deg);
}
74.999% {
-webkit-transform: rotate(240deg);
}
75.000% {
-webkit-transform: rotate(270deg);
}
83.332% {
-webkit-transform: rotate(270deg);
}
83.333% {
-webkit-transform: rotate(300deg);
}
91.665% {
-webkit-transform: rotate(300deg);
}
91.666% {
-webkit-transform: rotate(330deg);
}
100% {
-webkit-transform: rotate(330deg);
}
}
.animation-discrete-spinner {
-webkit-animation-name: discreteSpinner;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
</style>
<script src="safari-resource:/localizedStrings.js"></script>
</head>
<!-- The body element will have class="preloading", which gets nullified after the loading is completed. — Mathias -->
<body class=" " onload="ReaderJS.loaded();" onselectstart="setHUDAcceptsPointerEvents(false);" onmouseup="setHUDAcceptsPointerEvents(true);" onblur="didLoseFocus();">
<div id="background" onclick="deactivateAfterAnimation();"></div>
<iframe id="next-page-container"></iframe>
<div id="container">
<div id="resize-indicator" style="display: block;"></div>
<div id="hud" onmouseover="hudMouseOver(event);" onmouseout="hudMouseOut(event);" style="pointer-events: none; opacity: 0;">
<button id="hud-zoom-out" onclick="makeTextSmaller();" title="Zoom out" disabled="true"></button>
<button id="hud-zoom-in" onclick="makeTextLarger();" title="Zoom in" disabled="true"></button>
<button id="hud-mail" onclick="mailArticle();" title="Mail this page" disabled="true"></button>
<button id="hud-print" onclick="printArticle();" title="Print this page" disabled="true"></button>
<button id="hud-exit" onclick="deactivateAfterAnimation();" title="Exit Reader" disabled="true"></button>
</div>
<div id="centered">
<div id="drop-shadow" style="opacity: 1;"></div>
<div id="article" onscroll="articleScrolled();" tabindex="0">
<!-- This node contains a number of 'page' class divs. -->
<div class="page" style="font-family: Palatino, Georgia, Times, 'Times New Roman', serif; font-size: 17px; line-height: 1.4; padding-bottom: 85px;">
<div class="page-number">Page 1 of 1</div>
<h1 class="title"><!-- {article title} --></h1>
<!-- {article HTML} -->
</div>
</div>
</div>
<div id="fade-top" class="article-fade" style="clip: rect(-147px 800px 36px 0px);"></div>
<div id="fade-bottom" class="article-fade" style="clip: rect(0px 800px 36px 0px);"></div>
</div>
</body>
</html>
请注意,我已将所有可变内容替换为
<!-- {article title} -->
形式的 HTML 注释,以便更轻松地关注每次打开 Reader 时 Safari 使用的生成代码。 可以在 Mac 上的file:///Applications/Safari.app/Contents/Resources/Reader.html
找到原始模板(没有任何指示实际内容的去向)。
一些注意事项:
- 尽管使用了 HTML5 DOCTYPE,但文档的字符编码仍采用老式方式设置。
-
Reader 文档的
<body>
元素具有“空”类属性(仅包含空格)。 当将它与 Reader 模板交叉引用时,我们了解到该属性最初有一个值:class="preloading"
。 -
预加载微调器(在多页文章上使用阅读器时可见)不是 GIF 图像,而是使用
[vendor-specific]
“CSS3” 属性进行旋转。 (在代码中查找 discreteSpinner。) -
打开 Reader 时,Web Inspector 会自动关闭。 此外,“Show Web Inspector”和“Show Error Console”项目(位于“Develop”菜单下)被禁用。 这些功能的键盘快捷键(分别为
⌘ + ⌥ + I
和⌘ + ⌥ + C
)也不起作用。 但是,仍然可以右键单击 Reader 文档并选择“检查元素”。 这样做无论如何都会打开 Web Inspector,并让我们可以访问它的所有工具。 - 使用 JavaScript 和 CSS 自定义 Safari 阅读器 UI
因为 Safari 阅读器是基于 HTML 的,所以我们可以轻松编写自己的 CSS 来代替默认的 CSS。
例如,尝试在打开 Reader 后从控制台运行以下 JavaScript 代码,以极大地提高其可用性和整体性能:
(function(d) {
var s = d.createElement('style');
var c = '#background{background:#f773b5 url(https://i.imgur.com/bB7aD.jpg)}h1.title,.page{font-family:"Comic Sans MS"!important}';
c += 'h1.title{color:#f773b5}.page{background:rgba(255,255,255,.9);-webkit-animation-name:f;-webkit-animation-duration:5s;';
c += '-webkit-animation-iteration-count:infinite;-webkit-animation-timing-function:linear}@-webkit-keyframes f{';
c += '0%{-webkit-transform:rotate(0) scale(1)}25%{-webkit-transform:rotate(-4deg) scale(.95)}50%{-webkit-transform:rotate(0) scale(1)}';
c += '75%{-webkit-transform:rotate(4deg) scale(.95)}100%{-webkit-transform:rotate(0) scale(1)}}';
s.appendChild(d.createTextNode(c));
d.head.appendChild(s)
}(document));
好多了,对吧?
如何使用 JavaScript 定位 Reader 文档?
我想通过将代码重写为单行代码并在其前面加上 javascript: 来使它成为一个小书签,但不幸的是,这似乎不起作用。 在启用了阅读器的 Safari 中使用小书签时,文档仍然指的是原始 HTML 文档,而不是阅读器文档。 奇怪的是,在控制台中输入时,文档确实引用了 Reader 文档。
事情是这样的——我不知道如何在 JavaScript 中定位 Reader 文档。 它不是 frameset
或 iframe
; 原始文档的 DOM 似乎没有任何改变。
了解如何使用 JavaScript 操作 Safari Reader 文档,而无需使用控制台,这将是一件非常有趣的事情。
相关文章
HTML 中的 role 属性
发布时间:2023/05/06 浏览次数:124 分类:HTML
-
本篇文章介绍 HTML role属性。HTML中 role 属性介绍,role 属性定义描述语义的 HTML 元素的角色。
在 HTML 中打印时分页
发布时间:2023/05/06 浏览次数:188 分类:HTML
-
本篇文章介绍如何在打印 HTML 页面或内容时强制分页。将 page-break-after 属性设置为 always Inside @media print to Page Break in HTML
在 HTML 中显示基于 Cookie 的图像
发布时间:2023/05/06 浏览次数:154 分类:HTML
-
本文介绍如何根据 HTML 中的 cookies 显示图像。根据 HTML 中设置的 Cookies 显示图像。问题陈述是我们需要根据网页传递的cookie来显示特定的图像。
在 HTML 中创建下载链接
发布时间:2023/05/06 浏览次数:140 分类:HTML
-
本文介绍如何在 HTML 中创建下载链接。使用 download 属性在 HTML 中创建下载链接.。我们可以使用 HTML 锚元素内的下载属性来创建下载链接。
HTML 中的 ::before 选择器
发布时间:2023/05/06 浏览次数:70 分类:HTML
-
本教程介绍 CSS ::before 伪元素。CSS ::before 伪元素。 ::before 选择器是一个 CSS 伪元素,我们可以使用它在一个或多个选定元素之前插入内容。 它默认是内联的。
在 HTML 中创建一个可滚动的 Div
发布时间:2023/05/06 浏览次数:54 分类:HTML
-
本篇文章介绍如何使 HTML div 可滚动。本文将介绍在 HTML 中使 div 可滚动的方法。 我们将探索垂直和水平滚动,并通过示例查看它们的实现。
HTML 显示箭头的代码
发布时间:2023/05/06 浏览次数:153 分类:HTML
-
一篇关于用于显示箭头的 Unicode 字符实体的紧凑文章。本文讨论使用 Unicode 字符实体在我们的 HTML 页面上显示不同的字符。 HTML 中使用了许多实体,但我们将重点学习表示上、下、左、右的三角
在 HTML 中启用和禁用复选框
发布时间:2023/05/06 浏览次数:149 分类:HTML
-
本篇文章介绍如何启用和禁用 HTML 中的复选框。HTML 中的复选框 复选框是一个交互式框,可以切换以表示肯定或否定。 它广泛用于表单和对话框。
HTML 中的只读复选框
发布时间:2023/05/06 浏览次数:198 分类:HTML
-
本篇文章介绍了如何在 HTML 中制作只读复选框。本文是关于如何使 HTML 复选框控件成为只读组件的快速破解。 但是,首先,让我们简要介绍一下复选框控件。