分类
前端

空宽空格的问题与使用

今天有同学在群里提问:

“我的请求路径是这样的”
“路径上面自动多加东西了,好奇怪”

我的第一反应是“零宽空格”,然后该同学试着手动敲了一遍 url 地址,问题果然解决了。看起来,就是因为原来的 URL 里含有零宽空格,直接复制过来,虽然看起来没问题,但是在发起请求时,非标准字符被 encode 之后就出错了。

我们姑且不管为啥他的复制来源里会有零宽空格,聊一聊什么是“零宽空格”,以及“零宽空格”能干什么。

零宽空格定义

零宽空格是空格的一种空格,但是它的宽度为零,即不显示,所以看起来跟没有一样。我们可以在浏览器里启动开发者工具,然后切换到 Console 面板,输入以下代码:

> a = '\u200b'; // 即零宽空格
"" // 其实是有内容的,只是看不到
> a.length
1 // 长度为 1,说明有东西
> encodeURIComponent(a)
"%E2%80%8B" // encode 之后跟截图里一样,破案了

维基百科的解释:

零宽空格(zero-width space, ZWSP)是一种不可打印的Unicode字符,用于可能需要换行处。

它的用法:

在HTML页面中,零宽空格可以替代 <wbr>。但是在一些网页浏览器(例如 Internet Explorer的版本6或以下)不支持零宽空格的功能。

MDN 上没有零宽空格的定义,但是有 <wbr> 的内容。之前我也写过一篇文章:使用 <wbr> 解决长 URL 的换行问题,里面介绍了 HTML 换行算法,以及我选择 <wbr> 的思路,建议大家看一下。

用途一:在特定位置换行

比如一首古诗:

锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦。

我们有时候会希望:

  1. 在宽度足够的时候,放一行
  2. 如果宽度不够,就在标点符号处换行

这个时候,我们可以先设置这段文字 word-break: keep-all,避免在汉字后断句换行;然后在每个标点后面加上零宽空格,这样,一行的时候就不会看到奇怪的空格,而宽度不够的时候,又能根据 white-space 属性正常换行。

用途二:特殊标记

我厂有一个产品,要输出大量日志,包含大量数字。为方便阅读,需要给数字添加千位分隔符;为了方便复制,又希望剪贴板上的是纯数字,不要千位分隔符;但是如果本来就是千位分隔符的,比如在别的软件里格式化的数字,就原样复制,不需要去掉千位分隔符。

这个时候就可以用到零宽空格。我先找出来足够长的数字,然后添加千位分隔符,然后在两头加上零宽空格。这样在用户眼里,看到的是千位分隔过的数字;等他们复制的时候,我就检查两端的零宽空格,如果有的话,就复原数字;如果没有的话,就原样返回。

其它零宽字符

除了零宽空格之外,还有很多零宽字符,可以用来在页面中加入特殊标记,或者实现一些控制功能。大家如果发现 url encode 之后的内容和之前肉眼看到的不符,那么多半是存在零宽字符,可以试着干掉它们,多半问题就能解决。

分类
前端

Font Awesome 发布 Duotone 字体,支持双颜色

无意中看到 Font Awesome 发布了 Duotone 双色字体,感觉很神奇,我还不知道 WebFont 竟然支持多种颜色,于是赶紧看了看。

首先,这是旧闻,实际上,去年,也就是2019年7月30日,Font Awesome 就发布了 Duotone。

关于 Duotone 的介绍,大家可以看这篇官方博客:Introducing Duotone。借张图直观地展现 Duotone 的效果:

然后我就很好奇它们是怎么实现的,据我所知 WebFont 不支持多颜色。研究了半天,发现原来是这样:

