惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
Recent Announcements
Recent Announcements
H
Help Net Security
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
有赞技术团队
有赞技术团队
小众软件
小众软件
Last Week in AI
Last Week in AI
U
Unit 42
Google DeepMind News
Google DeepMind News
博客园 - 司徒正美
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale
云风的 BLOG
云风的 BLOG
V
V2EX
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
博客园 - 三生石上(FineUI控件)
阮一峰的网络日志
阮一峰的网络日志
爱范儿
爱范儿

张鑫旭-鑫空间-鑫生活

1分钟速度了解text-align match-parent声明 « 张鑫旭-鑫空间-鑫生活 光标的形状也能设置了,就是CSS caret-shape属性 « 张鑫旭-鑫空间-鑫生活 pretext与文字四面环绕效果的实现 « 张鑫旭-鑫空间-鑫生活 JSON.rawJSON方法的作用是什么? « 张鑫旭-鑫空间-鑫生活 如何使用CSS判断鼠标从哪个方向进入元素? « 张鑫旭-鑫空间-鑫生活 借助mediabunny纯JS实现视频水印、剪裁、合成等功能 « 张鑫旭-鑫空间-鑫生活 务必谨慎使用JS WeakRef弱引用 « 张鑫旭-鑫空间-鑫生活 CSS六边形头像的实现与蜂巢布局 « 张鑫旭-鑫空间-鑫生活 CSS corner-shape与背景底纹技术 « 张鑫旭-鑫空间-鑫生活 浅学WebTransport API:下一代Web双向通信技术 « 张鑫旭-鑫空间-鑫生活 HTML dialog元素新支持了closedBy属性 « 张鑫旭-鑫空间-鑫生活 HTML interestfor属性与悬停popover交互效果 « 张鑫旭-鑫空间-鑫生活 CSS3模拟window7炫酷界面效果展示 « 张鑫旭-鑫空间-鑫生活 图片旋转+剪裁js插件(兼容各浏览器) « 张鑫旭-鑫空间-鑫生活 纯js无图片无外链CSS图片幻灯片播放插件 « 张鑫旭-鑫空间-鑫生活 CSS border三角、圆角图形生成技术简介 « 张鑫旭-鑫空间-鑫生活 CSS “渐进增强”在web制作中常见应用举例 « 张鑫旭-鑫空间-鑫生活 让IE6/IE7/IE8浏览器支持CSS3属性 « 张鑫旭-鑫空间-鑫生活 jQuery – 高亮动态显示页面HTML代码插件 « 张鑫旭-鑫空间-鑫生活 翻译 – 逐渐消失的Flash网站 « 张鑫旭-鑫空间-鑫生活 CSS reset的重新审视 – 避免样式重置 « 张鑫旭-鑫空间-鑫生活 新浪微博插入话题后部分文字选中的js实现 « 张鑫旭-鑫空间-鑫生活 JavaScript实现http地址自动检测并添加URL链接 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变背景(gradient)效果 « 张鑫旭-鑫空间-鑫生活 CSS content内容生成技术以及应用 « 张鑫旭-鑫空间-鑫生活 CSS gradient渐变之webkit核心浏览器下的使用 « 张鑫旭-鑫空间-鑫生活 CSS渐变之CSS3 gradient在Firefox3.6下的使用 « 张鑫旭-鑫空间-鑫生活 区分IE8/IE7/IE6及其他浏览器-CSS “\9″hack « 张鑫旭-鑫空间-鑫生活 CSS实现跨浏览器兼容性的盒阴影效果 « 张鑫旭-鑫空间-鑫生活 CSS3&HTML5各浏览器支持情况一览表 « 张鑫旭-鑫空间-鑫生活
密码强度效果最佳实现一定是HTML meter元素 « 张鑫旭-鑫空间...
张鑫旭,zhangxinxu · 2021-11-14 · via 张鑫旭-鑫空间-鑫生活

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=10188 鑫空间-鑫生活
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

注册时候密码输入框显示密码强度是个很常见的交互效果,例如下面找的效果截图:

密码强度截图

