This commit is contained in:
Sivan 2020-02-11 20:47:29 +08:00
commit f65382b12a
19 changed files with 5085 additions and 0 deletions

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
# EditorConfig from https://github.com/sivan/dotfiles
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
indent_size = 4
trim_trailing_whitespace = false

21
.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# Editor generate files
.idea/
.settings/
# Dev dependencies and cache files
dist/
node_modules/
npm-debug.log
# Folder view configuration files
.DS_Store
Desktop.ini
# Thumbnail cache files
*~
._*
Thumbs.db
# Files that might appear on external disks
.Spotlight-V100
.Trashes

11
.stylelintrc Normal file
View file

@ -0,0 +1,11 @@
{
"extends": ["stylelint-config-standard", "stylelint-config-recommended-scss"],
"rules": {
"no-descending-specificity": [
true,
{
"ignore": ["selectors-within-list"]
}
]
}
}

40
README.md Normal file
View file

@ -0,0 +1,40 @@
# 赫蹏
赫蹏(hètí)是专为中文内容展示设计的排版样式增强。它基于通行的中文排版规范而来,可以为网站的读者带来更好的文章阅读体验。
主要特性:
- 全标签样式统一;
- 贴合网格的排版;
- 内置多种预设字体族(仅限桌面端);
- 支持横排、竖排两种排版;
- 支持诗词、行间注版式;
- 兼容 *normalize.css*、**CSS Reset** 等大部分重置样式;
- 移动端支持;
- ……
## 使用方法
1. 在页面的 `<head>` 标签中引入 `heti.css` 文件:
```
<link rel="stylesheet" href="./heti.css">
```
1. 在要作用的容器元素上增加 `class="heti"` 的类名即可:。
```
<article class="entry heti">
<h1>我的世界观</h1>
<p>有钱人的生活就是这么朴实无华,且枯燥</p>
……
</article>
```
## WIP
- [ ] 繁体中文支持
- [ ] 中、西文混排
- [ ] 标点挤压
- [ ] 标点悬挂
- [x] 诗词版式
- [x] 行间注版式
-- EOF --

8
index.scss Normal file
View file

@ -0,0 +1,8 @@
/*!
* Project: Heti
* URL: https://github.com/sivan/heti
* Author: Sivan [sun.sivan@gmail.com]
* Date: 2020-01-22 00:00
*/
@import './lib/heti';

89
lib/_base.scss Normal file
View file

@ -0,0 +1,89 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: base reset and entry styles.
*/
@import "variables";
@mixin hetiBase {
// 清容器浮动
@include clear-float();
// 清容器内首尾元素外边距
&,
section,
td {
> *:first-child {
margin-block-start: 0 !important;
}
> *:last-child {
margin-block-end: 0 !important;
}
}
// 定义块级元素样式
blockquote {
margin-block-start: $std-block-unit / 2;
margin-block-end: $std-block-unit;
margin-inline-start: $std-inline-unit * 2;
margin-inline-end: $std-inline-unit * 2;
padding-block-start: $std-block-unit / 2;
padding-block-end: $std-block-unit / 2;
padding-inline-start: $std-inline-unit;
padding-inline-end: $std-inline-unit;
background-color: rgba(0, 0, 0, 0.054);
//border-radius: 4px;
}
figure {
display: block;
text-align: center;
> img {
display: block;
margin-inline-start: auto;
margin-inline-end: auto;
}
}
hr {
width: 30%;
height: 1px;
margin-block-start: $std-block-unit * 2;
margin-block-end: $std-block-unit * 2 - 1px;
margin-inline-start: auto;
margin-inline-end: auto;
border: 0;
background-color: #ddd;
}
p {
margin-block-start: $std-block-unit / 2;
margin-block-end: $std-block-unit;
text-align: justify;
@include non-cjk-block {
text-align: left;
}
//+ pre {
// margin-block-start: -$std-block-unit / 2;
//}
}
pre {
margin-block-start: $std-block-unit / 2;
margin-block-end: $std-block-unit / 2;
margin-inline-start: 0;
margin-inline-end: 0;
padding-block-start: $std-block-unit / 2;
padding-block-end: $std-block-unit / 2;
padding-inline-start: $std-inline-unit;
padding-inline-end: $std-inline-unit;
overflow: auto;
white-space: pre;
word-wrap: normal;
background-color: rgba(0, 0, 0, 0.054);
border-radius: 4px;
}
}