2019年5月30日,Font Awesome 发布了 Font Awesome Kits(工具包)。Kits 是一个 JS,用来取代之前直接使用 CSS 引用字体的方式。这样做有几个好处:

  1. 根据字体使用情况按需加载
  2. 可以在客户端管理缓存,避免重复下载图标
  3. 可以自动更新图标,跟 Font Awesome 发布同步
  4. 可以帮助开发者处理可用性问题(关于这一点,GitHub 曾经发布过一篇博客,解释他们为什么要从 Icon Font 切换回 图标:https://github.blog/2016-02-22-delivering-octicons-with-svg/
  5. 可以更快应用新技术,比如 HTTP2,SRI 等

上面几个好处都是 Font Awesome 官博《Introducing Font Awesome Kits》中列出来的,还有一个好处它们没说:可以修改 DOM。Duofont 正是藉此实现双色的。打开开发者工具,我们可以看到,所有图标 <i class="fad fa-*"></i> 都被替换成了 inline <svg>,包含两个图层,自然可以通过 CSS 控制颜色等样式。

这个思路很有意思,布局也一步一步规划的很好,虽然不知道最终效果如何,但还是学到不少东西。

Font Awesome 提供免费版,我一直在用。付费版一年 $99,我觉得还是贵了点,所以一直没用,有需求的同学应该试一下。

分类
技术 招聘

代友招聘:珠海/远程 APISIX 前端

另外我们 OpenResty Inc. 也在持续招聘后端工程师/系统工程师,可选北京、深圳,也支持远程,详情请点击:OpenResty Inc. 招聘后端工程师


支流科技(APISIX)是一家开源基础软件创业公司,围绕着 Apache APISIX 构建下一代微服务,用户包括:中航信、海尔优家、腾讯云、空中云汇、NASA、欧盟数字工厂等 100 多家国内外知名公司和科研机构。

招聘中高级前端工程师,主要负责:

  1. 企业官网开发
  2. Dashboard 型产品开发

主要待遇:

  1. 全职工作,有五险一金
  2. 珠海上班最好,远程亦可
  3. 有(丰厚)期权

需要:

  1. 独立工作能力
  2. 掌握 Web 前端技术
  3. 掌握前端工具链
  4. 熟悉软件工程体系
  5. 至少熟练使用一个前端框架

加分项:

  1. 有开源项目参与经验
  2. 有长期博客
  3. 有远程工作经验
分类
技术 招聘

代友招聘:广州垂直领域知识付费

公司从 2018 年开始做相关的产品研发,到现在已经经历了两轮迭代,目前正在招聘新鲜血液,准备在 2020 年再搏一搏。

招聘链接在这里,长期招聘:https://www.zhipin.com/job_detail/?query=硅碳鼠&city=101280100&industry=&position=,目前主要招聘中级以上的前端和 PHP。

感兴趣的同学可以直接联系,或者找我推荐。

分类
js 技术

使用 JS 模拟元素被 click

需求来自于我厂的 QA 产品。在这个产品中,我需要在浏览器插件里模拟用的各种行为,比如:点击。

click 事件前后发生了什么

最初我觉得点击嘛,能有啥问题,就直接广播 click 事件呗。结果发现并非如此。实际上,一次 click 背后,其实有一大套的逻辑:

  1. 移动到按钮上时,会依次触发 mouseovermouseenter 事件,前者冒泡,后者不冒泡
  2. 鼠标按下时,广播 mousedown 事件
  3. 如果此时其它元素有焦点,那么该元素会先失去焦点,并广播 blur 事件
  4. (下一节补充)
  5. 按钮获得焦点,广播 focus 事件
  6. 如果因此影响到 DOM,那么会等待 DOM 变更
  7. 如果鼠标没有离开按钮,按钮广播 mouseup 事件
  8. 最后广播 click 事件
  9. 在移动设备上,可能会有 300ms 延迟

其实(5)并不准确,每一次事件广播都是独立的 event loop ,所以上面每一步都可能产生 DOM 变化和其它次生变化,也可能导致一些操作或功能不符合预期。比如:

  1. 一个搜索框。输入后自动搜索,结果以 dropdown 形式展示在下面
  2. 点击 dropdown 里的条目可以跳转
  3. 搜索框 blur 时 dropdown 移除

此时,dropdown 里的条目可能无法点击。因为点击时,输入框先 blur,之后 dropdown 隐藏,接下来 mouseup 事件触发在别的元素上,于是不会有 click 事件。

最简单的解决方案,给 blur 事件加延迟,10ms 就够。

(关于上面的事件触发顺序,可以用这个的 codepen 尝试)

click 事件对 change 事件的影响

接下来,回到 QA 产品。

我真正踩的坑,是 change 事件没有按照预期触发。大家知道,Vue 组件通过 $emit('input') 可以更新绑定在 v-model 里的值。触发的时机一般通过侦听 DOM input 或者 change 来决定。如果 change 无法正确触发,那么 QA 产品自然而然就无法正常工作。

实际上,在上一节的 click 逻辑中,第(4)步可以展开为:

如果失去焦点的元素是 <input> 或者 <textarea>,则该元素会广播 change 事件。

模拟 click 动作的代码

最后,演示一下最终代码:

const options = {
  bubbles: true,
  cancelable: true,
  view: window,
};
let event = new MouseEvent('mousedown', options);
elem.dispatchEvent(event);
elem.focus();
event = new MouseEvent('mouseup', options);
elem.dispatchEvent(event);
elem.click();

相关链接

分类
服务器端

树莓派4 安装 OpenResty + PostgreSQL

为了给 OpenResty.org 添加论坛链接,在本地搭建开发环境,选择用树莓派搞。记录一下,以备将来回顾。

分类
css

CSS 网页保持全屏并自动伸长

其实是个小需求,以前也搞过很多次,没想到前几天被坑了一下,记一笔。

以前,如果想要页面在内容任意多的时候都能占满浏览器,可以简单设置:

html,
body {
  height: 100%;
}

但是这样设置,在 Safari 浏览器上,会将 <body> 固定为窗口高度,如果内容多,就会被底部挡住内容。解决方案是 body 高度用 min-height:100%

如果是三行一列的结构,即上面是导航条,下面是脚部,中间随内容自适应,可以用:

body {
  display: flex;
  flex-direction: column;
}

这个时候,不能用 flex-basis,在 Safari 上会失去弹性,也要用 min-height。所以,最终样式大概就是:

html {
  height: 100%;
}

body {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

#nav {
  height: 4rem;
}
#bottom {
  height: 10rem;
}
#content {
  flex-grow: 1;
  min-height: 40rem;
}