这种效果实现最好的方法一定是使用 HTML <meter> 元素,无论是跟随强度的 UI 色值变化,还是弱中强的文字提示,都是可以使用纯 CSS 实现,无需 JS 去控制 DOM 的色值与尺寸变化。

一、先看实现效果

下面两张图就是最终在浏览器中实现的效果。

Chrome 浏览器下:

密码提示强弱

Safari 浏览器下:

Safari浏览器下截图

眼见为实,您可以狠狠的点击这里:meter元素与密码强度实现demo

接下来一步一步带大家了解具体的实现过程,先从了解 <meter> 元素开始。

二、meter 元素基本特性与效果

单词 meter 直译意思是“计量器”,“计量表”,因此,在 Web 中,任何与丈量相关,同时需要分阶段提示的场景都非常使用使用 <meter> 元素。

例如汽车油箱剩余油量,降雨量,风度,温度,游戏中人物角色的血量等。

先看下面一段代码:

生命值:<meter min="0" max="100" low="30" high="60" optimum="80" value="20"></meter>
生命值:<meter min="0" max="100" low="30" high="60" optimum="80" value="50"></meter>
生命值:<meter min="0" max="100" low="30" high="60" optimum="80" value="70"></meter>

在现代浏览器下就会有如下图所示的 UI 效果。

meter基本效果

下面则是实时渲染效果,大家可以看下自己当前访问设备中的效果:

生命值:

生命值:

生命值:

其中出现了 6 个 HTML 属性,正好涵盖了 <meter> 元素所有常用属性。

属性简介

  • minmax 属性表示数值范围,默认是 0-1,也就是如果 min 属性如果不设置,则认为是 0,max 属性不设置则认为是 1。
  • value 表示当前的值,默认是 0。
  • lowhigh 是比较特殊的 HTML 属性,目前仅出现在 <meter> 元素上,表示警戒值,其中 low 表示过低警戒值,high 表示过高警戒值。

    但是,大家务必注意,过低还是过高是否需要警戒还需要一个属性进行判定,那就是 optimum 属性。

  • optimum 属性表示最佳值,用来决定过低和过高值属于正常还是异常,这个属性很重要,也是 <meter> 元素学习的难点。

optimum 属性

optimum 属性的作用表现描述如下:

  • 如果 optimum 属性值在 lowhigh 之间,则说明 lowhigh 都是警戒值,只有在这个区间范围的值才是正常的,因此,最终的色值状态只会有两个,即橙色警戒和绿色正常。

    代码示意:

    生命值:<meter max="100" low="30" high="60" optimum="50" value="20"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="50" value="50"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="50" value="70"></meter>

    效果如下图所示,最多只会出现两种颜色。

    两种色值

  • 如果 optimum 属性值比 low 还要小,则说明 low 并不是警戒线,反而是推荐线,也就是越小反而越高,此时,low-high 之间的范围就属于警戒,而超过 high 的值就属于危险了。

    于是,最终 <meter> 元素可以有 3 段色值状态,HTML 代码示意:

    生命值:<meter max="100" low="30" high="60" optimum="20" value="20"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="20" value="50"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="20" value="70"></meter>

    meter 三段色值演示

  • 如果 optimum 属性值比 high 还要大,也会出现 3 段色值状态,此时,大于 high 的值会被认为是正常的,因此表现为绿色,这个效果,就是一开始那个例子所演示的那个效果,代码和截图效果是这样的:
    生命值:<meter max="100" low="30" high="60" optimum="80" value="20"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="80" value="50"></meter>
    生命值:<meter max="100" low="30" high="60" optimum="80" value="70"></meter>

    meter基本效果

回到本文这里,由于密码强度越强越好,因此,很显然,需要设置 optimum 属性值比 high 还要大。

但是,我们需要的是下图这样的效果,需要明显分段的,而浏览器默认的 <meter> 元素效果就是个色条,不符合产品需求,那有没有什么办法自定义 UI 呢?

目标密码强度效果

二、meter 元素的样式自定义

在现代浏览器下,<meter> 元素提供了若干伪元素,可以让我们对 <meter> 元素进行样式自定义。

其中,Chrome 浏览器和 Safari 浏览器可以使用的伪元素非常丰富,Firefox 浏览器相对少一些。