57
lib/_font.scss Normal file
View file

@ -0,0 +1,57 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: define font-face.
*/
@import "variables";
// 黑体
@font-face {
font-family: "Heti-Hei";
src: local("PingFang SC Light"), local("Heiti SC Light"), local("STXihei");
font-weight: 200;
}
@font-face {
font-family: "Heti-Hei";
src: local("Pingfang SC Regular"), local("Heiti SC Medium"), local(STHeiti);
font-weight: 400;
}
@font-face {
font-family: "Heti-Hei";
src: local("PingFang SC Medium"), local("Heiti SC Light");
font-weight: 600;
}
@font-face {
font-family: "Heti-Hei";
src: local("Pingfang SC Semibold"), local("Heiti SC Light");
font-weight: 800;
}
// 宋体
// 楷体
@font-face {
font-family: "Heti-Kai";
src: local("Kaiti SC Regular"), local("Heiti SC Light");
font-weight: 200;
}
@font-face {
font-family: "Heti-Kai";
src: local("Kaiti SC Regular"), local(STKaiti);
font-weight: 400;
}
@font-face {
font-family: "Heti-Kai";
src: local("Kaiti SC Bold"), local(STKaiti);
font-weight: 600;
}
@font-face {
font-family: "Heti-Kai";
src: local("Kaiti SC Black"), local(STKaiti);
font-weight: 800;
}

65
lib/_heading.scss Normal file
View file

@ -0,0 +1,65 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: heading styles.
*/
@import "variables";
@mixin hetiHeading {
h1,
h2,
h3,
h4,
h5,
h6 {
position: relative;
// 顶边距默认为一行间距且不因边距重叠原因减半
// 底边距考虑到亲密性默认为半行间距
margin-block-start: $std-block-unit;
margin-block-end: $std-block-unit / 2;
font-weight: $font-weight-bold;
}
h1 {
margin-block-end: $std-block-unit;
font-size: $font-size-h1;
line-height: $line-height-size-h1;
letter-spacing: $font-size-h1 * 0.05;
}
h2 {
font-size: $font-size-h2;
line-height: $line-height-size-h2;
letter-spacing: $font-size-h2 * 0.05;
}
h3 {
font-size: $font-size-h3;
line-height: $line-height-size-h3;
letter-spacing: $font-size-h3 * 0.05;
}
h4 {
font-size: $font-size-h4;
line-height: $line-height-size-h4;
}
h5 {
font-size: $font-size-h5;
line-height: $line-height-size-h5;
}
h6 {
font-size: $font-size-h6;
line-height: $line-height-size-h6;
}
// 压缩两个标题之间的间距
h1 + h2,
h2 + h3,
h3 + h4,
h4 + h5,
h5 + h6 {
margin-block-start: $std-block-unit / 2;
}
}

59
lib/_helper-block.scss Normal file
View file

