前言
刚过去的双11大家都去哪些网站购物了呢?不管去哪个网站,估计都少不了天猫吧,在逛天猫时发现了这样一种有趣的现象:
虽然说这种效果还比较常见,但有一个细节与众不同,比如说咱们先来看一个普通的 header 随窗口滚动而渐隐渐现的效果:
对比一下发现哪里不同了么,普通版的是一开始完全透明,随着窗口的滚动而慢慢显示出来,靠的是控制opacity
透明度属性来实现的。
而小黑盒那版是一开始就有一个渐变色,渐变到接近半透明,这种方式看起来更加的优雅,但看起来只是一开始进入页面还没滚动的时候带着很漂亮的渐变色,一滚动的时候行为又和以前靠透明度的时候差不多。
咱们要改进的就是用滚动的距离来控制background-position
,随着窗口的滚动,会慢慢改变渐变色渐变的程度而控制显隐效果。
样式
首先咱们先把header
的样式写出来:
header {
/* 设置一个控制背景色位置的CSS变量,方便JS控制 */
--position: 100;
/* 居中靠下显示子元素 */
display: grid;
place-items: end center;
/* 设置为固定定位 */
position: fixed;
/* 距离上边左边为0 */
top: 0;
left: 0;
/* 宽度铺满屏幕 */
width: 100%;
/* 给个合适的高度 */
height: 40px;
/* 白色字体 */
color: white;
/* 字体大小 */
font-size: 16px;
/* 让字体细一点 */
font-weight: 100;
/* 增加下内变局,防止文字过于靠下 */
padding-bottom: 10px;
/* 设置过渡效果 */
transition: background-position .2s;
/* 黑色渐变背景 */
background: linear-gradient(black, rgba(148, 88, 88, 0.3) 80%, rgba(0, 0, 0, 0)) 0 calc(var(--position) * 1%) / 100% 300%;
}
复制代码
运行结果:
可以看到我们在header
里面设置了一条CSS变量,如果不太清楚什么是CSS变量的话请点击这里,这里还用到了 gird 来进行居中,当然并不是完完全全的居中,而是稍稍偏下了一点,因为我看天猫的小黑盒就是做的偏下居中。
整体实现
然后咱们开始写 JS 代码了,因为纯 CSS 的话还是无法获取屏幕的滚动距离,但是为了能够更方便的进行双方交互,我们还是采用了CSS变量,因为CSS变量带来的提升绝不仅仅是节约点 CSS 代码,以及降低 CSS 开发和维护成本这点作用。
更重要的是,把组件中众多的交互开发从原来的JS转移到了CSS代码中,让组件代码更简洁,同时让视觉表现实现更加灵活了。 ——张鑫旭
CSS变量具体能为我们带来哪些好处,可以参考张鑫旭的博客:
来看一下CSS变量是怎么与 JS 进行交互的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>属于自己的渐变小黑盒</title>
<style>
/* 清除默认样式 */
* { padding: 0; margin: 0 }
header {
/* 设置一个控制背景色位置的CSS变量,方便JS控制 */
--position: 100;
/* 居中靠下显示子元素 */
display: grid;
place-items: end center;
/* 设置为固定定位 */
position: fixed;
/* 距离上边左边为0 */
top: 0;
left: 0;
/* 宽度铺满屏幕 */
width: 100%;
/* 给个合适的高度 */
height: 40px;
/* 白色字体 */
color: white;
/* 字体大小 */
font-size: 16px;
/* 让字体细一点 */
font-weight: 100;
/* 增加下内变局,防止文字过于靠下 */
padding-bottom: 10px;
/* 设置过渡效果 */
transition: background-position .2s;
/* 黑色渐变背景 */
background: linear-gradient(black, rgba(148, 88, 88, 0.3) 80%, rgba(0, 0, 0, 0)) 0 calc(var(--position) * 1%) / 100% 300%;
}
main {
/* 给个合适的高度 */
height: 1000px;
}
</style>
</head>
<body>
<header>咱们自己的小黑盒</header>
<main></main>
<script>
// 获取header
const header = document.getElementsByTagName('header')[0]
addEventListener('scroll', () => {
// 获取偏移值
const top = document.documentElement.scrollTop
// 设置一个合适的范围
if (top <= 200) {
// 令header的渐变色位置变成计算后的渐变位置
header.style.setProperty('--position', 100 - Math.min(100, top))
} else {
// 在移动一定范围后令其完全不透明
header.style.setProperty('--position', 0)
}
})
</script>
</body>
</html>
复制代码
运行结果:
想象一下如果不用CSS变量的话会变成什么样:
header.style.backgroundPosition = '0 ' + 100 - Math.min(100, top) + '%'
复制代码
虽然看起来好像没啥的,但当要控制的属性较多时这将会是一种灾难,而且这种方式要时刻都带着 CSS 单位,像 px、%、rem 这些,为我们增加了不必要的心智负担,而且也拖慢了程序的运行效率。
用了CSS变量之后都不用带单位了,直接赋值一个数字即可,那么为什么可以不带单位呢?答案就在 calc
函数上:
calc(
var(--position)
*1%
)
记住在这里可不能再用 JS 的思维来写 calc 函数了,在 JS 里我们用的是+
,因为这代表了字符串拼接,而在这里数字乘以
百分之一,就会变成具体的百分数,同理如果你需要的是其他单位的话可以根据具体需求进行灵活修改:
calc(
var(--position)
*1px
)
⚠️注意 px 前面那个1
很重要,不能省略掉!
而且也不是必须要写1
,还可以根据具体的需求按倍数来:
calc(
var(--position)
*6.6rem
)
扩展
其实从代码和我们日常生活中见到的效果可以得知,基本上滚动一段距离后header
的透明度就固定住了不会再发生变化,浪费了监听 onscroll
事件。但又不能取消监听,因为不知道用户何时会再滑到顶部去,但这种情况却非常适合做另一种效果:
我忘记了这种效果叫啥来着,总之就是随着用户滚动页面的距离而在顶部显示一个类似于进度条之类的东西,方便用户得知自己处在网页中大概什么样的一种位置,来看代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>属于自己的渐变小黑盒</title>
<style>
/* 清除默认样式 */
* { padding: 0; margin: 0 }
header {
/* 设置一个控制位置的CSS变量,方便JS控制 */
--position: 0;
/* 设置为固定定位 */
position: fixed;
/* 距离上边左边为0 */
top: 0;
left: 0;
/* 宽度铺满屏幕 */
width: 100%;
/* 给个合适的高度 */
height: 10px;
/* 设置过渡效果 */
transition: transform .1s;
/* 渐变背景 */
background: linear-gradient(to right,#4481eb,#04befe);
/* 设置形变效果 */
transform: scaleX(var(--position));
/* 设置变形参照点 */
transform-origin: left;
}
main {
/* 给个合适的高度 */
height: 10000px;
/* 渐变背景 */
background: linear-gradient(#30cfd0,#330867)
}
</style>
</head>
<body>
<header></header>
<main></main>
<script>
// 获取header
const header = document.getElementsByTagName('header')[0]
addEventListener('scroll', () => {
// 获取偏移值
const top = document.documentElement.scrollTop
// 获取页面总高度
const height = document.documentElement.scrollHeight
// 设置CSS变量
header.style.setProperty('--position', top / (height - document.documentElement.clientHeight))
})
</script>
</body>
</html>
复制代码
往期精彩文章
- 《整治GitHub不文明现象!微软推出评论区!》
- 《Vue 3.0.3 : 新增CSS变量传递以及最新的Ref提案》
- 《[译]尤雨溪: Ref语法糖提案》
- 《千万别小瞧九宫格 一道题就能让候选人原形毕露》
- 《移动端布局面试题 全面考察你的CSS功底(居中篇)》
- 《将原型对象设置成Proxy后的一系列迷惑行为》
- 《Vue超好玩的新特性:DOM传送门》
- 《Vue超好玩的新特性:在CSS中引入JS变量》
- 《不依赖任何库打造属于自己的可视化数据地图》
- 《在Vue项目中使用React超火的CSS-in-JS库: styled-components》
- 《终于轮到Vue来带给React灵感了?》
- 《Vue3在IOS下的一个小坑》
- 《2020要用immer来代替immutable优化你的React项目》
- 《来自《React Hooks 与 Immutable》小册作者'神三元'的灵魂拷问》
- 《好消息,Vue3官方文档出中文版的啦!》
- 《新版vue-router的hooks用法》
- 《[译]Vue 3:2020年中状态更新》
- 《[译]React 17终于发布RC版本了 官方竟说17是个过渡版!》
- 《[译]尤雨溪:Vue3的设计过程》
- 《Node之父重构的Deno终于发布了,它终究会取代Node吗?》
- 《今日凌晨Vue3 beta版震撼发布,竟然公开支持脚手架项目!》