忍不住开头打个广告😎:
2021 火爆全网的 CSS 架构实战课上线,好评如潮!!!
【课程链接:https://coding.imooc.com/class/501.html 】
前言
变量作为CSS体系中最高逼格的特性,没有之一。随着浏览器日益完善,变量可大范围在项目中使用,无需关注其兼容性。
虽说变量可在纯CSS中起到领头羊的作用,但是变量的设计初衷是为了更便利CSS与JS间的联系。CSS使用变量有如下好处。
- 减少样式代码的重复性
- 增加样式代码的扩展性
- 提高样式代码的灵活性
- 增多一种CSS与JS的通讯方式
- 不用深层遍历DOM改变某个样式
本章的主题是变量控件,主要是基于变量与JS通讯简化基于JS逻辑的效果。也是本小册唯二两章结合JS完成效果的章节,常见控件有放大镜
和滚动渐变背景
。
放大镜
传统的放大镜效果需依赖大部分JS逻辑,移动和显示的效果均依赖JS,通过JS计算偏移量再渲染样式。
本次使用变量简化这些JS逻辑,将计算偏移量的逻辑整合到变量中,还记得第7章函数计算的calc()
吗?calc()
用于动态计算单位,是本次改造的核心用法。
基于上述需求,实时获取鼠标的左偏移量
和上偏移量
即可,而这两个偏移量是相对父节点的。通过左偏移量
和上偏移量
结合calc()
即可计算放大镜显示内容相对父节点的显示位置。
event
提供以下八个偏移量,若不了解其概念很容易发生混淆。
- screenX/screenY:相对
屏幕区域左上角
定位,若发生滚动行为,则相对该区域定位 - pageX/pageY:相对
网页区域左上角
定位 - clientX/clientY:相对
浏览器可视区域左上角
定位 - offsetX/offsetY:相对
父节点区域左上角
定位,若无父节点则相对<html>
或<body>
定位
罗列出这些偏移量概念,发现offsetX/offsetY
是最符合需求的,所以使用其作为放大镜显示内容相对父节点的显示位置。
<div class="magnifier" @mousemove="move"></div>
export default {
methods: {
move(e) {
e.target.style.setProperty("--x", `${e.offsetX}px`);
e.target.style.setProperty("--y", `${e.offsetY}px`);
}
}
};
接下来使用sass
构建放大镜效果。放大镜显示内容其实就是将原图像放大N倍,通过上述偏移量按照比例截取一定区域显示内容。
先定义相关的Sass变量
。设定放大倍率为2倍,那么被放大图像的宽高也是原来宽高的2倍。声明两个变量,分为为--x
和--y
。
$ratio: 2;
$box-w: 600px;
$box-h: 400px;
$box-bg: "https://static.yangzw.vip/codepen/gz.jpg";
$outbox-w: $box-w * $ratio;
$outbox-h: $box-h * $ratio;
.magnifier {
--x: 0;
--y: 0;
overflow: hidden;
position: relative;
width: $box-w;
height: $box-h;
background: url($box-bg) no-repeat center/100% 100%;
cursor: pointer;
}
还记得第9章选择器的伪元素使用场景吗?在这个场景下很明显无需插入子节点作为放大镜的容器了,使用::before
即可。
放大镜在使用时宽高为100px
,不使用时宽高为0px
。通过绝对定位布局放大镜随鼠标移动的位置,即声明left
和top
,再通过声明transform:translate(-50%,-50%)
将放大镜补位,使放大镜中心与鼠标光标位置一致。由于声明left
和top
定位放大镜的位置,那么还需声明will-change
改善left
和top
因改变而引发的性能问题。
.magnifier {
&::before {
--size: 0;
position: absolute;
left: var(--x);
top: var(--y);
border-radius: 100%;
width: var(--size);
height: var(--size);
box-shadow: 1px 1px 3px rgba(#000, .5);
content: "";
will-change: left, top;
transform: translate(-50%, -50%);
}
&:hover::before {
--size: 100px;
}
}
接下来使用background
实现放大镜显示内容。依据放大倍率为2倍,那么声明size:$outbox-w $outbox-h
,通过声明position-x
和position-y
移动背景即可,最终连写成background:#333 url($box-bg) no-repeat $scale-x $scale-y/$outbox-w $outbox-h
,而$scale-x
和$scale-y
对应position-x
和position-y
,用于随着鼠标移动而改变背景位置。
水平方向偏移量 = offsetX * 倍率 - 放大镜宽度 / 倍率
垂直方向偏移量 = offsetY * 倍率 - 放大镜高度 / 倍率
基于第10章背景与遮罩的background-position
正负值问题,上述两条公式还需乘以-1
,则变成以下公式。
水平方向偏移量 = 放大镜宽度 / 倍率 - offsetX * 倍率
垂直方向偏移量 = 放大镜高度 / 倍率 - offsetY * 倍率
此时将两条公式代入到$scale-x
和$scale-y
两个Sass变量
中,若在calc()
中使用Sass变量
,需使用#{}
的方式包含Sass变量
,否则会按照字符串的方式解析。
$scale-x: calc(var(--size) / #{$ratio} - #{$ratio} * var(--x));
$scale-y: calc(var(--size) / #{$ratio} - #{$ratio} * var(--y));
最终的scss
文件如下。
$ratio: 2;
$box-w: 600px;
$box-h: 400px;
$box-bg: "https://static.yangzw.vip/codepen/gz.jpg";
$outbox-w: $box-w * $ratio;
$outbox-h: $box-h * $ratio;
.magnifier {
--x: 0;
--y: 0;
overflow: hidden;
position: relative;
width: $box-w;
height: $box-h;
background: url($box-bg) no-repeat center/100% 100%;
cursor: pointer;
&::before {
--size: 0;
$scale-x: calc(var(--size) / #{$ratio} - #{$ratio} * var(--x));
$scale-y: calc(var(--size) / #{$ratio} - #{$ratio} * var(--y));
position: absolute;
left: var(--x);
top: var(--y);
border-radius: 100%;
width: var(--size);
height: var(--size);
background: #333 url($box-bg) no-repeat $scale-x $scale-y/$outbox-w $outbox-h;
box-shadow: 1px 1px 3px rgba(#000, .5);
content: "";
will-change: left, top;
transform: translate(-50%, -50%);
}
&:hover::before {
--size: 100px;
}
}
- 在线演示:[Here] codepen.io/JowayYoung/pen/oNbGzPy
- 在线源码:[Here] github.com/JowayYoung/idea-css/blob/master/icss/src/components/component/%E6%94%BE%E5%A4%A7%E9%95%9C.vue
滚动渐变背景
各位同学使用移动端APP应该会发现某些页面在滚动时,顶部背景颜色会发生细微的变化,该变化随着滚动距离的增大而导致背景颜色变淡。
有了上述示例作为铺垫,可清楚知道变量结合鼠标事件
能完成更多的酷炫效果,而关键点是把鼠标的某些参数(例如偏移量
)赋值到变量上,让变量随着鼠标参数的变化而变化。主要了解该技巧,就能开发出很多变量与JS通讯的动画关联
和事件响应
。
由于本示例与滚动有关,那么毫不犹豫地想起了event.target.scrollTop
,监听滚动事件并将event.target.scrollTop
赋值到变量上即可。另外,当滚动距离超过一定时需做一些限制,例如背景颜色不再发生变化。
<div ref="bg" class="dynamic-bg">
<header></header>
<main @scroll="scroll">
<div>
<p>网易公司(NASDAQ: NTES),1997年由创始人兼CEO丁磊先生在广州创办,2000年在美国NASDAQ股票交易所挂牌上市,是中国领先的互联网技术公司。在开发互联网应用、服务及其它技术方面,始终保持中国业界领先地位。本着对中国互联网发展强烈的使命感,缔造美好生活的愿景,网易利用最先进的互联网技术,加强人与人之间信息的交流和共享。</p>
<p>网易公司推出了门户网站、在线游戏、电子邮箱、在线教育、电子商务、在线音乐、网易bobo等多种服务。网易在广州天河智慧城的总部项目计划2019年1月建成,网易游戏总部将入驻。2016年,游戏业务营业收入在网易总营收中占比73.3%。2011年,网易杭州研究院启用。网易传媒等业务在北京。网易在杭州上线了网易考拉海购、网易云音乐等项目。</p>
<p>网易2019全年财报显示,网易公司2019年全年净收入为592.4亿元;基于非美国通用会计准则,归属于网易公司股东的持续经营净利润为156.6亿元。</p>
<p>2019年,网易深入推进战略聚焦,坚守内容消费领域,积极布局游戏、教育、音乐、电商等核心赛道,取得重大突破。在保持稳健增长的同时,网易有道、创新及其他等业务板块爆发强大潜力,为未来的长期发展提供源源不断的动能。</p>
</div>
</main>
</div>
.dynamic-bg {
--scrolly: 250;
overflow: hidden;
position: relative;
border: 1px solid #66f;
width: 400px;
height: 400px;
header {
--Θ: calc(var(--scrolly) * 2deg);
--size: calc(1500px - var(--scrolly) * 2px);
--x: calc(var(--size) / 2 * -1);
--y: calc(var(--scrolly) * -1px);
--ratio: calc(50% - var(--scrolly) / 20 * 1%);
position: absolute;
left: 50%;
bottom: 100%;
margin: 0 0 var(--y) var(--x);
border-radius: var(--ratio);
width: var(--size);
height: var(--size);
background-color: #3c9;
filter: hue-rotate(var(--Θ));
animation: rotate 5s linear infinite;
}
main {
overflow: auto;
position: relative;
width: 100%;
height: 100%;
div {
padding: 300px 20px 50px;
}
p {
line-height: 1.2;
text-align: justify;
text-indent: 2em;
}
}
}
@keyframes rotate {
to {
transform: rotate(1turn);
}
}
export default {
mounted() {
this.bgStyle = this.$refs.bg.style;
},
methods: {
scroll(e) {
const top = e.target.scrollTop;
if (top <= 250) {
this.bgStyle.setProperty("--scrolly", 250 - top);
} else {
this.bgStyle.setProperty("--scrolly", 0);
}
}
}
};
- 在线演示:[Here] codepen.io/JowayYoung/pen/wvMxdNm
- 在线源码:[Here] github.com/JowayYoung/idea-css/blob/master/icss/src/components/component/%E6%BB%9A%E5%8A%A8%E6%B8%90%E5%8F%98%E8%83%8C%E6%99%AF.vue
作者:JowayYoung
打个小广告
2021 火爆全网的 CSS 架构实战课上线,好评如潮!!!
【课程链接:https://coding.imooc.com/class/501.html 】