@ -0,0 +1,59 @@
/*
* Author: Sivan [sun.sivan@gmail.com]
* Description: define block helper classes.
*/
@import "variables";
@mixin hetiBlockHelperClasses {
// 定义拉丁字母的有序列表
#{$root-selector}-list-latin {
list-style-type: upper-latin;
ol {
list-style-type: lower-roman;
ol {
list-style-type: lower-latin;
}
}
}
// 定义中文序号的有序列表
#{$root-selector}-list-han {
list-style-type: cjk-ideographic;
ol {
list-style-type: decimal;
ol {
list-style-type: decimal-leading-zero;
}
}
}
// 定义多栏布局
@each $columns in (2, 3, 4) {
#{$root-selector}-columns-#{$columns} {
// 多行时不再设总宽度限制
max-width: none;
column-count: #{$columns};
column-gap: 2em;
}
}
@each $column-width in (16em, 20em, 24em, 28em, 32em, 36em, 40em, 44em, 48em) {
#{$root-selector}-columns-#{$column-width} {
// 多行时不再设总宽度限制
max-width: none;
column-width: #{$column-width};
column-gap: 2em;
}
}
// 元信息诗节居中显示
#{$root-selector}-meta {
line-height: $line-height-size-normal;
text-align: center;
text-indent: 0;
}
}

47
lib/_helper-inline.scss Normal file
View file

@ -0,0 +1,47 @@
/*
* Author: Sivan [sun.sivan@gmail.com]
* Description: define inline helper classes.
*/
@import "variables";
@mixin hetiInlineHelperClasses {
// 标题内锚点
#{$root-selector}-anchor {
position: absolute;
left: -1em;
width: 1em;
font-family: $font-family-hei;
font-weight: 400;
line-height: inherit;
text-align: center;
opacity: 0;
transition: opacity 0.2s linear;
&:hover {
text-decoration: none;
border-block-end: 0;
}
@at-root {
#{$root-selector} {
h1,
h2,
h3,
h4,
h5,
h6 {
position: relative;
&:hover #{$root-selector}-anchor {
opacity: 1;
}
}
}
}
}
// @todo: 用于标点悬挂用的样式
#{$root-selector}-hang {
@include hang();
}
}

173
lib/_inline.scss Normal file
View file