另外,因为基本只有桌面浏览器需要这个功能,所以可以考虑加一个 @media (min-width: 576px) 做限制。

分类
学习

从 uiprint.co 聊一聊“练习作品”

我一直有做 Side project 的心,经常想实践一些 idea,不过多数止步于画原型。

虽然我常年购买 Adobe Creative 和 Sketch,也经常使用 Photoshop、XD、Sketch 切页面,不过并不擅长真刀实枪的“创作”。一旦涉及到画原型,进度就会很慢,经常让我的 indie hacker 之路止步于此。于是我就想,要不还是画在纸上。

然后我就找到这个网站:uiprint.co。上面有很多做好的 PDF,直接下载打印,就可以得到很好的设计底图,然后连连画画(上面有网格点),就能画出很棒的设计原型。这样做最大的好处是,设计思路不会中断,可以专注于产品逻辑。

为了方便大家理解,我截了一张图

接着聊聊“练习作品”。

我经常逛技术论坛和问答区,常常看到有同学提问:“自学前端,能仿着教程写出 demo,接下来该怎么做?”,或者“应届生,该写什么项目经历?”

面对这种问题,我都会建议他:

  1. 不要仿做 demo,要做有人用的东西
  2. 认真地进行推广、迭代
  3. 解决遇到的各种问题

模仿写 demo,意味着作品没有得到真正的检验。没有职业经验的新人,他眼里的“也做得出来”、“挺好”,在商业产品里多半连及格都算不上。满足于做这样的作品,没有办法获得真正的提升,写到简历里,也没什么价值。

接下来的问题是:做什么?

首先,不要贪大求全。你当然可以做电商网站,或者自己从头写个博客、论坛,看起来很高端,但实际上既耗时耗力,也没有什么价值,因为没有人真的会用。

其次,要把眼界放宽。互联网已经是一种基础设施,大部分行业都能被互联网赋能提升。与其照抄千篇一律的 todo-list,电商网站首页,好好想想自己周围的人需要什么,做一个他们会用的东西更有价值。

uiprint.co 就是一个很好的例子:

  1. 它本身很简单,就是网页+可以下载的 PDF,纯静态,开发成本维护成本都很低。即使是前端新人,也不太会遭遇无法攻克的技术难题。
  2. 有价值,是 Product Hunt 日榜第一,所有需要做产品设计的人都可以获得帮助。不断有人用,作者就有不断更新的动力,也有不断升级的需求,比如视觉效果调整、访问量统计、添加内容的后台等等。
  3. 就更不用说这个网站本身可能带来的价值

其实我们身边类似这样的机会并不少。比如 2010 年的时候,智能手机刚刚兴起,就有一个人告诉我,他想做一个应用,告诉你在北京上海这样的大城市怎么做地铁,哪站有厕所,哪站车门开在那边、等等。

这样的项目坚持下来,虽然未必有经济收益,但一定能获得很多有价值的项目经验,对入行、对找工作,都会有很大帮助。


总结一下:

  1. 想自学、想提升自己、想找工作,做项目一定要做有人用的东西,不要模仿做 demo
  2. 选择题目不需要特别大,也不需要纯互联网,有人用 是首要原则
  3. 接下来就是坚持,坚持开发、坚持维护、坚持推广

希望对大家有帮助。

分类
开发工具

PhpStorm 添加其它目录到本项目

小笔记,低技术含量。

分类
前端

给 Markdown 里的图片增加样式

在 markdown 里添加图片很容易,用这个语法即可:

![alt](/path/to/image "title")

但是如果图片需要一些特殊样式,就不太好搞。比如前两天,老板觉得博文中的二维码太大,不好看,让我改小点。我一开始只知道可以用 HTML 来做,因为 Markdown 内建支持所有 HTML,但总觉得不够优雅,尤其是,不知道怎么要求将来写博客的人都用 HTML 来写。

于是 Google 之,找到这篇文章:How to Style Images With Markdown,写得非常好,列举了很多添加样式的方法,尤其是使用 #hash + CSS 选择器的方法,很有想象力,推荐给大家。

首先,在 Markdown 里,给图片的 URL 添加 hash。这个动作并不会造成任何实质性的影响。

![alt](/path/to/image#thumbnail)

然后,在 CSS 里,定义“src 里包含字符串 #thumbnail”的规则即可:

img[src*="#thumbnail"] {
  max-width: 10rem;
}

[attr*=val] 选择器的意思是 attr 属性里包含 val 字符串。这里用 [src$="#thumbnail"] 效果是一样的。如果你想了解所有 CSS 属性选择器,还是推荐看 MDN 文档