这里,主要以 Chrome 浏览器示意。

所有可以设置 <meter> 元素的选择器包括下面这些:

  • meter 元素自身选择器;
  • ::-webkit-meter-inner-element {}
  • ::-webkit-meter-bar {} 灰色背景条。
  • ::-webkit-meter-even-less-good-value {} 红色。
  • ::-webkit-meter-optimum-value {} 橙色。
  • ::-webkit-meter-suboptimum-value {} 绿色。

各个伪元素所对应的 DOM 层级结构如下图所示:

伪元素结构

使用字符图形表示是这样的:

meter
  |-- ::-webkit-meter-inner-element
    |-- ::-webkit-meter-bar
      |-- ::-webkit-meter-even-less-good-value  -|
      |-- ::-webkit-meter-suboptimum-value      -|--> 只会同时出现1个
      |-- ::-webkit-meter-optimum-value         -|

所以,我们就可以使用上面的伪元素实现我们想要的 UI 效果了。

然而,事情并没有预想的那么简单。

  1. 密码强度如何确定?
  2. 表示 3 个颜色的伪元素最多只会出现 1 个,而我们的目标效果却是 3 色同时显示,另外,默认的色值是连续的,而需要的效果是分段的,该怎么实现呢?
  3. 强度色块下面还有“弱 中 强”的文字提示,这个布局效果又该如何实现呢?

关于这些实现难点,我们一个一个来看下,其中不乏一些有创意的实现技巧。

//zxx: 如果你看到这段文字,说明你现在访问是不是原文站点,更好的阅读体验在这里:https://www.zhangxinxu.com/wordpress/?p=10188(作者张鑫旭)

四、密码强度的计算

密码强度的计算直接使用开源的公认的算法就可以了,比方说 zxcvbn:https://github.com/dropbox/zxcvbn

使用也相当简单,引入然后执行,示意:

<script src="https://cdn.bootcdn.net/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
<script>
    let objResult = zxcvbn('your password');
</script>

其中 objResult 包含下面这些属性:

{
    guesses: Number
    guesses_log10: Number
    score: Number (0-4)
    crack_times_seconds: Object (不同运算力下的破解时间,数值展示)
    crack_times_display: Object (不同运算力下的破解时间,字符描述展示)
    sequence: Array 验证序列
    feedback: 反馈与建议
    calc_time: zxcvbn 计算此密码强度花费的时间,单位是毫秒 ms
}

截图示意:
运行结果

其中,与密码强度直接相关的是:guesses、guesses_log10 和 score。

其中,score 范围是 0-4,数值越大,密码越安全,虽然也能解决强度的判断,但是体现在 <meter> 元素上就没有了丰度的 value 变化,视觉效果也不咋地。

因此,在本文所描述的场景下,我们使用 guesses_log10 作为我们的强度判断值。

根据我的测试,guesses_log10 的值在 12 以上,密码强度就已经很 Strong 了,考虑到弱中强三种状态的色条范围是三等分的,因此,最终的 <meter> 元素的高低值如下所示:

<meter min="0" max="12" low="4" high="8" optimum="10"></meter>

相关 JS 代码则是这样子的:

meter.value = zxcvbn('paddworld').guesses_log10;

剩下的视觉表现的工作全部都交给 CSS 好了。

五、最终样式实现的细节

1. 背景条的样式

首先,我们确定个尺寸,假设 长度是 120px,高度是 12px:

::-webkit-meter-bar {
    width: 120px;
    height: 12px;
}

浏览器默认的边框效果是不需要的,然后为了兼容性,需要统一背景色,于是有:

::-webkit-meter-bar {
    width: 120px; height: 12px;
    border: 0;
    background: #eee;
}

Firefox 浏览器可以使用 ::-moz-meter-bar 伪元素设置。

2. 色带的实现

浏览器默认的状态都是纯色,从左纯到右,想要变成一个一个的色带,不少人的想法会是叠加,也就是几个 <meter> 元素叠加在一起,其实不需要这么麻烦的,我们使用 CSS 渐变模拟就好了。