@ -0,0 +1,173 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: inline element styles.
*/
@import "variables";
@mixin hetiInline {
a {
text-decoration: none;
&:hover {
padding-block-end: 1px;
border-block-end: 1px solid currentColor;
text-decoration: none;
}
}
abbr[title] {
padding-block-end: 1px;
border-block-end: 1px dotted;
text-decoration: none;
cursor: help;
}
b,
strong {
font-weight: $font-weight-bold;
}
code {
font-family: $font-family-mono;
font-size: $font-size-small;
}
dfn {
font-weight: $font-weight-bold;
// 非中文时显示斜体
@include non-cjk-block {
font-weight: $font-weight-normal;
}
}
em {
font-weight: $font-weight-bold;
}
// 标题单行时居中多行时居左
figcaption {
display: inline-block;
vertical-align: top;
font-size: $font-size-small;
text-align: start;
}
// 显式斜体标签予以保留
i {
font-style: italic;
}
ins,
u {
padding-block-end: 1px;
border-block-end: 1px solid;
text-decoration: none;
}
mark {
padding-block-start: 2px;
padding-block-end: 2px;
padding-inline-start: 1px;
padding-inline-end: 1px;
margin-inline-start: 1px;
margin-inline-end: 1px;
background-color: rgba(255, 247, 0, 0.88);
}
// 设置引用文本为中文引号
q {
quotes: "" "" "" "";
@include non-cjk-block {
quotes: initial;
quotes: auto;
}
}
rt {
font-size: 0.875em;
color: rgba(0, 0, 0, 0.88);
}
// 完美 <small> 字号 by Sivan
/// 12px * 0.875 => 11px
/// 14px * 0.875 => 12px
/// 16px * 0.875 => 14px
/// 18px * 0.875 => 16px
/// 20px * 0.875 => 18px
small {
font-size: 0.875em;
}
strong {
font-weight: $font-weight-bold;
}
sub,
sup {
position: relative;
margin-inline-start: 0.25em;
margin-inline-end: 0.25em;
font-size: 0.75em;
line-height: 1;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
summary {
padding-left: 1em;
outline: 0;
cursor: pointer;
}
summary::-webkit-details-marker {
width: 0.6em;
margin-inline-end: 0.4em;
}
u[title] {
cursor: help;
border-block-end-color: rgba(0, 0, 0, 0.54);
border-block-end-width: 3px;
border-block-end-style: double;
}
// 默认禁用中文斜体 https://www.zhihu.com/question/20120243
address,
cite,
dfn,
dt,
em {
font-style: normal;
// 非中文时显示斜体
@include non-cjk-block {
font-style: italic;
}
}
//b,
//cite,
//dfn,
//em,
//strong {
// margin-inline-start: 1px;
// margin-inline-end: 1px;
//}
// 带边框的元素两个相连时添加间距以防止视觉上混为一个元素
// @todo: 此处有一个问题如果结构是 <u>倚天</u><u>屠龙</u>屠龙前面仍然会有边距此处跟预期不一致应该只在两个同名元素紧邻时增加边距<u>倚天剑</u><u>屠龙刀</u>
//@each $tag in (abbr, del, ins, s, u) {
// #{$tag} + #{$tag} {
// margin-inline-start: 0.125em;
// }
//}
}

55
lib/_list.scss Normal file
View file

@ -0,0 +1,55 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: list styles.
*/
@import "variables";
@mixin hetiList {
// 标准化间距
ul,
ol,
dl {
margin-block-start: $line-height-size-normal / 2;
margin-block-end: $line-height-size-normal;
}
ul,
ol {
padding-inline-start: $text-indent-length;
ul,
ol {
margin-block-start: 0;
margin-block-end: 0;
}
}
// 重置部分 CSS Reset ul, ol { list-style: none; } 造成的样式污染
// 如果搭配 normalize.css 使用则不存在这些样式污染
@if $_css-reset-scheme == "reset" {
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
ul ul,
ol ul {
list-style-type: circle;
}
ul ul ul,
ul ol ul,
ol ul ul,
ol ol ul {
list-style-type: square;
}
// 重置不知道哪里散播出来的垃圾代码 ul, li { list-style: none; }
li {
list-style-type: unset;
}
}
}

78
lib/_modifier-font.scss Normal file
View file

@ -0,0 +1,78 @@
/*
* Author: Sivan [sun.sivan@gmail.com]
* Description: define font stack classes.
*/
@import "variables";
@mixin hetiFontModifier {
// 定义无衬线字体为黑体
&-sans {
font-family: $font-family-hei;
}
// 定义衬线字体为宋体
&-serif {
font-family: $font-family-song;
}
// 定义传统字体
&-classic {
font-family: $font-family-song;
// 标题使用 800 字重
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: $font-weight-bolder;
}
// 标题引用使用楷体
h1,
h2,
h3,
h4,
h5,
h6,
blockquote,
cite,
q {
font-family: $font-family-kai;
}
// 说明文字角标表头使用黑体
figcaption,
caption,
sup,
sub,
th {
font-family: $font-family-hei;
}
}
// 定义超大号字
&-x-large {
font-size: $font-size-x-large;
line-height: $line-height-size-x-large;
}
// 定义大号字
&-large {
font-size: $font-size-large;
line-height: $line-height-size-large;
}
// 定义小号字
&-small {
font-size: $font-size-small;
line-height: $line-height-size-small;
}
// 定义超小号字
&-x-small {
font-size: $font-size-x-small;
line-height: $line-height-size-x-small;
}
}

79
lib/_modifier-layout.scss Normal file
View file

