Skip to content

Commit

Permalink
release v1.1.4 | optimization: remove image mask and data-style. feat…
Browse files Browse the repository at this point in the history
…ure: suport getContrast API. bugfix: fix the inheritance algorithm of text color
  • Loading branch information
JaminQ committed Oct 21, 2024
1 parent 6b6ee86 commit 692b51a
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 76 deletions.
101 changes: 66 additions & 35 deletions dist/darkmode.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/darkmode.min.js

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions doc/cn/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ Darkmode.init({
Darkmode.convertBg(document.body.querySelectorAll('*'));
```

### `Darkmode.getContrast(color1, color2) => contrast`

- `color1` <string> 要计算颜色对比度的颜色1,支持css颜色格式。
- `color2` <string> 要计算颜色对比度的颜色2,支持css颜色格式。
- return `contrast` <number> 颜色对比度,取值范围为`[1, 21]`

获取两个颜色的对比度。

```javascript
Darkmode.getContrast('#fff', '#000'); // return 21
```

### `Darkmode.extend(pluginList)`

- `pluginList` <Plugin Array> 要挂载的插件列表。
Expand Down
9 changes: 0 additions & 9 deletions doc/cn/principle.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,10 @@
## 处理 2:带背景图片节点

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

> **注意:**
> - 背景图处理规则影响子节点,直到子节点出现可见背景颜色(透明度需 ≥ 0.05)恢复为*处理 1*
> - 使用 `border-image` 设置背景图节点暂无法在图片上层添加**蒙层**
## 处理 3:`IMG` 图片节点

* 添加 `filter` 降低图片亮度

> **注意:**
> - 添加 `filter` 后会创建新的 [Stacking Contexts](https://philipwalton.com/articles/what-no-one-told-you-about-z-index/),影响节点层级(副作用)
## 算法思路:颜色转换

Expand Down
12 changes: 12 additions & 0 deletions doc/en/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ Processing background. When `delayBgJudge = true` in the configuration item, you
Darkmode.convertBg(document.body.querySelectorAll('*'));
```

### `Darkmode.getContrast(color1, color2) => contrast`

- `color1` <string> The color used to calculate color contrast, supports CSS color format.
- `color2` <string> The color used to calculate color contrast, supports CSS color format.
- return `contrast` <number> The color contrast, its value range is `[1, 21]`.

Get the contrast between two colors.

```javascript
Darkmode.getContrast('#fff', '#000'); // return 21
```

### `Darkmode.extend(pluginList)`

- `pluginList` <Plugin Array> List of plugins to mount.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mp-darkmode",
"version": "1.1.3",
"version": "1.1.4",
"description": "微信公众平台图文 Dark Mode 转换算法",
"main": "dist/darkmode.min.js",
"dependencies": {
Expand Down
4 changes: 4 additions & 0 deletions src/darkmode.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,7 @@ export function updateStyle(node, styles) {
cssUtils.addCss(sdk.convert(node, styles ? Object.keys(styles).map(key => [key, styles[key]]) : undefined, true), false);
cssUtils.writeStyle();
};

export function getContrast(color1, color2) {
return sdk.getContrast(color1, color2);
}
14 changes: 9 additions & 5 deletions src/modules/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@
export const MEDIA_QUERY = '(prefers-color-scheme: dark)'; // Dark Mode的CSS媒体查询

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

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

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

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

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

export const IMPORTANT_REGEXP = / !important$/; // !important

export const SEMICOLON_PLACEHOLDER = '<$#_SEMICOLON_#$>'; // 分号占位符
export const SEMICOLON_PLACEHOLDER_REGEXP = /<\$#_SEMICOLON_#\$>/g;
66 changes: 42 additions & 24 deletions src/modules/sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ ColorName.transparent = [255, 255, 255, 0]; // 支持透明,暂定用白色透

import {
CLASS_PREFIX,
DM_CLASSNAME_REGEXP,

COLORATTR,
BGCOLORATTR,
ORIGINAL_COLORATTR,
ORIGINAL_BGCOLORATTR,
BGIMAGEATTR,

GRAY_MASK_COLOR,
BG_COLOR_DELIMITER,

WHITE_LIKE_COLOR_BRIGHTNESS,
MIN_LIMIT_OFFSET_BRIGHTNESS,
Expand All @@ -36,7 +36,10 @@ import {

TABLE_NAME,

IMPORTANT_REGEXP
IMPORTANT_REGEXP,

SEMICOLON_PLACEHOLDER,
SEMICOLON_PLACEHOLDER_REGEXP
} from './constant';

// Darkmode配置
Expand All @@ -56,11 +59,6 @@ import {
hasTableClass
} from './domUtils';

const SEMICOLON_PLACEHOLDER = '<$#_SEMICOLON_#$>'; // 分号占位符
const SEMICOLON_PLACEHOLDER_REGEXP = /<\$#_SEMICOLON_#\$>/g;

const DM_CLASSNAME_REGEXP = new RegExp(`${CLASS_PREFIX}\\d+`);

const colorNameReg = new RegExp(Object.keys(ColorName).map(colorName => `\\b${colorName}\\b`).join('|'), 'ig'); // 生成正则表达式来匹配这些colorName
const colorReg = /\brgba?\([^)]+\)/i;
const colorRegGlobal = /\brgba?\([^)]+\)/ig;
Expand All @@ -71,7 +69,6 @@ const parseColor = (value, parseTransparent) => removeImportant(value).replace(c
const color = ColorName[match.toLowerCase()];
return `${color.length > 3 ? 'rgba' : 'rgb'}(${color.toString()})`;
});
const BG_COLOR_DELIMITER = '|';

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

// 计算亮度,用作对比度计算
const getLuminanace = rgb => {
const srgb = rgb.map(val => {
val /= 255;
return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
});
return srgb[0] * 0.2126 + srgb[1] * 0.7152 + srgb[2] * 0.0722;
};

// 计算对比度 https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-procedure
const getContrast = (rgb1, rgb2) => {
const lum1 = getLuminanace(rgb1);
const lum2 = getLuminanace(rgb2);

// 亮色 / 暗色
if (lum1 < lum2) return (lum2 + 0.05) / (lum1 + 0.05);
return (lum1 + 0.05) / (lum2 + 0.05);
}

export default class SDK {
_idx = 0; // 索引值
_defaultDarkTextColorRgb = Color(config.defaultDarkTextColor).rgb().array();
Expand Down Expand Up @@ -228,11 +244,10 @@ export default class SDK {
newColor = this._adjustBackgroundBrightness(color);

if (!options.hasInlineColor) {
const parentTextColor = el[COLORATTR] || config.defaultLightTextColor;
const parentBgColorStr = newColor || color;
const parentTextColor = el[ORIGINAL_COLORATTR] || config.defaultLightTextColor;
const ret = this._adjustBrightness(Color(parentTextColor), el, {
isTextColor: true,
parentElementBgColorStr: parentBgColorStr
parentElementBgColorStr: newColor || color
}, isUpdate);
if (ret.newColor) {
extStyle += cssUtils.genCssKV('color', ret.newColor);
Expand Down Expand Up @@ -366,7 +381,7 @@ export default class SDK {
});
}

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

// 对背景颜色和文字颜色做继承传递,用于文字亮度计算
if (isBgColor || textColorIdx > 0) { // 不处理-webkit-text-stroke-color
const attrName = isBgColor ? BGCOLORATTR : COLORATTR;
const originalAttrName = isBgColor ? ORIGINAL_BGCOLORATTR : ORIGINAL_COLORATTR;
const retColorStr = retColor ? retColor.toString() : match;
replaceIndex === 0 && getChildrenAndIt(el).forEach(dom => {
const originalAttrValue = dom[originalAttrName] || config.defaultLightBgColor;
dom[attrName] = retColorStr;
dom[originalAttrName] = originalAttrValue.split(BG_COLOR_DELIMITER).concat(match).join(BG_COLOR_DELIMITER);
if (isBgColor) {
dom[BGCOLORATTR] = retColorStr;
dom[ORIGINAL_BGCOLORATTR] = (dom[ORIGINAL_BGCOLORATTR] || config.defaultLightBgColor).split(BG_COLOR_DELIMITER).concat(match).join(BG_COLOR_DELIMITER);
} else {
dom[COLORATTR] = retColorStr;
dom[ORIGINAL_COLORATTR] = match;
}

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

retColor && (cssChange = true);
replaceIndex += 1;
replaceIndex++;
return retColor || match;
}
return match;
Expand Down Expand Up @@ -535,7 +552,6 @@ export default class SDK {

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

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

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

return css;
}

getContrast(color1, color2) {
return getContrast(Color(color1).rgb().array(), Color(color2).rgb().array());
}
};
2 changes: 1 addition & 1 deletion test/darkmode_online.js

Large diffs are not rendered by default.

Loading

0 comments on commit 692b51a

Please sign in to comment.