例如,进入橙色状态的时候,把前 1/3 部分改成红色(原来是橙色),这样,当状态条从红色变成橙色的时候,就像是无缝添加的,而不是突然替换,绿色这部分也是类似的。

代码示意:

::-webkit-meter-even-less-good-value {
    background: red;
}
::-webkit-meter-suboptimum-value {
    background: linear-gradient(to right, red 40px, orange 0);
}
::-webkit-meter-optimum-value {
    background: linear-gradient(to right, red 40px, orange 0 80px, green 0);
}

::-webkit-meter-optimum-value 伪元素举例,浏览器默认状态下,这个伪元素是纯绿色,这里使用 CSS 渐变重新实现之后,就是 红-橙-绿 三段,很好地模拟了三态强度效果。

最终的效果可以参见下面的 GIF 录屏。

三色模拟效果

3. 中间镂空分隔

上面的 GIF 效果,各个色块是紧密相连的,但是最终需要的效果是彼此之间有间隙,这个该如何实现呢?

方法其实挺多的,我这里选择使用遮罩实现,在色块的容器元素上绘制一个镂空渐变作为遮罩图像:

::-webkit-meter-bar {
    -webkit-mask: linear-gradient(to right, 
      red 39px, 
      transparent 0 41px, 
      orange 0 79px, 
      transparent 0 81px, 
      green 0
    );
}

此时,效果就会是这样:

带间隙的强度效果

4. 文字左中右对齐实现

接下来就是“弱中强”三个文字的效果实现了,如下图:
目标密码强度效果

有人会想到使用一个 <span> 元素和 <meter> 元素包在一起再重定位,这个虽然也能实现,但是 HTML 就啰嗦了,以后也不太好维护。

实际上,直接使用 <meter> 元素就可以实现,方法就是 ::after 伪元素。

meter::after {
    content: '弱中强';
}

效果如下截图所示:

文字显示效果

不过有几个问题,首先,文字占据的尺寸空间,影响了和输入框的垂直对齐,这个好办,设置为绝对定位就可以了:

meter::after {
    content: '弱中强';
    position: absolute;
}

但是,“弱中强”三个字要分别在 3 个颜色片段的中间,这个对齐该怎么实现呢?

我们可以让伪元素宽度充满 <meter> 元素,给文字中间增加空格、末尾增加一串长长的连续英文字符实现:

meter {
    position: relative;    
}
meter::after {
    content: '弱 中 强 aaaaaaaaaaaaaaaaaaaaaa';
    position: absolute;
    left: 0; right: 0;
    /* 两端对齐 */
    text-align: justify;
    /* 隐藏 aaaaaaaaaaaaaaaaaaaaaa */
    height: 20px;
    line-height: 20px;
    overflow: hidden;
}

为什么后面需要一段莫名其妙的 'aaaaaaaaaaaaaaaaaaaaaa' 呢,因为两端对齐效果的实现,处理字符之间有空格,还需要内容超过1行,而连续英文字符默认是不会换行的,因此会作为整体在第 2 行显示,从而让第一行的 “弱中强”三个字两端对齐。

效果如下所示:

文字对齐效果

我猜,有人会说,不对啊,“弱”和“强”两个字需要在色块的中间啊,不是边上。

对,边上是不对的,所以,需要修改下 lefttop 位置微调下(中文字符占据宽度是 1em):

meter {
    position: relative;    
}
meter::after {
    content: '弱 中 强 aaaaaaaaaaaaaaaaaaaaaa';
    position: absolute;
    left: calc(20px - .5em);
    right: calc(20px - .5em);
    /* 两端对齐 */
    text-align: justify;
    /* 隐藏 aaaaaaaaaaaaaaaaaaaaaa */
    height: 20px;
    line-height: 20px;
    overflow: hidden;
}

效果为:

对齐效果

接下来,就是文字变色的实现了。

5. 不同文字不同颜色实现

同一段文字显示不同颜色的技术其实很多很多年前(10年前)就介绍过了,详见:“CSS3下的渐变文字效果实现”,在《CSS新世界》这本书中也有介绍。

这里使用 background-clip:text加 linear-gradient 渐变背景实现的。