@ -0,0 +1,79 @@
/*
* Author: Sivan [sun.sivan@gmail.com]
* Description: define vertical layout classes.
*/
@import "variables";
@mixin hetiLayoutModifier {
// 定义垂直布局
&-vertical {
max-width: none;
max-height: $line-length;
writing-mode: vertical-rl;
letter-spacing: 0.125em;
}
// 定义古文诗词样式
&-poetry,
&-ancient {
font-family: $font-family-song;
h1,
h2,
h3 {
font-family: $font-family-song;
font-weight: $font-weight-bolder;
text-align: center;
// 标题内元信息不应占据空间影响标题文字居中
#{$root-selector}-meta {
display: block;
font-weight: 400;
@media screen and (min-width: 640px) {
@include hang();
display: inline;
margin-block-start: 4px;
margin-inline-start: 8px;
}
}
}
#{$root-selector}-verse {
text-align: center;
text-indent: 0;
}
// 古文文言文默认首行缩进
p {
text-indent: $text-indent-length;
}
}
// 定义行间注样式
// @todo: 类名太长了得简化一下
&-interlinear-annotation {
// 首行缩进且行间距大无需添加段落边距
p {
margin-block-start: 0;
margin-block-end: 0;
line-height: $line-height-expanded-ultra;
text-indent: $text-indent-length;
}
// 着重号不应影响行间距经测试最小可用行高为 1.7
em {
-webkit-text-emphasis: filled circle;
-webkit-text-emphasis-position: under;
font-weight: $font-weight-normal;
@include non-cjk-block {
-webkit-text-emphasis: none;
}
}
// ruby 不应影响行间距经测试最小可用行高为 2
//ruby {}
}
}

30
lib/_table.scss Normal file
View file

@ -0,0 +1,30 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: 表格样式
*/
@import "variables";
@mixin hetiTable {
table {
box-sizing: border-box;
table-layout: fixed;
border-collapse: collapse;
border: 1px solid #ccc;
margin-block-start: $std-block-unit / 2;
margin-block-end: $std-block-unit;
margin-inline-start: auto;
margin-inline-end: auto;
}
th,
td {
border: 1px solid #ccc;
padding: 8px 16px;
}
caption {
caption-side: bottom;
font-size: $font-size-small;
line-height: $line-height-size-small;
}
}

108
lib/_variables.scss Normal file
View file

@ -0,0 +1,108 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
* Description: define variables, alias etc.
*/
// 定义赫蹏根 class
$root-selector: '.heti' !default;
// 字体 Fonts
/// 字体栈 Font Stacks
$_font-stack-hei: "Pingfang SC", "Pingfang TC", "Heiti SC", "Heiti TC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei" !default;
$_font-stack-song: 'Noto Serif','Noto Serif CJK SC', 'Noto Serif CJK', 'Source Han Serif SC', Source Han Serif, source-han-serif-sc, "Songti SC", "Songti TC", STSong, SimSun !default;
$_font-stack-kai: "Kaiti SC", STKaiti !default;
$_font-stack-sans: "Helvetica Neue", Helvetica, Arial !default;
$_font-stack-serif: "Times New Roman", Times !default;
$_font-stack-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier !default;
$_font-stack-symbol: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
/// 字体族 Font Families
$font-family-hei: $_font-stack-sans, $_font-stack-hei, sans-serif, $_font-stack-symbol !default;
$font-family-song: $_font-stack-serif, $_font-stack-song, serif, $_font-stack-symbol !default;
$font-family-kai: $_font-stack-serif, $_font-stack-kai, serif, $_font-stack-symbol !default;
$font-family-mono: $_font-stack-mono, monospace, $_font-stack-symbol !default;
/// 字重 Font Weights
$font-weight-bolder: 800 !default;
$font-weight-bold: 600 !default;
$font-weight-normal: 400 !default;
$font-weight-lighter: 200 !default;
/// 字号 Font Sizes
$font-size-normal: 16px !default;
$font-size-x-large: 20px !default;
$font-size-large: 18px !default;
$font-size-small: 14px !default;
$font-size-x-small: 12px !default;
$font-size-h1: 32px !default;
$font-size-h2: 24px !default;
$font-size-h3: 20px !default;
$font-size-h4: 18px !default;
$font-size-h5: 16px !default;
$font-size-h6: 14px !default;
// 行宽
$line-length: 42em !default;
// 行高 Line Heights
$line-height-normal: 1.5 !default;
//$line-height-expanded: 1.875 !default;
$line-height-expanded-ultra: 2.25 !default;
//$line-height-condensed: 1.25 !default;
//$line-height-condensed-ultra: 1 !default;
$line-height-size-normal: $font-size-normal * $line-height-normal !default;
$line-height-size-large: $line-height-size-normal !default;
$line-height-size-x-large: $font-size-x-large * $line-height-normal !default;
$line-height-size-small: $line-height-size-normal !default;
$line-height-size-x-small: 18px !default;
$line-height-size-h1: 48px !default;
$line-height-size-h2: 36px !default;
$line-height-size-h3: 36px !default;
$line-height-size-h4: 24px !default;
$line-height-size-h5: 24px !default;
$line-height-size-h6: 24px !default;
// 标准网格单位变量 Standard Length
// 垂直方向标准单位 = 标准行高
// 水平方向标准单位 = 标准字号
$std-block-unit: $line-height-size-normal !default;
$std-inline-unit: $font-size-normal !default;
// 示例缩进单位 = 二倍文字宽度
$text-indent-length: 2em !default;
// 开发用配置项 Develop Configs
/// 预设重置方案 "reset" | "normalize"
/// reset假定 Eric Meyer CSS Reset 或其它流行的 Reset
/// normalize指定为 normalize.css
$_css-reset-scheme: "reset";
// Mix-in: Clear float
@mixin clear-float {
&::before,
&::after {
content: "";
display: table;
}
&::after {
clear: both;
}
}
// Mix-in: Include Non-cjk styles
@mixin non-cjk-block {
&:not(:lang(zh)):not(:lang(ja)):not(:lang(kr)),
&:not(:lang(zh)) {
@content;
}
}
// Mix-in: Hang Punctuation Mark
@mixin hang {
position: absolute;
line-height: inherit;
}

