乐趣区

关于html5:纯CSS免费让网站拥有暗黑模式切换功能

前言

暗黑模式 这个概念最早起源于 MacOS 零碎Mojave,提供 浅色主题 深色主题 两种皮肤供用户抉择,深色主题 就是咱们常说的 暗黑模式 。为了眼睛衰弱,笔者在手机、平板和电脑上都抉择了 暗黑模式

随着苹果官网逐步要求各大零碎平台都得适配 暗黑模式 ,所以笔者也摸索出一种应该是 市面上最低老本 网站暗黑模式适配计划

意识笔者的敌人应该都晓得笔者是一位重度 CSS 发烧友,当然这次也是应用纯 CSS 实现这个计划。是的,不加任何一段 JS,侧面再次证实 CSS 的弱小。

思路

思路很简略,应用一个按钮来回切换主题款式。按钮未选中则切换到 浅色主题 ,按钮选中则切换到 深色主题 。可用:checked+打辅助实现这个工作。

  • :checked:选项选中的表单元素
  • +:元素相邻的同胞元素

应用 <input> 模仿按钮,当按钮处于选中状态时触发 :checked,通过+ 带动前面相邻的网站主体 <div> 进入 暗黑模式 ,选中状态勾销时则退出 暗黑模式

<body>
    <input class="ios-switch" type="checkbox">
    <div class="main"> 网站主体 </div>
</body>

更多选择器的性能和分类请回看笔者这篇文章《可能是最全最易记的 CSS 选择器分类大法》。

切换按钮

打算设计一个好看的按钮,可是没有特地思路,就关上 iPhone,把设置里的 切换按钮 用纯 CSS 实现一番。

尺寸和色彩都是与 iPhone 切换按钮 统一。思路是应用 <input> 模仿按钮,申明 appearance:none 将其默认外观抹去,应用 ::before 模仿背景区域,应用 ::after 模仿点击区域,在触发 :checked 后增加一些小动画进行润饰,近乎完满地实现了iPhone 切换按钮

