暗黑模式图片适配研究
暗黑模式图片适配研究

暗黑模式图片适配研究

暗黑模式图片适配研究

正常、暗黑模式切换时,如何保证图片展示效果最佳

Since dark mode starts to be of fashion on main cellphones, the dark mode for page is coming too.

如何动态检测暗黑模式的切换呢?

1. window.matchMedia 可以满足需求

if (window.matchMedia) {
    const matches: MediaQueryList = window.matchMedia(
        '(prefers-color-scheme: dark)'
    )
    const func = (obj: MediaQueryListEvent): void => {
        const evt: EventTarget =
            obj.currentTarget ||
            obj.target ||
            obj.srcElement ||
            new EventTarget()
        const mql: MediaQueryList = <MediaQueryList>evt
        document.body.classList[mql.matches ? 'add' : 'remove'](
            'codernote_dark'
        )
    }
    if (matches) {
        if (matches.addEventListener) {
            matches.addEventListener('change', func)
        } else if (matches.addListener) {
            matches.addListener(func)
        } else {
            matches.onchange = func
        }
    }
} else {
    console.log('detection is not supported')
}

2. 使用 css 有媒体查询来满足

// first put normal style here
// ...
body {
    color: darkblue;
}
@media screen and (prefers-color-scheme: dark) {
    // write some darkmode style here
    // ..
    body {
        color: darkgreen;
    }
}

3. 如果是不同模式下图片也要跟着变呢?

分两种情况
  1. 图片在编写 css 时是确定的(这种情况好处理)
  2. 图片是动态返回的
1. 针对图片是确定的,如普通模式是白底黑色线条,这种通过上述的 css 媒体查询可以做到,示例如下
.some-img-helder {
    width: 100px;
    height: 100px;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    background-image: url('./point_to_nomal_img_path.png');
}
// 暗黑模式匹配
@media screen and (prefers-color-scheme: dark) {
    .some-img-helder {
        background-image: url('./point_to_dark_mode_img_path.png');
    }
}

这里为什么用 background-image来做,而不是 img,
主要考虑是 background 方式不影响 dom ready,能让页面结构尽快展示出来

如果用图片是动态返回的,那么可以使用第二种方式来实现,当然已知确定图片的也可以使用这种方式:

2.图片是动态返回的
.img_wrap {
    img {
        width: 100px;
        height: 100px;
    }
    .normal {
        display: inherit;
    }
    .dark {
        display: none;
    }
}
@media screen and (prefers-color-scheme: dark) {
    .img_wrap {
        .normal {
            display: none;
        }
        .dark {
            display: inherit;
        }
    }
}
<div class="img_wrap">
    <img class="normal" src="point_to_nomal_img_path.png" />
    <img class="dark" src="point_to_dark_mode_img_path.png" />
</div>

这样做是基于以下原因:

  1. 相同规则的 css 后边的优先级更高
  2. 虽然两张图片都设置了 src, 但 display: none 不会加载图片,和只有一张图片效果一致
  3. 媒体查询只有在满足条件时,内部的规则才会生效
  4. 第二种方式同样适用于自行切换主题的场景,实现方式为把 img_wrap上追加一个主题样式名,然后在后面补充主题样式包裹下的样式即可,示例如下:
.img_wrap {
    color: black;
    background-color: white;
    img {
        width: 100px;
        height: 100px;
        background-repeat: no-repeat;
        background-size: 100%;
        background-position: center;
    }
}
.img_wrap.yellow_theme {
    color: white;
    background-color: lightgoldenrodyellow;
}
<div class="img_wrap yellow_theme">
    <div>文本内容</div>
    <img src="动态返回图片" />
</div>