41
lib/heti.scss Normal file
View file

@ -0,0 +1,41 @@
/**
* Author: Sivan [sun.sivan@gmail.com]
*/
@import "variables";
@import "base";
@import "heading";
@import "list";
@import "table";
@import "inline";
@import "modifier-layout";
@import "modifier-font";
@import "helper-block";
@import "helper-inline";
#{$root-selector} {
// 中文每行展示文字CPL建议在 30~50 之间默认 42
max-width: $line-length;
// 默认字体大小为 16px行高 1.5
font-size: $font-size-normal;
font-weight: $font-weight-normal;
line-height: $line-height-normal;
// 自动在中西文间加 1/4 空格暂无浏览器支持
//text-spacing: ideograph-alpha;
// 引入各模块
@include hetiBase();
@include hetiHeading();
@include hetiList();
@include hetiTable();
@include hetiInline();
// 定义所有状态样式 .heti 并列使用
@include hetiLayoutModifier();
@include hetiFontModifier();
// 定义所有内嵌样式仅在 .heti 内使用有效
@include hetiBlockHelperClasses();
@include hetiInlineHelperClasses();
}

4074
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

36
package.json Normal file
View file

@ -0,0 +1,36 @@
{
"name": "heti",
"version": "0.1.0",
"description": "赫蹏",
"main": "index.scss",
"directories": {
"lib": "lib"
},
"scripts": {
"start": "node-sass -w --output-style=compressed index.scss dist/heti.css",
"build": "node-sass index.scss dist/heti.css --output-style=compressed",
"deploy": "gh-pages -d dist",
"test": "npx stylelint --config .stylelintrc 'lib/**/*.scss'"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sivan/heti.git"
},
"keywords": [
"typography"
],
"author": "Sivan <sun.sivan@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/sivan/heti/issues"
},
"homepage": "https://github.com/sivan/heti#readme",
"devDependencies": {
"gh-pages": "^2.2.0",
"node-sass": "^4.13.1",
"stylelint": "^13.0.0",
"stylelint-config-recommended-scss": "^4.1.0",
"stylelint-config-standard": "^19.0.0",
"stylelint-scss": "^3.13.0"
}
}