Skip to content

Commit 692b51a

Browse files
committed
release v1.1.4 | optimization: remove image mask and data-style. feature: suport getContrast API. bugfix: fix the inheritance algorithm of text color
1 parent 6b6ee86 commit 692b51a

File tree

12 files changed

+216
-76
lines changed

12 files changed

+216
-76
lines changed

dist/darkmode.js

Lines changed: 66 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/darkmode.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cn/API.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ Darkmode.init({
5959
Darkmode.convertBg(document.body.querySelectorAll('*'));
6060
```
6161

62+
### `Darkmode.getContrast(color1, color2) => contrast`
63+
64+
- `color1` <string> 要计算颜色对比度的颜色1,支持css颜色格式。
65+
- `color2` <string> 要计算颜色对比度的颜色2,支持css颜色格式。
66+
- return `contrast` <number> 颜色对比度,取值范围为`[1, 21]`
67+
68+
获取两个颜色的对比度。
69+
70+
```javascript
71+
Darkmode.getContrast('#fff', '#000'); // return 21
72+
```
73+
6274
### `Darkmode.extend(pluginList)`
6375

6476
- `pluginList` <Plugin Array> 要挂载的插件列表。

doc/cn/principle.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,10 @@
1414
## 处理 2:带背景图片节点
1515

1616
* 图片上方存在文本,则给图片底层补 Light Mode **原背景色**(保证图片上方文本的可读性)
17-
* 图片上层加**蒙层**(降低背景亮度)
1817
* `SVG` 节点跳过(`SVG` 存在动画状态,存在不可控因素)
1918

2019
> **注意:**
2120
> - 背景图处理规则影响子节点,直到子节点出现可见背景颜色(透明度需 ≥ 0.05)恢复为*处理 1*
22-
> - 使用 `border-image` 设置背景图节点暂无法在图片上层添加**蒙层**
23-
24-
## 处理 3:`IMG` 图片节点
25-
26-
* 添加 `filter` 降低图片亮度
27-
28-
> **注意:**
29-
> - 添加 `filter` 后会创建新的 [Stacking Contexts](https://philipwalton.com/articles/what-no-one-told-you-about-z-index/),影响节点层级(副作用)
3021
3122
## 算法思路:颜色转换
3223

doc/en/API.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ Processing background. When `delayBgJudge = true` in the configuration item, you
5959
Darkmode.convertBg(document.body.querySelectorAll('*'));
6060
```
6161

62+
### `Darkmode.getContrast(color1, color2) => contrast`
63+
64+
- `color1` <string> The color used to calculate color contrast, supports CSS color format.
65+
- `color2` <string> The color used to calculate color contrast, supports CSS color format.
66+
- return `contrast` <number> The color contrast, its value range is `[1, 21]`.
67+
68+
Get the contrast between two colors.
69+
70+
```javascript
71+
Darkmode.getContrast('#fff', '#000'); // return 21
72+
```
73+
6274
### `Darkmode.extend(pluginList)`
6375

6476
- `pluginList` <Plugin Array> List of plugins to mount.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mp-darkmode",
3-
"version": "1.1.3",
3+
"version": "1.1.4",
44
"description": "微信公众平台图文 Dark Mode 转换算法",
55
"main": "dist/darkmode.min.js",
66
"dependencies": {

src/darkmode.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,7 @@ export function updateStyle(node, styles) {
200200
cssUtils.addCss(sdk.convert(node, styles ? Object.keys(styles).map(key => [key, styles[key]]) : undefined, true), false);
201201
cssUtils.writeStyle();
202202
};
203+
204+
export function getContrast(color1, color2) {
205+
return sdk.getContrast(color1, color2);
206+
}

src/modules/constant.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
export const MEDIA_QUERY = '(prefers-color-scheme: dark)'; // Dark Mode的CSS媒体查询
77

88
export const CLASS_PREFIX = 'js_darkmode__'; // Dark Mode class前缀
9+
export const DM_CLASSNAME_REGEXP = new RegExp(`${CLASS_PREFIX}\\d+`);
910

1011
export const HTML_CLASS = 'data_color_scheme_dark'; // 强制设置暗黑模式时给html加的class
1112

1213
const RANDOM = `${new Date() * 1}${Math.round(Math.random() * 10)}`; // 生成个随机数,格式为时间戳+随机数
13-
export const COLORATTR = `data-darkmode-color-${RANDOM}`;
14-
export const BGCOLORATTR = `data-darkmode-bgcolor-${RANDOM}`;
15-
export const ORIGINAL_COLORATTR = `data-darkmode-original-color-${RANDOM}`;
16-
export const ORIGINAL_BGCOLORATTR = `data-darkmode-original-bgcolor-${RANDOM}`;
14+
export const COLORATTR = `data-darkmode-color-${RANDOM}`; // dm color,即算法生成的新色值,单个
15+
export const BGCOLORATTR = `data-darkmode-bgcolor-${RANDOM}`; // dm bg-color,即算法生成的新色值,有多个,用BG_COLOR_DELIMITER分割
16+
export const ORIGINAL_COLORATTR = `data-darkmode-original-color-${RANDOM}`; // lm color,即原色值,单个
17+
export const ORIGINAL_BGCOLORATTR = `data-darkmode-original-bgcolor-${RANDOM}`; // lm bg-color,即原色值,有多个,用BG_COLOR_DELIMITER分割
1718
export const BGIMAGEATTR = `data-darkmode-bgimage-${RANDOM}`;
19+
export const BG_COLOR_DELIMITER = '|';
1820

1921
export const DEFAULT_LIGHT_TEXTCOLOR = '#191919'; // 非Dark Mode下字体颜色
2022
export const DEFAULT_LIGHT_BGCOLOR = '#fff'; // 非Dark Mode下背景颜色
2123
export const DEFAULT_DARK_TEXTCOLOR = '#a3a3a3'; // 前景色:rgba(255,255,255,0.6) 背景色:#191919
2224
export const DEFAULT_DARK_BGCOLOR = '#191919'; // Dark Mode下背景颜色
23-
export const GRAY_MASK_COLOR = 'rgba(0,0,0,0.2)'; // 灰色蒙层色值
2425

2526
export const WHITE_LIKE_COLOR_BRIGHTNESS = 250; // 接近白色的感知亮度阈值
2627
export const MAX_LIMIT_BGCOLOR_BRIGHTNESS = 190;
@@ -37,3 +38,6 @@ export const PAGE_HEIGHT = (window.getInnerHeight && window.getInnerHeight())
3738
export const TABLE_NAME = ['TABLE', 'TR', 'TD', 'TH']; // 支持bgcolor属性的table标签列表
3839

3940
export const IMPORTANT_REGEXP = / !important$/; // !important
41+
42+
export const SEMICOLON_PLACEHOLDER = '<$#_SEMICOLON_#$>'; // 分号占位符
43+
export const SEMICOLON_PLACEHOLDER_REGEXP = /<\$#_SEMICOLON_#\$>/g;

src/modules/sdk.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ ColorName.transparent = [255, 255, 255, 0]; // 支持透明,暂定用白色透
1717

1818
import {
1919
CLASS_PREFIX,
20+
DM_CLASSNAME_REGEXP,
2021

2122
COLORATTR,
2223
BGCOLORATTR,
2324
ORIGINAL_COLORATTR,
2425
ORIGINAL_BGCOLORATTR,
2526
BGIMAGEATTR,
26-
27-
GRAY_MASK_COLOR,
27+
BG_COLOR_DELIMITER,
2828

2929
WHITE_LIKE_COLOR_BRIGHTNESS,
3030
MIN_LIMIT_OFFSET_BRIGHTNESS,
@@ -36,7 +36,10 @@ import {
3636

3737
TABLE_NAME,
3838

39-
IMPORTANT_REGEXP
39+
IMPORTANT_REGEXP,
40+
41+
SEMICOLON_PLACEHOLDER,
42+
SEMICOLON_PLACEHOLDER_REGEXP
4043
} from './constant';
4144

4245
// Darkmode配置
@@ -56,11 +59,6 @@ import {
5659
hasTableClass
5760
} from './domUtils';
5861

59-
const SEMICOLON_PLACEHOLDER = '<$#_SEMICOLON_#$>'; // 分号占位符
60-
const SEMICOLON_PLACEHOLDER_REGEXP = /<\$#_SEMICOLON_#\$>/g;
61-
62-
const DM_CLASSNAME_REGEXP = new RegExp(`${CLASS_PREFIX}\\d+`);
63-
6462
const colorNameReg = new RegExp(Object.keys(ColorName).map(colorName => `\\b${colorName}\\b`).join('|'), 'ig'); // 生成正则表达式来匹配这些colorName
6563
const colorReg = /\brgba?\([^)]+\)/i;
6664
const colorRegGlobal = /\brgba?\([^)]+\)/ig;
@@ -71,7 +69,6 @@ const parseColor = (value, parseTransparent) => removeImportant(value).replace(c
7169
const color = ColorName[match.toLowerCase()];
7270
return `${color.length > 3 ? 'rgba' : 'rgb'}(${color.toString()})`;
7371
});
74-
const BG_COLOR_DELIMITER = '|';
7572

7673
// 计算mix颜色
7774
const mixColor = colors => {
@@ -114,6 +111,25 @@ const adjustBrightnessByLimit = (limitBright, rgb) => {
114111
return Color.rgb(newTextR, newTextG, newTextB);
115112
};
116113

114+
// 计算亮度,用作对比度计算
115+
const getLuminanace = rgb => {
116+
const srgb = rgb.map(val => {
117+
val /= 255;
118+
return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
119+
});
120+
return srgb[0] * 0.2126 + srgb[1] * 0.7152 + srgb[2] * 0.0722;
121+
};
122+
123+
// 计算对比度 https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-procedure
124+
const getContrast = (rgb1, rgb2) => {
125+
const lum1 = getLuminanace(rgb1);
126+
const lum2 = getLuminanace(rgb2);
127+
128+
// 亮色 / 暗色
129+
if (lum1 < lum2) return (lum2 + 0.05) / (lum1 + 0.05);
130+
return (lum1 + 0.05) / (lum2 + 0.05);
131+
}
132+
117133
export default class SDK {
118134
_idx = 0; // 索引值
119135
_defaultDarkTextColorRgb = Color(config.defaultDarkTextColor).rgb().array();
@@ -228,11 +244,10 @@ export default class SDK {
228244
newColor = this._adjustBackgroundBrightness(color);
229245

230246
if (!options.hasInlineColor) {
231-
const parentTextColor = el[COLORATTR] || config.defaultLightTextColor;
232-
const parentBgColorStr = newColor || color;
247+
const parentTextColor = el[ORIGINAL_COLORATTR] || config.defaultLightTextColor;
233248
const ret = this._adjustBrightness(Color(parentTextColor), el, {
234249
isTextColor: true,
235-
parentElementBgColorStr: parentBgColorStr
250+
parentElementBgColorStr: newColor || color
236251
}, isUpdate);
237252
if (ret.newColor) {
238253
extStyle += cssUtils.genCssKV('color', ret.newColor);
@@ -366,7 +381,7 @@ export default class SDK {
366381
});
367382
}
368383

369-
if (nodeName === 'FONT' && !hasInlineColor) { // 如果是font标签且没有内联样式
384+
if (nodeName === 'FONT' && !hasInlineColor) { // 如果是font标签且没有内联文本颜色样式
370385
this._try(() => {
371386
const color = el.getAttribute('color'); // 获取color的色值
372387
if (color) { // 有色值,则当做内联样式来处理
@@ -485,13 +500,15 @@ export default class SDK {
485500

486501
// 对背景颜色和文字颜色做继承传递,用于文字亮度计算
487502
if (isBgColor || textColorIdx > 0) { // 不处理-webkit-text-stroke-color
488-
const attrName = isBgColor ? BGCOLORATTR : COLORATTR;
489-
const originalAttrName = isBgColor ? ORIGINAL_BGCOLORATTR : ORIGINAL_COLORATTR;
490503
const retColorStr = retColor ? retColor.toString() : match;
491504
replaceIndex === 0 && getChildrenAndIt(el).forEach(dom => {
492-
const originalAttrValue = dom[originalAttrName] || config.defaultLightBgColor;
493-
dom[attrName] = retColorStr;
494-
dom[originalAttrName] = originalAttrValue.split(BG_COLOR_DELIMITER).concat(match).join(BG_COLOR_DELIMITER);
505+
if (isBgColor) {
506+
dom[BGCOLORATTR] = retColorStr;
507+
dom[ORIGINAL_BGCOLORATTR] = (dom[ORIGINAL_BGCOLORATTR] || config.defaultLightBgColor).split(BG_COLOR_DELIMITER).concat(match).join(BG_COLOR_DELIMITER);
508+
} else {
509+
dom[COLORATTR] = retColorStr;
510+
dom[ORIGINAL_COLORATTR] = match;
511+
}
495512

496513
// 如果设置背景颜色,取消背景图片的影响
497514
if (isBgColor && Color(retColorStr).alpha() >= IGNORE_ALPHA && dom[BGIMAGEATTR]) {
@@ -501,7 +518,7 @@ export default class SDK {
501518
}
502519

503520
retColor && (cssChange = true);
504-
replaceIndex += 1;
521+
replaceIndex++;
505522
return retColor || match;
506523
}
507524
return match;
@@ -535,7 +552,6 @@ export default class SDK {
535552

536553
// background-image
537554
if (isBackgroundAttr) {
538-
newValue = `linear-gradient(${GRAY_MASK_COLOR}, ${GRAY_MASK_COLOR}),${matches}`;
539555
tmpCssKvStr = cssUtils.genCssKV(key, `${newValue},linear-gradient(${imgBgColor}, ${imgBgColor})`);
540556
if (elBackgroundPositionAttr) {
541557
newBackgroundPositionValue = `top left,${elBackgroundPositionAttr}`;
@@ -555,7 +571,7 @@ export default class SDK {
555571
} else {
556572
// border-image元素,如果当前元素没有背景颜色,补背景颜色
557573
if (!hasInlineBackground) {
558-
tmpCssKvStr = cssUtils.genCssKV('background-image', `linear-gradient(${GRAY_MASK_COLOR}, ${GRAY_MASK_COLOR}),linear-gradient(${imgBgColor}, ${imgBgColor})`);
574+
tmpCssKvStr = cssUtils.genCssKV('background-image', `linear-gradient(${imgBgColor}, ${imgBgColor})`);
559575
if (dmBgClassName) { // 如果是文字底图,则直接加样式
560576
bgCss += cssUtils.genCss(dmBgClassName, tmpCssKvStr);
561577
} else { // 否则背景图入栈
@@ -568,7 +584,7 @@ export default class SDK {
568584

569585
// 没有设置自定义字体颜色,则使用非 Dark Mode 下默认字体颜色
570586
if (!hasInlineColor) {
571-
const textColor = mixColor((el[ORIGINAL_COLORATTR] || config.defaultLightTextColor).split(BG_COLOR_DELIMITER));
587+
const textColor = el[ORIGINAL_COLORATTR] || config.defaultLightTextColor;
572588
cssKV += cssUtils.genCssKV('color', textColor);
573589
getChildrenAndIt(el).forEach(dom => {
574590
dom[COLORATTR] = textColor;
@@ -592,8 +608,6 @@ export default class SDK {
592608
}));
593609

594610
if (cssKV) { // 有处理过或者是背景图片就加class以及css
595-
// TODO: 备份应该写到插件里
596-
el.setAttribute('data-style', styles.cssText); // 备份内联样式到data-style里,供编辑器做反处理
597611
if (!dmClassName) {
598612
dmClassName = `${CLASS_PREFIX}${this._idx++}`;
599613
el.classList.add(dmClassName);
@@ -618,4 +632,8 @@ export default class SDK {
618632

619633
return css;
620634
}
635+
636+
getContrast(color1, color2) {
637+
return getContrast(Color(color1).rgb().array(), Color(color2).rgb().array());
638+
}
621639
};

test/darkmode_online.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)