meter::after {
    -webkit-text-fill-color: transparent;
    background-image: linear-gradient(to right, 
        red 39px, 
        transparent 0 41px, 
        orange 0 79px, 
        transparent 0 81px, 
        green 0
    );
    -webkit-background-clip: text;
}

再加上一些尺寸和位置的细节调整,于是就有了最终的效果:

最终渐变文字效果

6. Safari 浏览器

好,Chrome 浏览器搞定了,看看 Safari 浏览器下的效果,结果……呃……:

Safari下效果

本以为是safari浏览器不支持,后来研究了一下,发现原来只需要设置外面的meter 元素边框尺寸为0或none就可以触发伪元素重定义了,也就是:

meter {
    border: 0;
}

所有的效果就会出现,如下所示:

密码效果Safari

7. 使用 CSS 变量优化

最后把上面所有的实现整合一下,同时使用css变量优化一下渐变以及尺寸。就会得到如下所示的终极代码:

meter {
     --size: 60px;
     --gradient: linear-gradient(to right, red calc(var(--size) - 1px), transparent 0 calc(var(--size) + 1px), orange 0 calc(var(--size) * 2 - 1px), transparent 0 calc(var(--size) * 2 + 1px), green 0);
    width: calc(3 * var(--size));
    border: 0; /* Safari */
    position: relative;
}
meter::after {
    content: '弱 中 强 aaaaaaaaaaaaaaaaaaaaaa';
    position: absolute;
    font-size: 14px;
    line-height: 20px;
    height: 20px;
    overflow: hidden;
    left: calc(var(--size) / 2 - .5em);
    right: calc(var(--size) / 2 - .5em);
    text-align: justify;
    -webkit-text-fill-color: transparent;
    background: var(--gradient) calc(.5em - var(--size) / 2) / calc(3 * var(--size));
    -webkit-background-clip: text;
}
::-webkit-meter-bar {
    height: 12px;
    width: calc(3 * var(--size));
    border: 0;
    background: #eee;
    -webkit-mask: var(--gradient);
    mask: var(--gradient);
}
::-webkit-meter-even-less-good-value {
    background: red;
}
::-webkit-meter-suboptimum-value {
    background: linear-gradient(to right, red var(--size), orange 0);
}
::-webkit-meter-optimum-value {
    background: linear-gradient(to right, red var(--size), orange 0 calc(2 * var(--size)), green 0);
}

如果想要改变强度测量条元素的宽度,只需要修改CSS自定义属性 --size 的值就可以了。

眼见为实,效果体验

您可以狠狠地点击这里:meter元素自定义效果纯享版demo

进行效果体验。

至此,所有相关实现的介绍都结束了。

六、总结

当然,正如一开始所提到的,<meter> 元素不仅可以用来表示密码强度。在 Web 中,所有与丈量、测量相关的场景,都可以考虑使用这一个 HTML 元素。

有人可能会纠结 IE 浏览器的问题。

毕竟 <meter> 元素的兼容性是这样子的。

meter 元素的兼容性

一种方法是使用polyfill,我这里找了个项目:https://github.com/fisker/meter-polyfill

这个项目的作者可能是国人,因为头像看起来非常熟悉,不过这个 polyfill 项目我自己没试过,所以质量如何并不清楚。

从我自己的角度讲,如果我是遇到这样的场景,我会说服产品直接放弃 IE浏览器,就不用搞什么所谓的密码强度了,本来这种密码强度就是锦上添花的功能,没有的话,也不影响功能。

况且现在 IE 浏览器占比其实非常低了,3%都不到,我不知道其他公司产品怎样的,以及我们开发产品总是要面向未来的,你不能说我当下还有一些 IE 浏览器用户,你就放弃了未来,想想看,现在项目中还有兼容 IE8 浏览器的代码,是不是想吐。

当然,如果产品是个直溜子说服不通,以为工程师就是想偷懒。

那我觉得专门给IE做一个特殊的处理,其实也不需要多大的成本,回头哪天 IE 嗝屁了直接移除就好。

好,巴拉巴拉,断断续续,没想到讲了这么多,这篇文章篇幅又铺出来了,所以就不再啰嗦了。

行文不易,欢迎分享,感谢转发!

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=10188

(本篇完)