月度归档: 2017 年 3 月

  • 选择合适的字体区分 1Il、0Oo

    为了能够清晰区分 1Il 0Oo、准确识别相似字符,测试了 70+ 种 Windows 系统下使用的字体,得到 3 种能清晰区分 1Il 0Oo 的字体,效果如下:

    # 字体 1, i, l, 零和欧, 全角
    1 Consolas 1iIl 0Oo0Oo ø
    2 Tahoma 1iIl 0Oo0Oo ø
    3 Verdana 1iIl 0Oo0Oo ø

     

    在这 3 种字体中,Verdana 和 Tahoma 效果最好,Consolas 次之,在 Excel 中也常用到 Tahoma。

    最终采取的方案是:

    .input {
        font-family: Verdana, Tahoma, Consolas, monospace;
    }
    

    全部对比效果如下:

    # 字体 1, i, l, 零和欧, 全角
    1 Consolas 1iIl 0Oo0Oo ø
    2 Tahoma 1iIl 0Oo0Oo ø
    3 Verdana 1iIl 0Oo0Oo ø
    4 ‘Angsana New’ 1iIl 0Oo0Oo ø
    5 Arial 1iIl 0Oo0Oo ø
    6 ‘Arial Black’ 1iIl 0Oo0Oo ø
    7 Basemic 1iIl 0Oo0Oo ø
    8 Batang 1iIl 0Oo0Oo ø
    9 ‘Book Antiqua’ 1iIl 0Oo0Oo ø
    10 ‘Browallia New’ 1iIl 0Oo0Oo ø
    11 Calibri 1iIl 0Oo0Oo ø
    12 Cambria 1iIl 0Oo0Oo ø
    13 Candara 1iIl 0Oo0Oo ø
    14 Century 1iIl 0Oo0Oo ø
    15 ‘Comic Sans MS’ 1iIl 0Oo0Oo ø
    16 Constantia 1iIl 0Oo0Oo ø
    17 Corbel 1iIl 0Oo0Oo ø
    18 ‘Cordia New’ 1iIl 0Oo0Oo ø
    19 Courier 1iIl 0Oo0Oo ø
    20 ‘Courier New’ 1iIl 0Oo0Oo ø
    21 DilleniaUPC 1iIl 0Oo0Oo ø
    22 Dotum 1iIl 0Oo0Oo ø
    23 Garamond 1iIl 0Oo0Oo ø
    24 Geneva 1iIl 0Oo0Oo ø
    25 Georgia 1iIl 0Oo0Oo ø
    26 Gulim 1iIl 0Oo0Oo ø
    27 GungSuh 1iIl 0Oo0Oo ø
    28 Impact 1iIl 0Oo0Oo ø
    29 JasmineUPC 1iIl 0Oo0Oo ø
    30 ‘Lucida Console’ 1iIl 0Oo0Oo ø
    31 ‘Lucida Sans Unicode’ 1iIl 0Oo0Oo ø
    32 ‘Malgun Gothic’ 1iIl 0Oo0Oo ø
    33 Mangal 1iIl 0Oo0Oo ø
    34 Marlett 1iIl 0Oo0Oo ø
    35 Meiryo 1iIl 0Oo0Oo ø
    36 ‘Microsoft JhengHei’ 1iIl 0Oo0Oo ø
    37 MingLiu 1iIl 0Oo0Oo ø
    38 MingLiU_HKSCS 1iIl 0Oo0Oo ø
    39 monospace 1iIl 0Oo0Oo ø
    40 Modern 1iIl 0Oo0Oo ø
    41 ‘MS Gothic’ 1iIl 0Oo0Oo ø
    42 ‘MS Mincho’ 1iIl 0Oo0Oo ø
    43 ‘MS PGothic’ 1iIl 0Oo0Oo ø
    44 ‘MS PMincho’ 1iIl 0Oo0Oo ø
    45 ‘MS Sans Serif’ 1iIl 0Oo0Oo ø
    46 ‘MS Serif’ 1iIl 0Oo0Oo ø
    47 ‘Palatino Linotype’ 1iIl 0Oo0Oo ø
    48 PMingliU 1iIl 0Oo0Oo ø
    49 PMingLiU-ExtB 1iIl 0Oo0Oo ø
    50 serif 1iIl 0Oo0Oo ø
    51 Symbol 1iIl 0Oo0Oo ø
    52 Times 1iIl 0Oo0Oo ø
    53 ‘Times New Roman’ 1iIl 0Oo0Oo ø
    54 ‘Trebuchet MS’ 1iIl 0Oo0Oo ø
    55 Wingdings 1iIl 0Oo0Oo ø
    56 ‘Yu Gothic’ 1iIl 0Oo0Oo ø
    57 ‘Yu Mincho’ 1iIl 0Oo0Oo ø
    58 方正舒体 1iIl 0Oo0Oo ø
    59 方正姚体 1iIl 0Oo0Oo ø
    60 仿宋 1iIl 0Oo0Oo ø
    61 黑体 1iIl 0Oo0Oo ø
    62 华文彩云 1iIl 0Oo0Oo ø
    63 华文仿宋 1iIl 0Oo0Oo ø
    64 华文行楷 1iIl 0Oo0Oo ø
    65 华文琥珀 1iIl 0Oo0Oo ø
    66 华文楷体 1iIl 0Oo0Oo ø
    67 华文隶书 1iIl 0Oo0Oo ø
    68 华文宋体 1iIl 0Oo0Oo ø
    69 华文细黑 1iIl 0Oo0Oo ø
    70 华文新魏 1iIl 0Oo0Oo ø
    71 华文中宋 1iIl 0Oo0Oo ø
    72 楷体 1iIl 0Oo0Oo ø
    73 隶书 1iIl 0Oo0Oo ø
    74 宋体 1iIl 0Oo0Oo ø
    75 宋体-ExtB 1iIl 0Oo0Oo ø
    76 微软雅黑 1iIl 0Oo0Oo ø
    77 新宋体 1iIl 0Oo0Oo ø
    78 幼圆 1iIl 0Oo0Oo ø
  • 在 Firefox 下 bootstrap-datetimepicker 报错

    日期插件 bootstrap-datetimepicker 在火狐下出现一条报错

    TypeError: (intermediate value).toString(…).split(…)[1] is undefined

    这条错误必然出现,难道没有在 Firefox 下进行测试。

    在 Firefox 下查看项目 demo (http://www.malot.fr/bootstrap-datetimepicker/demo.php)可以正常运行,但这个 demo.php 使用的是 2013-3-2 的 datetimepicker,github 项目(https://github.com/smalot/bootstrap-datetimepicker/releases)已经发布到 2017-3-3,这个最新的版本(以及最近的一些版本)在 Firefox 下测试不完善,计算 defaultTimeZone 时虽然没有出错,但给出的结果也不正确

    源代码如下,运行环境 Firefox 51.0.1(32位)

    this.defaultTimeZone = (new Date).toString().split('(')[1].slice(0, -1);
    this.timezone = options.timezone || this.defaultTimeZone;
    
    // 2.4.4 改进版本
    this.timezone = options.timezone || timeZoneAbbreviation();
    
    function timeZoneAbbreviation() {
        var abbreviation, date, formattedStr, i, len, matchedStrings, ref, str;
        date = (new Date()).toString();
        formattedStr = ((ref = date.split('(')[1]) != null ? ref.slice(0, -1) : 0) || date.split(' ');
        if (formattedStr instanceof Array) {
            matchedStrings = [];
            for (var i = 0, len = formattedStr.length; i < len; i++) {
                str = formattedStr[i];
                if ((abbreviation = (ref = str.match(/\b[A-Z]+\b/)) !== null) ? ref[0] : 0) {
                    matchedStrings.push(abbreviation);
                }
            }
            formattedStr = matchedStrings.pop();
        }
        return formattedStr;
    }
    

    出错原因是 Firefox 下 Date.prototype.toString 返回结果不包含 TimeZone 的文字描述。

    2.4.4 改进版本使用的 timeZoneAbbreviation 函数在 Firefox 下返回  true


    对 timeZoneAbbreviation 使用的三元表达式依次简化

    • ((abbreviation = (ref = str.match(/\b[A-Z]+\b/)) !== null) ? ref[0] : 0)
    • (abbreviation = (ref = str.match(/\b[A-Z]+\b/)) !== null)
    • (abbreviation = (xxx) !== null)
    • (abbreviation = xxx !== null)

    abbreviation 必然是布尔值,如果将 matchedStrings.push(abbreviation) 换成 matchedStrings.push(str) 更接近预期值。

    推荐使用文末的方案。


    • Firefox date toString 返回结果没有(中国标准时间)“, 因此 split('(')[1] 是 undefined

    • Chrome date toString 返回结果包含 “(中国标准时间)

    • IE/Edge date toString 返回结果包含 “(中国标准时间)

    解决方案

    将 date toString 最后一个空格之后的字符串作为 TimeZone。

    // this.defaultTimeZone = (new Date).toString().split('(')[1].slice(0, -1);
    this.defaultTimeZone = (new Date + '').split(' ').slice(-1)[0].replace(/\(|\)/g, '');
    this.timezone = options.timezone || this.defaultTimeZone;
    
  • CSS 压缩 initial、normal

    CSS 压缩在完成简单的字符替换,空白符压缩之后,还可以进一步进行特定 value 压缩。

    比如:

    /* 压缩前 */
    .main{margin:initial}
    
    /* 压缩后 */
    .main{margin:0px}
    
    /* 进一步压缩 */
    .main{margin:0}
    

    最后只需要占用一个字符就达到 initial 效果。

    css initial 是一个特殊值,用于设置一些复杂、容易混淆的、难记忆的初始值非常有效。

    /* 压缩前 */
    .main{background:initial}
    
    /* 压缩后 */
    .main{background:rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box}
    

    对于这种真实样式比 initial 更长的样式可以不用压缩。

    Chrome 下 css initial 对应真实值

    在多个浏览器遍历设置元素 css 样式为 initial,再通过 getComputedStyle 获取真实样式,将其中相同的部分归纳到 initial 集合中,提供给压缩脚本使用,即可完成 css 特定 value 压缩。

    同样可以压缩 css normal,使文件更小。

  • Webpack 打包 css,z-index 被重新计算

    使用 Webpack 打包 css 文件,发现打包后的 z-index 值跟源文件 z-index 不一致。

    如下图,左侧是源文件,右侧是打包后的文件:

    即使加上 !important,经过 OptimizeCssAssetsPlugin 调用 cssProcessor cssnano 处理之后也是 z-index: 2

    因此,很可能是 cssnano 进行了重新计算(cssnano 称为 rebase),而且这种计算是不够准确的

    因为打包后的文件有两处 z-index,这里是第二处,所以此处 z-index 是 2。

    cssnano 将 z-index rebase 归类为 unsafe,而不是 bug,只有在单个网页的 css 全部写入一个 css 文件,并且不通过 JavaScript 进行改动时是 safe。

    参考:http://cssnano.co/optimisations/zindex/

    项目中提取了公共的 css,已经对 layout 设置了很小的 z-index,因此受到 cssnano z-index rebase 的影响。

    cssnano 默认进行 z-index rebase。

    unsafe (potential bug) 优化项默认不开启应该比较友好。

    new OptimizeCssAssetsPlugin({
        cssProcessor: require('cssnano'),
        cssProcessorOptions: {
            discardComments: {removeAll: true},
            // 避免 cssnano 重新计算 z-index
            safe: true
        },
        canPrint: false
    })