跳到主要内容

一些有关细节和冷门的知识

· 阅读需 7 分钟

记录一些不太常用却十分靠谱的布局样式和内置函数。

position: sticky;

这个属性首当其冲,其实也不算冷门了,典型的应用场景是导航栏、搜索条、底部版权说明等,这些原本需要用fixed的在大部分情况下都可以被替代。

下面是一个很常见的例子,在一个长长的移动端宣传页上需要在底部添加一个浮动的咨询按钮,过去我们的做法是:

<style>
.long-content {
height: 2000px;
}
.contact {
background: #fff;
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
</style>

<div class="long-content">长长的宣传内容</div>
<footer class="footer">Copyright © xx有限公司</footer>
<div class="contact">
<button>点击咨询</button>
</div>

很熟悉的代码,但是这样会覆盖着原来在底部的footer标签的内容,于是我们需要给它添加一行样式可能是这样的:padding-bottom: 60px;这个60px需要精确的控制为刚好是咨询模块的高度,这时候你又会发现为了兼容全面屏手机需要继续修改,于是样式代码进化成这样:

.long-content {
height: 2000px;
}
.footer {
padding-bottom: calc(60px + env(safe-area-inset-bottom));
}
.contact {
background: #fff;
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding-bottom: env(safe-area-inset-bottom);
}

这里的问题所在就是每次改动咨询模块的高度的时候就需要相应的变动被它覆盖着的那部分内容footer样式,如果改成sticky,这个问题就不会存在,同时footer也不需要增加下边距:

.long-content {
height: 2000px;
}
.contact {
background: #fff;
position: sticky;
left: 0;
right: 0;
bottom: 0;
padding-bottom: env(safe-area-inset-bottom);
}

这就是一个典型案例,用在顶部搜索条、导航栏也是一样的原理。

有一点点奇怪的 100vh

这个问题是在测试一个高度接近满屏的页面时,在iOS中发现的:创建一个页面,高度为100vh,在浏览器加载页面之后会在顶部出现地址栏,这时候页面是溢出窗口的,将地址栏向上拖动后地址栏会隐藏,这时候滚动条也会消失,SafariChrome都可以复现这个问题。

非全屏状态

全屏状态

而且在地址栏的出现与否对safe-area-inset-*变量的有效性也会产生影响,下面这个例子中在一个页面中加了一个按钮,并设置它的下边距为env(safe-area-inset-bottom),可以看到地址栏隐藏的时候变量才会生效,猜测可能是因为在地址栏出现的时候不属于全面屏显示模式,有意而为之让这些变量不会生效?

样式

全面屏模式动画演示

stackoverflow社区中和Avoid 100vh On Mobile WebURL Bar Resizing也有关于这些现象的描述。

在一般的页面也不会关注到这个问题,在页面高度接近100vh时会比较突出。

text-align-last

平时经常用text-align,有时候遇到多行长文本的情况,使用居中功能的时候,有些行与容器之间总是会有间隙,当时也不影响大局,如下图:

居中样式

这时候可以使用这个属性让文本的显示呈现的更完美:

.center {
text-align: justify;
text-align-last: center;
}

更完美的居中样式

数字格式化方法toLocaleString

有时候我们需要将一个金额转换为在阅读上更友好的形式,包括但不限于,添加千位分隔符(可能还在面试里出现过)、保留到分的小数、金额相加时处理精度问题,我们经常借助Math.roundNumber.toFixed等来完成以上转换,但是其实有个更方便的方法来实现这些变换,那就是使用toLocaleString

该函数接口接受两个参数,第一个是代表地区,中国根据不同地区可以使用不同的代码,常用的有:zhzh-Hanszh-Hans-CNzh-Hans-HKzh-Hans-TW,所有的地区列表可以在这里找到;第二个参数是对象,表示格式样式和一些额外设置,格式样式style可选项包括:decimalcurrencypercentunit,这里挑两个我认为最有用的聊一下:

  • 显示货币 currency

    (12345678).toLocaleString('zh-Hans-CN', { style: 'currency', currency: 'CNY' });
    // ¥12,345,678.00

    // 如果需要去掉千位分隔符,可以这样做
    (12345678).toLocaleString('zh-Hans-CN', { style: 'currency', currency: 'CNY', useGrouping: false });
    // ¥12345678.00

    // 常见的两个金额相加的精度问题
    0.1 + 0.2
    // 0.30000000000000004
    (0.1 + 0.2).toLocaleString('zh-Hans-CN', { style: 'currency', currency: 'CNY' });
    // ¥0.30

    // 如果需要保留3位小数,可以这样做
    (0.1 + 0.2).toLocaleString('zh-Hans-CN', { style: 'currency', currency: 'CNY', minimumFractionDigits: 3 })
    // ¥0.300
  • 显示百分比 percent

    (0.1).toLocaleString('zh-Hans-CN', { style: 'percent' })
    // 10%

    // 规避精度问题
    (0.1 + 0.2).toLocaleString('zh-Hans-CN', { style: 'percent' })
    // 30%

    // 保留小数
    (1 / 3).toLocaleString('zh-Hans-CN', { style: 'percent', minimumFractionDigits: 2 })
    // 33.33%
    (2 / 3).toLocaleString('zh-Hans-CN', { style: 'percent', minimumFractionDigits: 2 })
    // 66.67%