一些有关细节和冷门的知识
记录一些不太常用却十分靠谱的布局样式和内置函数。
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
,在浏览器加载页面之后会在顶部出现地址栏,这时候页面是溢出窗口的,将地址栏向上拖动后地址栏会隐藏,这时候滚动条也会消失,Safari和Chrome都可以复现这个问题。
而且在地址栏的出现与否对safe-area-inset-*
变量的有效性也会产生影响,下面这个例子中在一个页面中加了一个按钮,并设置它的下边距为env(safe-area-inset-bottom)
,可以看到地址栏隐藏的时候变量才会生效,猜测可能是因为在地址栏出现的时候不属于全面屏显示模式,有意而为之让这些变量不会生效?
在stackoverflow社区中和Avoid 100vh On Mobile Web、URL Bar Resizing也有关于这些现象的描述。
在一般的页面也不会关注到这个问题,在页面高度接近100vh
时会比较突出。
text-align-last
平时经常用text-align
,有时候遇到多行长文本的情况,使用居中功能的时候,有些行与容器之间总是会有间隙,当时也不影响大局,如下图:
这时候可以使用这个属性让文本的显示呈现的更完美:
.center {
text-align: justify;
text-align-last: center;
}
数字格式化方法toLocaleString
有时候我们需要将一个金额转换为在阅读上更友好的形式,包括但不限于,添加千位分隔符(可能还在面试里出现过)、保留到分的小数、金额相加时处理精度问题,我们经常借助Math.round
、Number.toFixed
等来完成以上转换,但是其实有个更方便的方法来实现这些变换,那就是使用toLocaleString
。
该函数接口接受两个参数,第一个是代表地区,中国根据不同地区可以使用不同的代码,常用的有:zh
、zh-Hans
、zh-Hans-CN
、zh-Hans-HK
、zh-Hans-TW
,所有的地区列表可以在这里找到;第二个参数是对象,表示格式样式和一些额外设置,格式样式style
可选项包括:decimal、currency、percent、unit,这里挑两个我认为最有用的聊一下:
-
显示货币 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%