CSS变量
总结的开始首先看一个例子:
如图是一个使用CSS3+CSS变量完成的
。
HTML
代码如下:
<div class="navigator">
<ul class="nav_ul">
<li class="nav_item">
<svg t="1580196202692" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="781" width="36" height="36"><path d="M555.541333 117.994667l312.874667 224.565333A117.333333 117.333333 0 0 1 917.333333 437.866667V800c0 64.8-52.533333 117.333333-117.333333 117.333333H640V746.666667c0-70.688-57.312-128-128-128s-128 57.312-128 128v170.666666H224c-64.8 0-117.333333-52.533333-117.333333-117.333333V437.877333a117.333333 117.333333 0 0 1 48.917333-95.317333l312.874667-224.565333a74.666667 74.666667 0 0 1 87.082666 0z" p-id="782" fill="currentColor"></path></svg>
<span class="tip_name">Home</span>
</li>
<li class="nav_item">
<svg t="1580196351612" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1159" width="36" height="36"><path d="M512 85.333333c235.637333 0 426.666667 191.029333 426.666667 426.666667S747.637333 938.666667 512 938.666667 85.333333 747.637333 85.333333 512 276.362667 85.333333 512 85.333333z m149.162667 222.901334L444.16 386.357333a96 96 0 0 0-57.802667 57.813334l-78.122666 216.992a42.666667 42.666667 0 0 0 54.602666 54.602666l217.002667-78.122666a96 96 0 0 0 57.802667-57.813334l78.122666-216.992a42.666667 42.666667 0 0 0-54.602666-54.602666zM512 565.333333a53.333333 53.333333 0 1 0 0-106.666666 53.333333 53.333333 0 0 0 0 106.666666z" p-id="1160" fill="currentColor"></path></svg>
<span class="tip_name">Explore</span>
</li>
<li class="nav_item">
<svg t="1580196428669" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2609" width="30" height="30"><path d="M335.008 916.629333c-35.914667 22.314667-82.88 10.773333-104.693333-25.557333a77.333333 77.333333 0 0 1-8.96-57.429333l46.485333-198.24a13.141333 13.141333 0 0 0-4.021333-12.864l-152.16-132.586667c-31.605333-27.52-35.253333-75.648-8.234667-107.733333a75.68 75.68 0 0 1 51.733333-26.752L354.848 339.2c4.352-0.362667 8.245333-3.232 10.026667-7.594667l76.938666-188.170666c16.032-39.2 60.618667-57.92 99.52-41.461334a76.309333 76.309333 0 0 1 40.832 41.461334l76.938667 188.16c1.781333 4.373333 5.674667 7.253333 10.026667 7.605333l199.712 16.277333c41.877333 3.413333 72.885333 40.458667 69.568 82.517334a76.938667 76.938667 0 0 1-26.08 51.978666l-152.16 132.586667c-3.541333 3.082667-5.141333 8.074667-4.021334 12.853333l46.485334 198.24c9.621333 41.013333-15.36 82.336-56.138667 92.224a75.285333 75.285333 0 0 1-57.525333-9.237333l-170.976-106.24a11.296 11.296 0 0 0-12.010667 0l-170.986667 106.24z" p-id="2610" fill="currentColor"></path></svg>
<span class="tip_name">Collection</span>
</li>
<li class="nav_item">
<svg t="1580196480651" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2891" width="30" height="30"><path d="M512 85.333333c235.637333 0 426.666667 191.029333 426.666667 426.666667S747.637333 938.666667 512 938.666667 85.333333 747.637333 85.333333 512 276.362667 85.333333 512 85.333333z m0 586.666667a32 32 0 1 0 0 64 32 32 0 0 0 0-64z m-2.517333-373.333333c-48.416 0-92.746667 24.16-118.613334 63.413333a137.088 137.088 0 0 0-15.978666 33.237333 32 32 0 0 0 60.906666 19.690667c2.016-6.24 4.885333-12.202667 8.522667-17.717333C458.4 375.914667 482.709333 362.666667 509.482667 362.666667 552.277333 362.666667 586.666667 396.266667 586.666667 437.333333s-34.4 74.666667-77.194667 74.666667a32 32 0 0 0-32 32v64a32 32 0 0 0 64 0v-35.584C603.946667 558.197333 650.666667 503.232 650.666667 437.333333c0-76.757333-63.381333-138.666667-141.194667-138.666666z" p-id="2892" fill="currentColor"></path></svg>
<span class="tip_name">Help</span>
</li>
</ul>
</div>
CSS
代码如下:
body{
height: 100vh;
background-color: #eceffc;
display: flex;
align-items: center;
justify-content: center;
}
.nav_ul {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
list-style-type: none;
}
.navigator {
--nav-width: 600px;
--nav-item-width: calc(var(--nav-width) / 4 );
--nav-overlay-width: calc(var(--nav-item-width));
--active-index: 0;
position: relative;
width: var(--nav-width);
height: 150px;
background: white;
border: 1em solid white;
border-radius: 5% 5% 15% 15% / 15% 15% 50% 50%;
overflow: hidden;
}
.nav_item {
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
flex-direction: column;
width: var(--nav-item-width);
height: 100%;
color: #0288d1;
cursor: pointer;
transition: 0.5s ease;
}
.navigator::after{
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
width: var(--nav-overlay-width);
height: 100%;
background: #b3e5fc;
transition: 0.2s ease;
transform: translateX(0px);
box-sizing: border-box;
/*! margin-left: 30px; */
transform: translateX(calc(var(--nav-item-width) * var(--active-index)));
border-radius: 20px;
}
.nav_item span{
opacity: 0;
transition: 0.6s ease;
}
.active span{
opacity: 1;
}
JS
代码如下:
window.onload = function(){
nav = document.querySelector(".navigator")
navItems = document.querySelectorAll("li.nav_item")
navItems.forEach(function(navItem,activeIndex){
navItem.addEventListener("click",function(){
console.log("click")
navItems.forEach(function(item){
return item.classList.remove("active")
})
navItem.classList.add("active")
nav.style.setProperty("--active-index",activeIndex)
})
})
}
这里主要CSS动画
为:
transition: 0.2s ease;
transform: translateX(0px);
形成蓝色块的代码为:
.navigator::after{
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
width: var(--nav-overlay-width);
height: 100%;
background: #b3e5fc;
transition: 0.2s ease;
transform: translateX(0px);
box-sizing: border-box;
/*! margin-left: 30px; */
transform: translateX(calc(var(--nav-item-width) * var(--active-index)));
border-radius: 20px;
}
这里就是通过在四个tab的父元素设置一个after伪类
来形成的,有一定的宽度,初始是靠在左侧的。
那么如何运动的呢?这里就要提到CSS变量
。移动原理相关的CSS代码如下:
transform: translateX(calc(var(--nav-item-width) * var(--active-index)));
translateX
可以使块进行水平移动,如果能让translateX
里边的参数能在点击触发以后都移动一定的距离,这不就动起来了!这里移动的原理就是使用CSS函数
中的calc
方法和var
方法。以下是详细一点的分析。
- 字典之中有个单词是calculate,就是计算的意思。从这里可以看出
calc
是用来计算 。 var
同样,就是取自variable,也就是变量的意思。那他作为一个方法,意思很明显了,就是用来取变量的,也就是参数所代表的值。如下:
var(–nav-item-width)
这里就是取--nav-item-width
的值了。他是什么呢?
再往上找就可以看到他的定义:
–nav-item-width: calc(var(–nav-width) / 4 );
这里可以看到--nav-item-width
同样包含了一层的计算,这里表明:变量的值是可以嵌套var函数的。到了这里,也可以发现变量前边都是有两杠的。这就是CSS变量定义的格式。那么为什么的不用其他呢?因为 $variable
已经被SASS用了,而@variable
被Less用了。
继续上述的例子。从找到的式子可以看到其中还包含了一层运算,其中还有以一个变量--nav-width
。那就再找到–nav-width
.
–nav-width: 600px;
这里就找到一个准确的值,变量的简单定义就是直接定义一个值。那既然var
是获取变量的值,现在知道了这个变量的值。那么就可以知道这种结论:var函数会返回原本定义的值
var(–nav-width) == 600px
那么上述的例子就可以这么转化:
–nav-item-width: calc(var(–nav-width) / 4 ) => --nav-item-width: calc(600px / 4 )
从var
的使用得到了上述的结果。可以看到括号中还有一个600px / 4
看上去就是一个除法的运算。这个时候就是calc
发挥作用的时候,就像他的名字一样,对变量进行了计算并将结果返回。于是得到如下的等价结果:
–nav-item-width: calc(600px / 4 ) => --nav-item-width: calc(150px ) => --nav-item-width: 150px
这里就成功将--nav-item-width
设置成了150px。所以,总结以上:
- 自定义变量中前边是有两条杠的
- 变量可以直接赋值,也同样支持嵌套
var
可用来获取变量的值并将值进行返回calc
可以用来进行算数运算,并将结果返回
注意事项:
calc
函数进行运算,其中运算符号两侧是需要有空格的,不然是无效的。
例子补充
1. var
可以返回变量指向的值,可以用来字符串拼接
//HTML
<body>
<div class="test"></div>
</body>
//CSS
.test{
width: 100px;
height: 100px;
border: 1px solid grey;
}
.test::after{
--test-str: "hello";
content: var(--test-str)+"world";
}
是按JS
的方式进行拼接么?明显是不行的
正确的应该是这样:
.test::after{
--test-str: "hello";
content: var(--test-str)"world";
}
2. 那除了字符串还能进行其他值的拼接么?
// HTML
<body>
<div class="test"></div>
</body>
// CSS
.test{
--test-width: 100;
width: var(--test-width)px;
height: 100px;
border: 1px solid grey;
}
从结果上看也是不可以的。
这里在补充一点:
.test{
width: "100px";
height: 100px;
border: 1px solid grey;
}
从结果上看,这样的形式也是不可以的。也就是说,通过var
函数进行字符串拼接而来的数值设置给属性也是无效的。
那么如何在只拥有数值的情况下进行赋值呢。这里可以通过calc
方法进行赋值。
如下:
.test{
--test-width: 100;
width: calc(var(--test-width) * 1px);
height: 100px;
border: 1px solid grey;
}
3. 既然用到var
去设置变量的值,那么要是失效了会怎样呢?有 默认值吗?
// HTML
<body>
<div class="test"></div>
</body>
// CSS
.test{
--test-width: 100;
width: var(--test-width,100px);
height: 100px;
border: 1px solid grey;
}
结果:
不是说有默认值么?事实上该值**只有在变量缺失的时候作为返回值的。**这个值称为 回调值
.test{
/* --test-width: 100; */
width: var(--test-width,100px);
height: 100px;
border: 1px solid grey;
}
结果:
补充:
3.1 如果设置了多个回调值会怎样呢?如下
// 形式一
.test{
/* --test-width: 100; */
width: var(--test-width,100,200px);
height: 100px;
border: 1px solid grey;
}
// 形式二
.test{
/* --test-width: 100; */
width: var(--test-width,100px,200px);
height: 100px;
border: 1px solid grey;
}
二者的结果都是:
这里的原因就是var
函数中分为两个参数,第一个参数就是我们正常设置的,第二个参数就是回调的,二者之间是通过逗号隔开的。也就是说逗号以后的整个语句就是一个回调函数。
3.2 var
回调值是逗号以后的值,但是也是支持嵌套的。如下:
.test{
/* --test-width: 100; */
width: var(--test-width,var(--test,100px));
height: 100px;
border: 1px solid grey;
}
同样也是在参数缺省的时候才发挥作用。
4 为什么在设置里变量的基础上使用回调值会失败呢?这里就说明一下。css变量
的灵活是它的优点,因为在任何地方,你都可以通过var
函数进行调用,这么做的好处是什么呢?例如要给产品做个换肤的功能,使用css变量
就可以将这些跟皮肤相关的变量就可以统一设置在一个地方,换肤的时候就可以直接修改相应的值,而不是一个个查找(在仅仅使用css
实现的情况下)。
但是使用var
也同样是他的一个缺点,因为你只要定义了这个变量,但是浏览器是不知道你在哪里会调用他的,所以只要你定义了,它就会认为你有效,这里的一个坏处就是忽略了上下文。什么意思呢?这里首先看一个对比情况。
// HTML
<body>
<div class="container">
<div class="test"></div>
</div>
</body>
// CSS
情况一
.test{
width: 20px;
width: 100px;
height: 100px;
border: 1px solid grey;
}
情况二
.test{
--width: 100px;
width: 100px;
width: var(--width);
height: 100px;
border: 1px solid grey;
}
情况一结果:
情况二结果:
这里貌似都没有毛病,但是这里都是在值都是有效的情况下的。再来看看两种情况。
// HTML
<body>
<div class="container">
<div class="test"></div>
</div>
</body>
// CSS
情况一
.test{
width: 100px;
width: red;
height: 100px;
border: 1px solid grey;
}
情况二
.test{
--width: red;
width: 100px;
width: var(--width);
height: 100px;
border: 1px solid grey;
}
情况一结果:
可以看到情况一是正常设置两个width
属性,在发现第二个width
失效了以后,立即将其设置为无效,从上一个例子中,可以知道当第二个值有效的情况下是设置第二个值的。再来看看情况二的结果:
!
.test{
--width: red;
width: 100px;
width: var(--width);
height: 100px;
border: 1px solid grey;
}
情况二的结果就有点出人意料了,使用了var
函数将相同的值设置在同样额位置,但是上文的width
却出现了无效的结果。这里就会产生一个无效的计算时间,因为css变量
是处处有效,在这里更是忽略了上文的width
导致一些“浪费”和出人意料的结果。
5. 那么对4中的无效情况又如何处理呢?
这里对于第二种情况,在test类
中,width
属性都失效了。但是可以从父元素中进行继承和使用默认的样式或者内联样式中取到。
.container{
width: 100px;
}
.test{
--width: red;
width: 100px;
width: var(--width);
height: 100px;
border: 1px solid grey;
}
结果:
6. 以上都是介绍css
中使用css变量
的,那么如何而是用js进行操作css变量
呢?
DOM:setProperty
getPropertyValue
// 设置
var data = document.querySelector('div.test')
data.style.setProperty('--width','100px')
结果:
从上图中可以看到成功设置上了相应的数值,并且是设置到了内联样式中。
这里也是确实有效果的。
从上述中可以看到,结果是设置在内联样式中的,那么可以直接设置么?
var obj = document.querySelector('div.test')
obj.style['--width'] = '100px'
结果:
甚至连影子也是找不到。
或许会想到为什么不用obj.style.--width
呢,明显不行的,因为不符合变量要求。
那么还有其他办法么?是有的。
第一种: setAttribute
var obj = document.querySelector('div.test')
obj.setAttribute('style','--width:100px')
第二种:addRule
var style = document.querySelector('style')
var sheet = style.sheet
sheet.addRule('div.test','--width:100px')
第三种: insertRule
var style = document.querySelector('style')
var sheet = style.sheet
sheet.insertRule('div.test {--width:100px}',0)
上述经过测试都是可行的。在这里补充一点第二和第三种方法是通过在内联样式表中进行插入样式,所以html
文件中必须创建style
标签。
再看获取: getPropertyValue
// 设置
var data = document.querySelector('div.test')
data.style.getPropertyValue('--width')
结果:
出现获取不到的情况,getPropertyValue
获取不到值是什么原因呢?
从setProperty
中可以看出一点眉目,设置是设置在内联样式中的,那么获取是不是也是获取内联样式中的呢?
这里尝试一下:
<div class="test" style="--width:100px"></div>
结果:
所以getPropertyValue
仅仅是获取内联样式中的属性。
那么如何进行获取内联样式表中的css变量
呢?代码如下:
var obj = document.querySelector('div.test')
var cssStyles = window.getComputedStyle(obj,null)
var width = cssStyles.getPropertyValue('--width')
通过上述代码可以获取在火狐浏览器和谷歌浏览器。
以上方法都是获取在样式中的自定义变量的值
通过jquery去获取:通过jquery属性的值,首先会想到,既然是内联的样式,那么可不可以通过css
方法进行获取呢。尝试一下。
// HTML
<div class="container">
<div class="test" style="--width:100px"></div>
</div>
var $obj = $('div.test')
$obj.css('--width')
从结果可以看出,即使在设置了内联样式中的--width
也是不可行的。从上述的DOM中可以得到一些启发就是可以操作属性对象去获取相应的值。这里就用到attr
方法。
<div class="test" style="--width:100px"></div>
var $obj = $('div.test')
$obj.attr('style').split(':')[1]
因为获取的style
是一个字符串,所以对字符串进行分割。就可以得到--width
的值了。
初次以外还有一个方法:就是使用跟attr
很相似的prop
方法:
var $obj = $('div.test')
$obj.prop('style')
结果:
从图中可以看到并没有获得先gattr
那样返回的字符串,而是返回了一个DOM兑对象。那么就可以使用DOM的getPropertyValue
进行获取他的值。详细参考上述。
第三种方法就是: 转换成DOM,然后对DOM进行操作。
通过jquery去设置:
1. 从上述中使用css
方法进行获取是不可能的了,所以设置也是不可行的。
2. 通过attr
方法设置
var $obj = $('div.test')
$obj.attr('style',"--width:100px")
3. 通过prop
方法设置:
var $obj = $('div.test')
$obj.prop('style',"--width:100px")
CSS Custom Properties for Cascading Variables Module Level 1
(需要翻墙)