小tips:如何摆脱浏览器下12px的限制

目前Chrome浏览器依然没有放开12px的限制,但Chrome仍然是使用人数最多的浏览器。

在笔者开发某个项目时突发奇想:如果实际需要11px的字体大小怎么办?这在Chrome中是实现不了的。关于字体,一开始想到的就是rem等非px单位。但是rem只是为了响应式适配,并不能突破这一限制。

em、rem等单位只是为了不同分辨率下展示效果提出的换算单位,常见的库px2rem也只是利用了js将px转为rem。包括微信小程序提出的rpx单位也是一样!

这条路走不通,就只剩下一个方法:改变视觉大小而非实际大小

理论基础

css中有一个属性:transform: scale();

  • 值的绝对值>1,就是放大,比如2,就是放大2倍
  • 值的绝对值 0<值<1,就是缩小,比如0.5,就是原来的0.5倍;
  • 值的正负,负值表示图形翻转。

默认情况下,scale(x, y):以x/y轴进行缩放;如果y没有值,默认y==x
也可以分开写:scaleX() scaleY() scaleZ(),分开写的时候,可以对Z轴进行缩放

第二种写法:transform: scale3d(x, y, z)该写法是上面的方法的复合写法,结果和上面的一样。

但使用这个属性要注意一点:scale 缩放的时候是以“缩放元素所在空间的中心点”为基准的。
所以如果用在改变元素视觉大小的场景下,一般还需要利用另一个元素来“恢复位置”:

transform-origin: top left;

语法上说,transform-origin 拥有三个属性值:

transform-origin: x-axis y-axis z-axis;

默认为:

transform-origin:50% 50% 0;

属性值可以是百分比、em、px等具体的值,也可以是top、right、bottom、left和center这样的关键词。作用就是更改一个元素变形的原点。

实际应用

<div class="mmcce__info-r">
  <!-- 一些html结构 -->
  <div v-show="xxx" class="mmcce-valid-mj-period" :class="{'mmcce-mh': showStr}" @click="handleShowStr"> <!-- click中事件控制展示与否 -->
    <div class="mmcce-valid-period-child">{{couponInfo.startTimeFormat}}-{{couponInfo.endTimeFormat}}</div><!-- 父级结构,点击显示下面内容 -->
    <div class="mmcce-valid-pro" ref="mmcceW" :style="{opacity: showStr ? 1 : 0}">
      <!-- 下面内容在后面有讲解 -->
      <div class="mmcce-text" 
        v-for="(item, index) in couponInfo.thresholdStr" 
        :key="index" 
        :index="index"
        :style="{height: mTextH[index] + 'px'}"
      >{{item}}</div>
    </div>
  </div>
</div>
.mmcce-valid-mj-period {
  max-height: 15px;
  transition: all .2s ease;

  &.mmcce-mh {
    max-height: 200px;
  }

  .mmcce-valid-pro {
    display: flex;
    flex-direction: column;
    padding-bottom: 12px;

    .mmcce-text {
      width: 200%; // !
      font-size: 22px;
      height: 15px;
      line-height: 30px;
      color: #737373;
      letter-spacing: 0;
      transform       : scale(.5);
      transform-origin: top left;
    }
  }
}

.mmcce-valid-period-child {
  position: relative;
  width      : 200%;
  white-space: nowrap;
  font-size  : 22px;
  color      : #979797;
  line-height: 30px;

  transform       : scale(.5);
  transform-origin: top left;

  //xxx
}

微店-卡券包项目截图

可以明确说明的是,这样的 hack 需要明确规定缩放元素的height!!!

上面代码中为什么.mmcce-valid-mj-period类中要用max-height ?为什么对展开元素中的文字类.mmcce-text中使用height
我将类.mmcce-text中的height去掉后,看下效果:
微店-卡券包项目截图2

(使用min-height是一样的效果)

OK,可以看到,占高没有按我们想的“被缩放”。影响到了下面的元素位置。

本质上是“视觉大小改变了但实际(占位)大小无变化”。
这时候,宽高实际也被缩放了的。这一点通过代码中width:200%也可以看出来。或者你设置了overflow:hidden;也可以有相应的效果!

这一点需要注意,一般来说,给被缩放元素显式设置一个大于等于其font-sizeheight值即可。

缩放带来的其它问题

可能在很多人使用的场景中是不会考虑到这个问题的:被缩放元素限制高度以后如果元素换行那么会出现文字重叠的现象。
微店-卡券包项目截图3

为此,我采用了在mounted生命周期中获取父元素宽度,然后动态计算是否需要换行以及换行的行数,最后用动态style重新渲染每一条数据的height值。
这里有三点需要注意:

  1. 这里用的是一种取巧的方法:用每个文字的视觉font-size值*字符串长度。因为笔者遇到的场景不会出现问题所以可以这么用。在不确定场景中更推荐用canvas或dom实际计算每个字符的宽度再做判断(需要知道文字、字母和数字的宽度是不一样的);
  2. 需要注意一些特殊机型的展示,比如三星的galaxy fold,这玩意是个折叠屏,它的计算会和一般的屏幕计算的不一致;
  3. 在vue生命周期中,mounted可以操作dom,你可以通过this.$el获取元素。但要注意:在这个时期被获取的元素不能用v-if(即:必须存在于虚拟tree中)。这也是上面代码中笔者使用v-showopacity的原因。

关于第三点,还涉及到加载顺序的问题。比如刚进入页面时要展示弹窗,弹窗是一个组件。那你在index.vue中是获取不到这个组件的。但是你可以将比如header也拆分出来,然后在header组件的mounted中去调用弹窗组件暴露出的方法。

mounted(){
  let thresholdStr = this.info.dropDownTextList;
  let minW = false;
  if(this.$el.querySelector('.mmcce-valid-pro').clientWidth < 140) { // 以iPhone5位准,再小于其中元素宽度的的机型就要做特殊处理了
    minW = true
  }
  let mmcw = this.$el.querySelector('.mmcce-valid-pro').getBoundingClientRect().width;

  let mmch = [];

  for(let i=0;i<thresholdStr.length;i++) {
    // 11是指缩放后文字的font-size值,这是一种取巧的方式
    if(11*(thresholdStr[i].length) > mmcw) {
      if(minW) {
        mmch[i] = Math.floor((11*thresholdStr[i].length) / mmcw) * 15;
      }else {
        mmch[i] = Math.floor((11*(thresholdStr[i].length) + 40) / mmcw) * 15;
      }
    }else {
      mmch[i] = 15;
    }
  }

  this.mTextH = mmch;
},

2022-9-23更新
而且有的时候,其实可以和设计商讨一下。在一些场景下我们不必“死守视觉稿”。比如我司近期的项目中:
多单立减- H5-1

多单立减- H5-2

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恪愚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值