<input class="ios-switch" type="checkbox">
.btn {
    border-radius: 31px;
    width: 102px;
    height: 62px;
    background-color: #e9e9eb;
}
.ios-switch {
    position: relative;
    appearance: none;
    cursor: pointer;
    transition: all 100ms;
    @extend .btn;
    &::before {
        position: absolute;
        content: "";
        transition: all 300ms cubic-bezier(.45, 1, .4, 1);
        @extend .btn;
    }
    &::after {
        position: absolute;
        left: 4px;
        top: 4px;
        border-radius: 27px;
        width: 54px;
        height: 54px;
        background-color: #fff;
        box-shadow: 1px 1px 5px rgba(#000, .3);
        content: "";
        transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
    }
    &:checked {
        background-color: #5eb662;
        &::before {transform: scale(0);
        }
        &::after {transform: translateX(40px);
        }
    }
}

请戳这里查看在线演示与源码。

暗黑模式

还记得 4 月 4 日那次全网开启悼念模式吗?笔者发表了一篇文章《一行代码全站进入悼念模式》,奇妙地应用 filter 这个弱小的 CSS 属性。

html {filter:grayscale(1);
}

真的是一行代码,本次也不例外,一行代码全站进入暗黑模式

html {filter: invert(1) hue-rotate(180deg);
}

filter的兼容性不差,各位同学可放心使用,还有一些细节中央需注意,本文就不反复解说了,详情可回看《一行代码全站进入悼念模式》。

filter是一个十分神奇的属性,能将 Photoshop 一些根底的滤镜成果利用到网站上。笔者平时十分喜爱应用 filter,在笔者的 CodePen 上有许多纯 CSS 特效都应用了filter,仔细的同学可能会发现笔者特地喜爱应用hue-rotate() 这个函数联合 CSS 变量 动静生成过渡色彩,详情请回看《妙用 CSS 变量,让你的 CSS 变得更心动》。

本次的 暗黑模式 应用到两个滤镜函数:invert()hue-rotate()

  • invert():反相,反向输入图像着色,值为 0% 则无变动,值为 0~100% 则是线性乘子成果,值为 100% 则齐全反转
  • hue-rotate():色相旋转,削弱图像着色,解决非黑白的色彩,值为 0deg 则无变动,值为 0~360deg 则逐步削弱,值超过 360deg 则相当绕 N 圈再计算残余的值

invert()简略了解就是 黑变白,白变黑,黑白颠倒 hue-rotate() 简略了解就是 冲淡色彩 。为了确保主题色调不会扭转,将色相旋转申明为180deg 比拟正当。

根据上述剖析的思路,当按钮处于选中状态时应用 + 连带前面的同胞元素也进入选中状态。若同胞元素无背景色需申明background-color:#fff,否则无奈让滤镜成果起效,为了让这个同胞元素在应用滤镜成果时过渡得更天然,申明transition:all 300ms

.ios-switch {
    ...
    &:checked {
        ...
        & + .main {filter: invert(1) hue-rotate(180deg);
        }
    }
}
.main {
    background-color: #fff;
    transition: all 300ms;
}

在 CodePen 上为了更好地展现成果,就应用 <iframe> 引入咱们最爱的掘金社区,收费为其减少 暗黑模式 切换性能????。同时在排版上做了大量批改,请戳这里查看在线演示与源码。

优化

仔细的同学可能会发现,怎么图片都变成照 B 超的感觉了。

依照设计准则来说,换肤只针对组件,像一些媒体类型的元素,例如背景、图片、视频等,都是不能间接解决的,需放弃其原样。既然 暗黑模式 是应用了滤镜的反相和色相旋转实现,那么对这些媒体元素再次应用滤镜的反相和色相旋转就能还原了。应用过 Photoshop 滤镜 的同学应该会更分明。

img,
video {filter: invert(1) hue-rotate(180deg);
}

还有一个问题,背景怎么解决?家喻户晓,背景是应用 background 系列属性进行申明的,因而无奈通过特定的选择器进行标注。然而,可换种思路解决,就是给有背景的元素加上一个特定类名,将其蕴含到上述规定里即可。

通过 Chrome DevTools 查看 掘金社区 的网站源码,发现这些头像、缩略图和展现图都有一些特定类名,将其特定类名增加到规定里。

img,
video,
.avatar,
.image,
.thumb {filter: invert(1) hue-rotate(180deg);
}

在通用网站里,这个类名可自行定义,最可行的办法就是定义一个特定类名.exclude。不应用滤镜成果的元素通通加上.exclude

.exclude {filter: invert(1) hue-rotate(180deg);
}

革新

上述为了不便演示代码,在 CodePen Demo 里应用 <iframe> 引入咱们最爱的 掘金社区 。因为无奈对<iframe> 进行款式申明,所以转移到掘金社区上,通过 Chrome DevTools 间接革新。

Chrome 浏览器 里按 F12Cmd+Alt+I关上Chrome DevTools,剖析网站的 HTML 构造。

<body>
    <div id="__nuxt">...</div>
</body>

<body> 里插入 切换按钮

<body>
    <input class="ios-switch" type="checkbox">
    <div id="__nuxt">...</div>
</body>

把以下 SCSS 代码 转换成 CSS 代码 插入到 <head> 新建的 <style> 里。举荐一个在线 SASS 转 CSS 的工具网站,复制以下代码到网站里间接转换,实现后再贴到 <style> 里。

.btn {
    border-radius: 31px;
    width: 102px;
    height: 62px;
    background-color: #e9e9eb;
}
.ios-switch {
    position: relative;
    appearance: none;
    cursor: pointer;
    transition: all 100ms;
    @extend .btn;
    &::before {
        position: absolute;
        content: "";
        transition: all 300ms cubic-bezier(.45, 1, .4, 1);
        @extend .btn;
    }
    &::after {
        position: absolute;
        left: 4px;
        top: 4px;
        border-radius: 27px;
        width: 54px;
        height: 54px;
        background-color: #fff;
        box-shadow: 1px 1px 5px rgba(#000, .3);
        content: "";
        transition: all 300ms cubic-bezier(.4, .4, .25, 1.35);
    }
    &:checked {
        background-color: #5eb662;
        &::before {transform: scale(0);
        }
        &::after {transform: translateX(40px);
        }
        & + #__nuxt {filter: invert(1) hue-rotate(180deg);
            img,
            video,
            .avatar,
            .image,
            .thumb {filter: invert(1) hue-rotate(180deg);
            }
        }
    }
}
#__nuxt {
    background-color: #fff;
    transition: all 300ms;
}

实现后发现 切换按钮 没有呈现,可通过 position:absolute 将其相对定位到想要显示的地位。

