Files
ulthon_information/public/static/css/phone-image-templates.css
augushong 491a71bd44 feat(phone-image): fontSize滑块生效、水印渲染、保存大小检查和空内容提示
T5: 通过JS setProperty动态设置--pi-font-size-base让fontSize滑块真正改变渲染字号,
    修复h4标题不使用CSS变量避免被影响
T6: 在封面页/内容页/尾页生成函数中添加水印HTML,CSS添加.page-watermark样式
T7: saveImages添加16MB大小检查,render添加空内容检测提示,
    doCapturePages错误路径添加staging清理
2026-05-07 21:39:26 +08:00

611 lines
14 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ============================================
Phone Image Template System
用于生成手机端分享图片的CSS框架
渲染宽度540px, html2canvas scale=2 输出1080px
注意: 仅使用html2canvas兼容的CSS属性
支持: flexbox, border-radius, box-shadow, background-color,
font, padding, margin, border, position(relative/absolute/fixed)
不支持: transform, filter, clip-path, backdrop-filter,
CSS grid, object-fit, position:sticky, CSS animations
============================================ */
/* --- CSS Custom Properties (小红书经典风格) --- */
:root {
/* 字号 */
--pi-font-size-base: 14px;
--pi-font-size-title: 26px;
--pi-font-size-subtitle: 16px;
--pi-font-size-small: 12px;
/* 行高 */
--pi-line-height: 1.8;
/* 间距 */
--pi-spacing: 20px;
--pi-spacing-sm: 10px;
--pi-spacing-lg: 30px;
--pi-spacing-xs: 5px;
/* 颜色 */
--pi-color-text: #333333;
--pi-color-text-light: #666666;
--pi-color-text-lighter: #999999;
--pi-color-bg: #ffffff;
--pi-color-accent: #1890ff;
--pi-color-border: #eeeeee;
/* 圆角 */
--pi-radius: 12px;
/* 字体 */
--pi-font-family: 'Source Han Sans', 'SourceHanSans-Normal', sans-serif;
}
/* ============================================
Base Container
固定540px宽度的最外层容器
============================================ */
.phone-image-container {
width: 540px;
background: var(--pi-color-bg);
color: var(--pi-color-text);
font-family: var(--pi-font-family);
font-size: var(--pi-font-size-base);
line-height: var(--pi-line-height);
overflow: hidden;
position: relative;
}
/* ============================================
Page Container
每一页的容器, 尺寸由 size class 控制
============================================ */
.phone-image-page {
overflow: hidden;
box-sizing: border-box;
position: relative;
}
/* 水印 - 位于每页右下角的半透明文字 */
.page-watermark {
position: absolute;
bottom: 60px;
right: 20px;
font-size: 12px;
color: rgba(0, 0, 0, 0.3);
pointer-events: none;
white-space: nowrap;
}
/* ============================================
Size Variants
两种主流手机图片尺寸
============================================ */
/* 小红书尺寸 540x720 (输出1080x1440) */
.size-xiaohongshu .phone-image-page {
width: 540px;
height: 720px;
}
/* 抖音尺寸 540x960 (输出1080x1920) */
.size-douyin .phone-image-page {
width: 540px;
height: 960px;
}
/* ============================================
Page Type Variants
三种页面类型: 封面页/内容页/总结页
============================================ */
/* --- 封面页/首页 --- */
.page-cover {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: var(--pi-spacing-lg);
text-align: center;
}
.page-cover .cover-title {
font-size: 28px;
font-weight: normal;
letter-spacing: 2px;
line-height: 1.5;
margin-bottom: var(--pi-spacing);
color: var(--pi-color-text);
word-break: break-word;
}
.page-cover .cover-subtitle {
font-size: var(--pi-font-size-subtitle);
color: var(--pi-color-text-light);
margin-bottom: var(--pi-spacing);
}
.page-cover .cover-image {
width: 100%;
margin-bottom: var(--pi-spacing);
}
.page-cover .cover-meta {
font-size: var(--pi-font-size-small);
color: var(--pi-color-text-lighter);
margin-top: var(--pi-spacing-sm);
}
/* --- 封面页 - 无封面图装饰排版 --- */
.page-cover.no-cover-image {
justify-content: center;
padding: var(--pi-spacing-lg);
}
.page-cover.no-cover-image .cover-decor-line {
position: absolute;
left: 30px;
right: 30px;
height: 2px;
background: var(--pi-color-border);
}
.page-cover.no-cover-image .cover-decor-top {
top: 80px;
}
.page-cover.no-cover-image .cover-decor-bottom {
bottom: 80px;
}
.page-cover.no-cover-image .cover-no-img-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: var(--pi-spacing) 0;
}
.page-cover.no-cover-image .cover-no-img-title {
font-size: 36px;
font-weight: bold;
line-height: 1.4;
color: var(--pi-color-text);
word-break: break-word;
margin-bottom: var(--pi-spacing);
padding: 0 20px;
}
.page-cover.no-cover-image .cover-decor-divider {
width: 60px;
height: 3px;
background: var(--pi-color-accent);
margin-bottom: var(--pi-spacing);
}
.page-cover.no-cover-image .cover-no-img-desc {
font-size: var(--pi-font-size-subtitle);
color: var(--pi-color-text-light);
line-height: 1.8;
margin-bottom: var(--pi-spacing);
padding: 0 30px;
word-break: break-word;
}
.page-cover.no-cover-image .cover-no-img-meta {
display: flex;
gap: 15px;
font-size: var(--pi-font-size-small);
color: var(--pi-color-text-lighter);
flex-wrap: wrap;
justify-content: center;
}
/* --- 内容页图片强制约束 --- */
.page-content img {
max-width: 100% !important;
height: auto !important;
display: block;
margin: 10px 0;
}
/* --- 内容页 --- */
.page-body {
display: flex;
flex-direction: column;
padding: var(--pi-spacing);
}
/* 内容页 - 页头区域 */
.page-header {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 20px;
}
.page-header .page-title {
font-size: 20px;
font-weight: normal;
letter-spacing: 1px;
color: #666;
line-height: 1.4;
word-break: break-word;
}
.page-header .page-subtitle {
font-size: var(--pi-font-size-subtitle);
color: var(--pi-color-text-light);
margin-top: var(--pi-spacing-sm);
}
/* 内容页 - 正文区域 */
.page-content {
flex: 1;
overflow: hidden;
word-break: break-word;
line-height: 2.0;
}
.page-content p {
text-indent: 2em;
margin-bottom: 16px;
color: #333;
}
.page-content h2 {
font-weight: normal;
font-size: 18px;
letter-spacing: 1px;
margin-top: 24px;
margin-bottom: 12px;
color: #333;
}
.page-content h3 {
font-weight: normal;
font-size: 16px;
margin-top: 20px;
margin-bottom: 10px;
color: #555;
}
.page-content h4 {
font-size: 14px;
font-weight: bold;
margin-top: var(--pi-spacing-sm);
margin-bottom: 5px;
}
.page-content h5 {
font-size: 13px;
font-weight: bold;
margin-top: var(--pi-spacing-sm);
margin-bottom: 5px;
}
.page-content h6 {
font-size: 12px;
font-weight: bold;
margin-top: var(--pi-spacing-sm);
margin-bottom: 5px;
color: var(--pi-color-text-light);
}
.page-content blockquote {
border-left: 1px solid #ccc;
font-style: normal;
color: #888;
padding-left: 15px;
margin: var(--pi-spacing-sm) 0;
}
.page-content ul,
.page-content ol {
padding-left: var(--pi-spacing);
margin-bottom: var(--pi-spacing-sm);
}
.page-content li {
margin-bottom: 5px;
}
/* 内容页 - 页脚区域 */
.page-footer {
border-top: none;
padding-top: 0;
margin-top: var(--pi-spacing-sm);
font-size: 11px;
color: #bbb;
display: flex;
justify-content: space-between;
align-items: center;
}
/* --- 总结页/尾页 --- */
.page-summary {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: var(--pi-spacing-lg);
text-align: center;
}
.page-summary .summary-title {
font-weight: normal;
letter-spacing: 2px;
font-size: 22px;
margin-bottom: var(--pi-spacing);
color: var(--pi-color-text);
}
.page-summary .summary-text {
font-size: var(--pi-font-size-subtitle);
color: #aaa;
font-weight: normal;
margin-bottom: var(--pi-spacing);
line-height: 1.6;
}
.page-summary .summary-qr {
margin-bottom: var(--pi-spacing-sm);
}
.page-summary .summary-footer {
font-size: var(--pi-font-size-small);
color: #ccc;
}
/* ============================================
Font Variants
============================================ */
.font-source-han-sans {
--pi-font-family: 'Source Han Sans', 'SourceHanSans-Normal', sans-serif;
}
/* ============================================
Article Images
文章内图片样式
============================================ */
/* 行内图片, 有边距 */
.article-image {
max-width: 100%;
height: auto;
display: block;
margin: var(--pi-spacing) 0;
}
/* 全宽图片, 无边距 */
.article-image-full {
width: 100%;
height: auto;
display: block;
margin: 0;
}
/* ============================================
Page Number Indicator
页码指示器
============================================ */
.page-number-indicator {
position: absolute;
bottom: 10px;
right: 15px;
font-size: var(--pi-font-size-small);
color: var(--pi-color-text-lighter);
}
/* ============================================
Vertical Alignment (逐页对齐)
============================================ */
.page-body.valign-center .page-content {
display: flex;
flex-direction: column;
justify-content: center;
}
/* ============================================
Content Flow (中间栏内容流)
所有元素按实际尺寸纵向排列
============================================ */
.content-flow {
width: 540px;
padding: 20px;
box-sizing: border-box;
background: #fff;
min-height: 100%;
}
.content-flow-block {
position: relative;
margin-bottom: 0;
}
.content-flow-block img {
max-width: 100%;
height: auto;
display: block;
}
/* --- 分页插入区域 --- */
.break-inserter {
height: 20px;
border-top: 1px dashed #ddd;
display: flex;
align-items: center;
justify-content: center;
margin: 2px 0;
cursor: pointer;
}
.break-inserter:hover {
border-color: var(--pi-color-accent);
background: rgba(24, 144, 255, 0.05);
}
.break-inserter-btn {
opacity: 0;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--pi-color-accent);
color: #fff;
font-size: 14px;
line-height: 20px;
text-align: center;
border: none;
cursor: pointer;
padding: 0;
}
.break-inserter:hover .break-inserter-btn {
opacity: 1;
}
/* --- 已插入的分页标记 --- */
.page-break-marker {
height: 30px;
background: #fff3f3;
border: 1px dashed #ff4d4f;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin: 4px 0;
position: relative;
}
.page-break-marker .break-marker-label {
font-size: 12px;
color: #ff4d4f;
user-select: none;
}
.page-break-marker .remove-break-btn {
position: absolute;
right: 8px;
top: 50%;
margin-top: -10px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #ff4d4f;
color: #fff;
font-size: 14px;
line-height: 20px;
text-align: center;
border: none;
cursor: pointer;
padding: 0;
opacity: 0;
}
.page-break-marker:hover .remove-break-btn {
opacity: 1;
}
/* ============================================
Preview Thumbnails (缩略图容器)
============================================ */
.preview-thumbnails {
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 20px;
height: 100%;
padding: 0 10px;
}
.preview-thumb-item {
position: relative;
flex-shrink: 0;
text-align: center;
}
.preview-thumb-item img {
display: block;
border: 1px solid #e0e0e0;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.preview-thumb-page-num {
display: block;
text-align: center;
font-size: 12px;
color: #999;
margin-top: 6px;
}
.thumb-alignment-toggle {
position: absolute;
top: 8px;
right: 8px;
z-index: 10;
opacity: 0;
width: 24px;
height: 24px;
border-radius: 4px;
background: rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
user-select: none;
border: none;
padding: 0;
cursor: pointer;
transition: opacity 0.2s;
}
.preview-thumb-item:hover .thumb-alignment-toggle {
opacity: 1;
}
.thumb-alignment-toggle:hover {
background: rgba(0, 0, 0, 0.1);
}
.thumb-alignment-toggle.active-center {
opacity: 1;
background: rgba(24, 144, 255, 0.15);
color: #1890ff;
}
/* ============================================
Content Flow Code Blocks (中间栏代码块样式)
仅用于编辑区中间栏, 不影响渲染页面
============================================ */
/* 表格美化样式html2canvas兼容 */
.page-content table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13px; }
.page-content th { background-color: #f0f0f0; font-weight: bold; padding: 8px 10px; border: 1px solid #ddd; text-align: left; }
.page-content td { padding: 8px 10px; border: 1px solid #ddd; }
.page-content tr:nth-child(even) td { background-color: #f9f9f9; }
.content-flow pre {
background: #f5f5f5;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 12px;
overflow-x: auto;
font-size: 13px;
line-height: 1.6;
margin: 10px 0;
}
.content-flow code {
font-family: 'Courier New', Consolas, monospace;
font-size: 13px;
}
.content-flow pre code {
background: none;
border: none;
padding: 0;
}
/* 中间栏表格样式 */
.content-flow-block table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13px; }
.content-flow-block th { background-color: #f0f0f0; font-weight: bold; padding: 8px 10px; border: 1px solid #ddd; text-align: left; }
.content-flow-block td { padding: 8px 10px; border: 1px solid #ddd; }
.content-flow-block tr:nth-child(even) td { background-color: #f9f9f9; }