构建突破 Chrome 12px 字体限制的 input 输入框

前言

chrome 浏览器有 12 px 的字体的限制,因此对于 vw 自适应布局,非常的不友好。

我之前曾经写过一篇文章,用 svg 辅助页面文字自适应,它可以解决常见的 html 元素里面的文字不能小于 12 px 的问题。

很不幸的是,最近我们的项目中加了 input 标签,于是采用之前的方案的问题就浮出水面了——它无法让 input 标签里面的字体在 chrome 中突破 12 px。

但是对于我们实际的项目,又必须要做到这种效果,那么该怎么办呢?

经过大胆的猜想和细心的论证,得出了几种方案:

  1. 利用 html 标签的 contenteditable 属性,再配合 svg 的特性,进行缩放
  2. 利用 scale 对 input 中的文字进行缩放
  3. 改用 canvas 绘制文字

思路

1. 利用 html 标签的 contenteditable 属性

这个属性,说来惭愧,以前并没接触过,在此只能暗自感慨自个儿学艺不精了。

这次也是为了解决这个问题,在找解决方案的时候,无意中发现的。

当时就感觉很惊叹了,没想到 html 标签居然还有这个属性。这不刚好就是我理想中的解决方案么?

首先按照惯例,避免误导大家,还是先奉上 mdn 文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable

不过说实话,其实在默认情况下,这个属性其实并没有这么好用。

div 上加了这个属性以后,它的默认行为有点类似于 textarea,你可以换行输入,可以换行。但是与 textarea 不同的是(其实你打开控制台就会发现),它实际上是采用不同的 div 来辅助排版的,比如你换了一行,就给你新起了一行,创建了一个新的 div,然后你输入的内容就会出现在新创建的 div 内部。

这个行为与我们期待的还是有点不一样的,但是我们明白了它的工作原理以后,是否能想到,我们把之前的 svg 辅助排版的功能,塞到这个地方来,也能实现我们想要的效果呢?

果不其然,经过我的测试了以后发现,使用 svg 元素放在里面,也是可以编辑的,这样就太好办了。

我用如下代码,构建了三个不同字体大小的 div 输入框,div 里面放置的是 svg,用来辅助 chrome 字体缩放的。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      [contenteditable]:focus {
        outline: none;
      }
      div {
        width: 75px;
        height: 20px;
        margin-top: 5px;
        border: 1px solid red;
      }
      .first {
        font-size: 5px;
      }
      .second {
        font-size: 8px;
      }
      .third {
        font-size: 12px;
      }
    </style>
  </head>
  <body>
    <div class="first" contenteditable="true">
      <svg width="100%" height="100%">
        <text dy=".3em" x="5%" y="50%" fill="#000" text-anchor="left">
          5px;
        </text>
      </svg>
    </div>
    <div class="second" contenteditable="true">
      <svg width="100%" height="100%">
        <text dy=".3em" x="5%" y="50%" fill="#000" text-anchor="left">
          10px;
        </text>
      </svg>
    </div>
    <div class="third" contenteditable="true">
      <svg width="100%" height="100%">
        <text dy=".3em" x="5%" y="50%" fill="#000" text-anchor="left">
          12px;
        </text>
      </svg>
    </div>
  </body>
</html>

运行代码以后,chrome 浏览器里面的效果是这样的:

Aug-28-2019 23-39-37.gif
Aug-28-2019 23-39-37.gif

<br />可以看到,可以成功实现输入的效果,并且字体大小的问题也解决了。

这个方案是否能在别的浏览器上使用,我暂时并未详尽的测试过,不过别的浏览器里面就没有字体的限制,所以压根就不需要用到这种 hacker 方法。

虽然看起来效果还挺像 input 输入框的,但是这里还是有一些需要考虑到的问题:

  1. 里面的文字不能像 input 输入框一样,输入内容超过父容器的范围时,会自动隐藏前面的内容,显示出最后的内容
  2. 里面的文字能够按 delete 或者 backspace 键删除掉,但是也会将内部的元素删除掉,这样会导致 svg 内容被删除掉

目前,我能想到的解决方案是,朝 div 上添加监听事件,监听键盘事件,当碰到对应的情况,给出对应的解决方案。

不过,这个解决方案还是挺复杂的,所以推荐文字数目一定的情况下使用。

2. 利用 transform 的 scale 属性对 input 中的文字进行缩放

我之前就提到过,可以采用 scale 属性,解决 chrome 12 px 字体限制的文字,但是问题就是麻烦。

因为 transform 是对整个 input 框的内容进行缩放,所以在缩放完以后,input 框本身的大小也变化了,位置也变化了,所以为了达到理想的突破 12px 限制的效果,还是需要用 js,动态的扩大 input 宽高,然后在用 transform 去缩小,用起来着实太麻烦。

而且这个方法,只适合按照设计稿里面的尺寸来写页面的情况,不能有效的适应 vw 动态缩放的布局。关键麻烦的地方,还是在计算,必须要动态的计算出来 input 需要扩大多少,然后再缩小多少,因为 font 撑开 input 框,因此得在外面套一个 div 放原本的 input 位置来占位,然后将 input 动态的算进占位符上面才行。

3. 利用 canvas 进行绘制

这个方法对 canvas 功底要求比较高,这就相当于用 canvas 自己构建一套输入框了,说实话,难度还是比较大。

这里暂且跳过具体实现方式吧,我后面有计划写一个类似的 demo,到时候我再回来补上具体细节。

总结

有些时候,一些看似很小的功能,但是由于各种历史原因和实现的时候的抉择,真正实现起来并不好弄。

就像以前前端工程师对 ie 浏览器的颇多怨言一样,我相信有些 hacker 技巧,会随着技术的进步和成熟,慢慢会变得不是问题。

但是对于一名合格的前端工程师来说,目前问题就摆在我们面前了,抱怨是没有任何有意思的,想出解决方案,才是我们的第一要务。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • CSS参考手册 一、初识CSS3 1.1 CSS是什么 CSS3在CSS2.1的基础上增加了很多强大的新功能。目前...
    没汁帅阅读 3,556评论 1 13
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,569评论 0 7
  • mobileHack 这里收集了许多移动端上遇到的各种坑与相对解决方案 工具类网站 HTML5 与 CSS3 技术...
    Zoemings阅读 6,519评论 0 12
  • Mobile Web Favorites 参与贡献 移动前端开发收藏夹,欢迎使用Issues以及 Pull Req...
    柴东啊阅读 723评论 0 2
  • 一群孩子在太阳初升的操场有节奏地跳绳,先生画画,小宝宝在家,父亲烧火,母亲做饭。和谐而温暖的场面。 清晨自问 1....
    lijutong_010阅读 226评论 2 4