.ios-switch {
    position: absolute;
    right: 0;
    top: 0;
    z-index: 99999;
    outline: none;
}

或在 <div id="__nuxt"> 里任意中央创立一个 <label>,通过申明<input class="ios-switch" id="toggle" hidden><label for="toggle">相互绑定,将 <input> 的触发区域转移到 <label> 上。具体怎么实现,可参照笔者这个纯 CSS 标签导航栏实现。

若感觉解说有点乱,可稍作整顿,三步实现上述操作。

关上掘金社区网站

F12Cmd+Alt+I关上Chrome DevTools

<head> 里插入<style>

为了不便复制粘贴,笔者将上述剖析得出的 CSS 代码进行压缩。

<style>.btn,.ios-switch::before,.ios-switch{border-radius:31px;width:102px;height:62px;background-color:#e9e9eb;}.ios-switch{position:relative;appearance:none;cursor:pointer;transition:all 100ms;}.ios-switch::before{position:absolute;content:"";transition:all 300ms cubic-bezier(0.45,1,0.4,1);}.ios-switch::after{position:absolute;left:4px;top:4px;border-radius:27px;width:54px;height:54px;background-color:#fff;box-shadow:1px 1px 5px rgba(0,0,0,0.3);content:"";transition:all 300ms cubic-bezier(0.4,0.4,0.25,1.35);}.ios-switch:checked{background-color:#5eb662;}.ios-switch:checked::before{transform:scale(0);}.ios-switch:checked::after{transform:translateX(40px);}.ios-switch:checked + #__nuxt{filter:invert(1) hue-rotate(180deg);}.ios-switch:checked + #__nuxt img,.ios-switch:checked + #__nuxt video,.ios-switch:checked + #__nuxt .avatar,.ios-switch:checked + #__nuxt .image,.ios-switch:checked + #__nuxt .thumb{filter:invert(1) hue-rotate(180deg);}#__nuxt{background-color:#fff;transition:all 300ms;}.ios-switch{position:absolute;right:0;top:0;z-index:99999;outline:none;}</style>

<body> 里插入<input>

<body>
    <input class="ios-switch" type="checkbox">
    <div id="__nuxt">...</div>
</body>

就这样,一个纯 CSS 的实现计划就能让网站霎时领有 暗黑模式 切换性能,有没有又对 CSS 另眼相看了。

总结

整个 纯 CSS 实现计划 围绕着 :checked+filter三个点进行,缺一不可。看似简略,若不是罕用 CSS 做特效也很难设想出区区三个点打辅助也能实现一个这么弱小的性能。

<body>
    <input class="ios-switch" type="checkbox">
    <div class="main"> 网站主体 </div>
</body>
.ios-switch {
    ...
    &:checked {
        ...
        & + .main {filter: invert(1) hue-rotate(180deg);
            img,
            video,
            .exclude {filter: invert(1) hue-rotate(180deg);
            }
        }
    }
}
.main {
    background-color: #fff;
    transition: all 300ms;
}

相比于 CSS+JS 实现计划 而言,无需保护一整套 暗黑模式 款式代码,无需操作 DOM,没有了平常简单的操作。除非要做一整套高度定制的 暗黑模式 才需一个CSS+JS 实现计划,否则用该计划即可。

本计划具备以下特点。

  • 纯 CSS 实现,简略高效,逼格更高
  • 简直没有保护老本,疾速迭代
  • 充分利用滤镜成果,兼容性好

试试不妨,实现了感觉成果不错就连忙找你老板加薪去????,哈哈!

对于笔者而言,CSS 是一门天马行空的语言,说它简略也行说它艰难也行。若你很喜爱 CSS,想理解更多纯 CSS 特效,可回看笔者往期的文章,也可浏览笔者集体官网的纯 CSS 特效专辑,保障满足你的眼球。

  • 灵活运用 CSS 开发技巧:4000+点赞量,110k+浏览量
  • 妙用 CSS 变量,让你的 CSS 变得更心动:500+点赞量,13k+浏览量

最初,笔者很好奇咱们最爱的 掘金社区 会不会驳回这种纯 CSS 实现的换肤计划,各位掘友怎么看呢?

结语

❤️关注 + 点赞 + 珍藏 + 评论 + 转发❤️,原创不易,激励笔者创作更多高质量文章

关注公众号IQ 前端,一个专一于 CSS/JS 开发技巧的前端公众号,更多前端小干货等着你喔

退出移动版