이 문서에서는 CSS 변수를 이해하고, CSS 변수의 사용법을 소개하고, CSS 변수를 능숙하게 사용하여 CSS를 더욱 흥미롭고 프로젝트를 더욱 멋지게 만드는 방법을 알아봅니다!
CSS 변수를 CSS 사용자 정의 속성이라고도 합니다. 소수의 사람들이 사용하는 것이 갑자기 언급되는 이유는 무엇입니까? 최근 개인 공식 홈페이지를 개편하다 보니 왜 갑자기 CSS 변수를 사용하게 되는지 모르겠네요. 그 숨겨진 매력에 감탄하게 되는 건지도 모르겠습니다.
CSS에서 변수가 사용되는 이유에 대해 이야기하면, 예를 들어보면 누구나 한 눈에 이해할 수 있을 것입니다.
/* 不使用CSS变量 */ .title { background-color: red; } .desc { background-color: red; } /* 使用CSS变量 */ :root { --bg-color: red; } .title { background-color: var(--bg-color); } .desc { background-color: var(--bg-color); }
이 글을 읽고 나면 CSS 변수를 사용한 코드의 양이 조금 과하다는 생각이 들 수도 있겠지만, 어느 날 사악한 기획자 형과 디자인 소녀가 갑자기 만들고 싶다고 말한 적이 있습니까? 피부 변화 기능. 일반적인 생각에 따르면 일부 학생들은 아마도 기본 색상 테마
에 따라 해당 새 색상 테마
CSS 파일을 추가할 것입니다. 새로운 요구 사항이 있을 때마다 여러 테마 색상 세트를 동시에 유지하는 것은 번거로운 일입니다. 默认颜色主题
增加一份对照的新颜色主题
CSS文件。这样每次新增需求都同时维护几套主题颜色多麻烦啊。
此时CSS变量就派上用场了,提前跟设计小姐姐规范好各种需要变换的颜色并通过CSS变量进行定义,通过JS批量操作这些定义好的CSS变量即可。这也是变换主题颜色的一种解决方案之一,好处在于只需写一套CSS代码。
["red", "blue", "green"].forEach(v => { const btn = document.getElementById(`${v}-theme-btn`); btn.addEventListener("click", () => document.body.style.setProperty("--bg-color", v)); });
在此总结下CSS使用变量的好处:
可能有些同学会问,Sass和Less早就实现了变量这个特性,何必再多此一举呢。可是细想一下,CSS变量对比Sass和Less的变量,又有它的过人之处。
本来打算用一半篇幅讲述CSS变量的规范和用法,但是网上一搜一大把就感觉没必要了,贴上阮一峰老师写的教程《CSS变量教程》。同时笔者也对CSS变量的细节地方进行一个整理,方便大家记忆。
--变量名
<li>读取:var(--变量名, 默认值)
<li>类型属性值
不能用作属性名
<li>字符:与字符串拼接 "Hello, "var(--name)
<li>数值:使用calc()
与数值单位连用 var(--width) * 10px
当前元素块作用域
及其子元素块作用域
下有效
<li>优先级别:内联样式 > ID选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器
接下来使用几个特别的场景展示CSS变量的魅力。还是那句话,一样东西有使用的场景,那自然就会有它的价值,那么用的人也会越来越多。
其实CSS变量有一个特别好用的场景,那就是结合List元素集合使用。如果不明白这是什么,请继续往下看。
以下所有演示代码基于vue文件,但HTML、CSS和JS分开书写,为了简化CSS的书写而使用Sass进行预处理,方便代码演示
条形加载条
一个条形加载条通常由几条线条组成,并且每条线条对应一个存在不同时延的相同动画,通过时间差运行相同的动画,从而产生加载效果。估计大部分的同学可能会把CSS代码写成以下这样。
<ul class="strip-loading flex-ct-x"> <li v-for="v in 6" :key="v"></li> </ul>
.loading { width: 200px; height: 200px; li { border-radius: 3px; width: 6px; height: 30px; background-color: #f66; animation: beat 1s ease-in-out infinite; & + li { margin-left: 5px; } &:nth-child(2) { animation-delay: 200ms; } &:nth-child(3) { animation-delay: 400ms; } &:nth-child(4) { animation-delay: 600ms; } &:nth-child(5) { animation-delay: 800ms; } &:nth-child(6) { animation-delay: 1s; } } }
分析代码发现,每个<li>
只是存在animation-delay
不同,而其余代码则完全相同,换成其他类似的List元素集合场景,那岂不是有10个<li>
就写10个:nth-child
。
显然这种方法不灵活也不容易封装成组件,如果能像JS那样封装成一个函数,并根据参数输出不同的样式效果,那就更棒了。说到这里,很明显就是为了铺垫CSS变量的开发技巧了。
对于HTML部分的修改,让每个<li>
拥有一个自己作用域下的CSS变量。对于CSS部分的修改,就需要分析哪些属性是随着index
이때 CSS 변수
<ul class="strip-loading flex-ct-x"> <li v-for="v in 6" :key="v" :style="`--line-index: ${v}`"></li> </ul>🎜다음은 CSS에서 변수를 사용할 때의 이점을 요약한 것입니다: 🎜
--변수 이름
<li>읽기: var(--변수 이름, 기본값)
<li>유형속성 값
으로만 사용할 수 있고 속성 이름
으로 사용할 수 없음
<li>문자: 및 string Splicing "Hello, "var(--name)
<li>숫자 값: 숫자 단위 var(-와 함께 <code>calc()
사용 -width ) * 10px
현재 요소 블록 범위
및 해당 하위 요소 블록 범위에서 유효함
<li>우선순위: 인라인 스타일> ID 선택기> 클래스 선택기 = 속성 선택기 = 의사 클래스 선택기> code>
.strip-loading { width: 200px; height: 200px; li { --time: calc((var(--line-index) - 1) * 200ms); border-radius: 3px; width: 6px; height: 30px; background-color: #f66; animation: beat 1.5s ease-in-out var(--time) infinite; & + li { margin-left: 5px; } } }🎜🎜바 로딩 바🎜🎜🎜바 로딩 바는 일반적으로 여러 줄로 구성되며 각 줄은 서로 다른 지연에 해당합니다. 동일한 애니메이션은 시간차를 통해 로딩 효과를 생성합니다. 대부분의 학생들은 다음과 같이 CSS 코드를 작성할 것으로 추정됩니다. 🎜🎜🎜
/* flex属性无效 */ .loading { display: flex; align-items: center; flex: var(--line-index); }
<div class="heart-loading flex-ct-x"> <ul style="--line-count: 9;"> <li v-for="v in 9" :key="v" :class="`line-${v}`" :style="`--line-index: ${v}`"></li> </ul> </div>🎜 코드를 분석한 결과 각
<li>
는 animation-delay
만 다른 것으로 나타났으며, 나머지 코드는 완전히 동일한 것으로 나타났습니다. 다른 유사한 List 요소 수집 시나리오로 대체하면 10개의 <li>
가 있는 경우 10개의 :nth-child
를 작성하는 대신 어떻게 될까요? 🎜🎜분명히 이 방법은 유연하지 않고 쉽게 컴포넌트로 캡슐화할 수 없습니다. JS와 같은 함수로 캡슐화하고 매개변수에 따라 다양한 스타일 효과를 출력할 수 있다면 더욱 좋을 것입니다. 이렇게 말하면 🎜CSS 변수🎜 개발 기술의 길을 닦는 것이 분명합니다. 🎜🎜HTML 부분을 수정하려면 각 <li>
가 자체 범위에 🎜CSS 변수🎜를 갖도록 하세요. CSS 부분을 수정하려면 index
가 증가함에 따라 어떤 속성이 정기적으로 변경되는지 분석해야 합니다. 🎜CSS 변수🎜 표현식을 사용하여 정기적으로 변경되는 부분을 교체하세요. 🎜<ul class="strip-loading flex-ct-x"> <li v-for="v in 6" :key="v" :style="`--line-index: ${v}`"></li> </ul>
.strip-loading { width: 200px; height: 200px; li { --time: calc((var(--line-index) - 1) * 200ms); border-radius: 3px; width: 6px; height: 30px; background-color: #f66; animation: beat 1.5s ease-in-out var(--time) infinite; & + li { margin-left: 5px; } } }
代码中的变量--line-index
和--time
使每个<li>
拥有一个属于自己的作用域。例如第2个<li>
,--line-index
的值为2,--time
的计算值为200ms
,换成第3个<li>
后这两个值又会不同了。
这就是CSS变量的作用范围所致(在当前元素块作用域及其子元素块作用域下有效
),因此在.strip-loading
的块作用域下调用--line-index
是无效的。
/* flex属性无效 */ .loading { display: flex; align-items: center; flex: var(--line-index); }
通过妙用CSS变量,也把CSS代码从29行
缩减到15行
,对于那些含有List元素集合越多的场景,效果就更明显。而且这样写也更加美观更加容易维护,某天说加载效果的时间差不明显,直接将calc((var(--line-index) - 1) * 200ms)
里的200ms
调整成400ms
即可。就无需对每个:nth-child(n)
进行修改了。
心形加载条
前段时间刷掘金看到陈大鱼头兄
的心形加载条,觉得挺漂亮的,很带感觉。
通过动图分析,发现每条线条的背景色和动画时延不一致,另外动画运行时的高度也不一致。细心的你可能还会发现,第1条和第9条的高度一致,第2条和第8条的高度一致,依次类推,得到高度变换相同类
的公式:对称index = 总数 + 1 - index
。
背景色使用了滤镜的色相旋转hue-rotate
函数,目的是为了使颜色过渡得更加自然;动画时延的设置和上面条形加载条
的设置一致。下面就用CSS变量根据看到的动图实现一番。
<div class="heart-loading flex-ct-x"> <ul style="--line-count: 9;"> <li v-for="v in 9" :key="v" :class="`line-${v}`" :style="`--line-index: ${v}`"></li> </ul> </div>
.heart-loading { width: 200px; height: 200px; ul { display: flex; justify-content: space-between; width: 150px; height: 10px; } li { --Θ: calc(var(--line-index) / var(--line-count) * .5turn); --time: calc((var(--line-index) - 1) * 40ms); border-radius: 5px; width: 10px; height: 10px; background-color: #3c9; filter: hue-rotate(var(--Θ)); animation-duration: 1s; animation-delay: var(--time); animation-iteration-count: infinite; } .line-1, .line-9 { animation-name: line-move-1; } .line-2, .line-8 { animation-name: line-move-2; } .line-3, .line-7 { animation-name: line-move-3; } .line-4, .line-6 { animation-name: line-move-4; } .line-5 { animation-name: line-move-5; } }
一波操作后就有了下面的效果。和陈大鱼头兄
的心形加载条对比一下,颜色、波动曲线和跳动频率有点不一样,在暖色调的蔓延和肾上腺素的飙升下,这是一种心动的感觉。想起自己曾经写的一首诗:我见犹怜,爱不释手,雅俗共赏,君子好逑
。
标签导航栏
上面通过两个加载条演示了CSS变量在CSS中的运用以及一些妙用技巧,现在通过标签导航栏演示CSS变量在JS中的运用。
JS中主要有3个操作CSS变量的API,看上去简单易记,分别如下:
elem.style.getPropertyValue()
<li>设置变量:elem.style.setProperty()
<li>删除变量:elem.style.removeProperty()
先上效果图,效果中主要是使用CSS变量标记每个Tab的背景色和切换Tab的显示状态。
<div class="tab-navbar"> <nav> <a v-for="(v, i) in list" :key="v" :class="{ active: index === i }" @click="select(i)">标题{{i + 1}}</a> </nav> <div> <ul ref="tabs" :style="`--tab-count: ${list.length}`"> <li v-for="(v, i) in list" :key="v" :style="`--bg-color: ${v}`">内容{{i + 1}}</li> </ul> </div> </div>
.tab-navbar { display: flex; overflow: hidden; flex-direction: column-reverse; border-radius: 10px; width: 300px; height: 400px; nav { display: flex; height: 40px; background-color: #f0f0f0; line-height: 40px; text-align: center; a { flex: 1; cursor: pointer; transition: all 300ms; &.active { background-color: #66f; font-weight: bold; color: #fff; } } } div { flex: 1; ul { --tab-index: 0; --tab-width: calc(var(--tab-count) * 100%); --tab-move: calc(var(--tab-index) / var(--tab-count) * -100%); display: flex; flex-wrap: nowrap; width: var(--tab-width); height: 100%; transform: translate3d(var(--tab-move), 0, 0); transition: all 300ms; } li { display: flex; justify-content: center; align-items: center; flex: 1; background-color: var(--bg-color); font-weight: bold; font-size: 20px; color: #fff; } } }
export default { data() { return { index: 0, list: ["#f66", "#09f", "#3c9"] }; }, methods: { select(i) { this.index = i; this.$refs.tabs.style.setProperty("--tab-index", i); } } };
在<ul></ul>
上定义--tab-index
表示Tab当前的索引,当点击按钮时重置--tab-index
的值,就可实现不操作DOM来移动<ul></ul>
的位置显示指定的Tab。不操作DOM而可移动<ul></ul>
是因为定义了--tab-move
,通过calc()
计算--tab-index
与--tab-move
的关系,从而操控transform: translate3d()
来移动<ul></ul>
。
另外在<li>
上定义--bg-color
表示Tab的背景色,也是一种比较简洁的模板赋值方式,总比写<li :style="backgroundColor: ${color}">
要好看。如果多个CSS属性依赖一个变量赋值,那么使用CSS变量赋值到style上就更方便了,那些CSS属性可在CSS文件里进行计算与赋值,这样可帮助JS分担一些属性计算工作。
当然,这个标签导航栏也可通过纯CSS实现,有兴趣的同学可看看笔者之前一篇文章里的纯CSS标签导航栏。
悬浮跟踪按钮
通过几个栗子实践了CSS变量在CSS和JS上的运用,相信大家已经掌握了其用法和技巧。之前在某个网站看过一个比较酷炫的鼠标悬浮特效,好像也是使用CSS变量实现的。笔者凭着记忆也使用CSS变量实现一番。
其实思路也比较简单,先对按钮进行布局和着色,然后使用伪元素标记鼠标的位置,定义--x
和--y
表示伪元素在按钮里的坐标,通过JS获取鼠标在按钮上的offsetLeft
和offsetLeft
分别赋值给--x
和--y
,再对伪元素添加径向渐变的背景色,大功告成,一个酷炫的鼠标悬浮跟踪特效就这样诞生了。
<a class="track-btn pr tac" @mousemove="move"> <span>妙用CSS变量,让你的CSS变得更心动</span> </a>
.track-btn { display: block; overflow: hidden; border-radius: 100px; width: 400px; height: 50px; background-color: #66f; line-height: 50px; cursor: pointer; font-weight: bold; font-size: 18px; color: #fff; span { position: relative; } &::before { --size: 0; position: absolute; left: var(--x); top: var(--y); width: var(--size); height: var(--size); background-image: radial-gradient(circle closest-side, #09f, transparent); content: ""; transform: translate3d(-50%, -50%, 0); transition: all 200ms ease; } &:hover::before { --size: 400px; } }
export default { name: "track-btn", methods: { move(e) { const x = e.pageX - e.target.offsetLeft; const y = e.pageY - e.target.offsetTop; e.target.style.setProperty("--x", `${x}px`); e.target.style.setProperty("--y", `${y}px`); } } };
其实可结合鼠标事件来完成更多的酷炫效果,例如动画关联
、事件响应
等操作。没有做不到,只有想不到,尽情发挥你的想象力啦。
之前在CodePen上还看到一个挺不错的栗子,一个悬浮视差按钮,具体代码涉及到一些3D变换的知识。看完源码后,按照其思路自己也实现一番,顺便对代码稍加改良并封装成Vue组件,存放到本课件示例代码中。感觉录制的GIF有点别扭,显示效果不太好,有兴趣的同学可下载本课件示例代码,自己运行看看效果。
对于现代浏览器来说,CSS变量的兼容性其实还是蛮好的,所以大家可放心使用。毕竟现在都是各大浏览器厂商快速迭代的时刻,产品对于用户体验来说是占了很大比重,因此在条件允许的情况下还是大胆尝新,不要被一些过去的所谓的规范所约束着。
试问现在还有多少人愿意去维护IE6~IE9的兼容性,如果一个产品的用户体验受限于远古浏览器的压制(可能政务Web应用和金融Web应用除外吧
),相信这个产品也不会走得很远。
我们在完成一个产品的过程中,不仅仅是为了完成工作任务,如果在保证进度的同时能花点心思点缀一下,可能会有意外的收获。用心写好每一段代码,才是享受写代码的真谛。
本文通过循序渐进的方式探讨了CSS变量的运用和技巧,对于一个这么好用的特性,当然是不能放过啦。其实多多思考,就能把CSS变量用在很多场景上。
更多编程相关知识,请访问:编程入门!!
위 내용은 CSS 변수를 능숙하게 사용하여 프로젝트를 더욱 멋지게 만드세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!