SS变量(又名自定义属性)已在Web浏览器中支持了近四年。我一般也会根据项目情况使用它们。它们非常有用且易于使用,但是前端开发人员通常可能会误用或误解它们。
CSS变量是在CSS文档中定义的值,其目的是可重用性并减少CSS值中的冗余。下面是一个基本示例。
.section {
border: 2px solid #235ad1;
}
.section-title {
color: #235ad1;
}
.section-title::before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-color: #235ad1;
}
在此代码段中,#235ad1使用了3次。想象一下,对于一个大型项目,不同的CSS文件,如果哪天被要求更改颜色。我们可以做的最好快的方式就是“查找并替换”。
使用CSS变量,可以更快解决这个问题。定义变量名需要用--开头。首先,我们现在将在:root或<html>元素中定义变量。
:root {
--color-primary: #235ad1;
}
.section {
border: 2px solid var(--color-primary);
}
.section-title {
color: var(--color-primary);
}
.section-title::before {
/* Other styles */
background-color: var(--color-primary);
}
是不是比前面的干净得多?--color-primary变量是全局变量,因为我们在:root元素中定义了它。但是,我们还可以将变量范围限定到整个文档中的某些元素。
与编程语言命名变量相似,CSS 变量的有效命名应包含字母数字字符,下划线和破折号。另外,值得一提的是 CSS 变量区分大小写。
/* 合法命名 */
:root {
--primary-color: #222;
--_primary-color: #222;
--12-primary-color: #222;
--primay-color-12: #222;
}
/* 非法命名 */
:root {
--primary color: #222; /* Spacings are not allowed */
--primary$%#%$#
}
CSS 变量也有自己的作用域,这个概念类似于其他编程语言。以 JS 为例:
:root {
--primary-color: #235ad1;
}
.section-title {
--primary-color: d12374;
color: var(--primary-color);
}
变量element是全局的,因此可以在cool()函数内部访问。但是,只能在cool()函数中访问变量otherElement。
:root {
--primary-color: #235ad1;
}
.section-title {
--primary-color: d12374;
color: var(--primary-color);
}
变量--primary-color是全局变量,可以从文档中的任何地方访问。变量--primary-color由于是在.section-title定义的,所以只能在.section-title中访问。
下面是一个比较直观的示例图片,可以加强我们的理解:
变量--primary-color用于标题颜色。我们想为作者名和最新文章标题自定义颜色,因此我们需要将--primary-color覆盖。这同样适用于--unit变量。
/* 全局变量 */
:root {
--primary-color: #235ad1;
--unit: 1rem;
}
/* section-title 默认的颜色和间距 */
.section-title {
color: var(--primary-color);
margin-bottom: var(--unit);
}
/* 覆盖 section-title 样式 */
.featured-authors .section-title {
--primary-color: #d16823;
}
.latest-articles .section-title {
--primary-color: #d12374;
--unit: 2rem;
}
这里的回退不是不支持 CSS 变量的回退,而是 CSS 变量可以支持回退方案。考虑以下示例:
.section-title {
color: var(--primary-color, #222);
}
注意,var()有多个值。第二个#221只在变量--primary-color由于某种原因没有定义的情况下有效。不仅如此,我们还可以将var()嵌套到另一个var()中。
.section-title {
color: var(--primary-color, var(--black, #222));
}
在变量值依赖于某个动作的情况下,该特性非常有用。当变量没有值时,为它提供一个回退很重要。
在设计系统中,按钮通常有多种尺寸。通常,按钮可以具有三种尺寸(Small, normal, large)。使用 CSS 变量来实现它并不容易:
.button {
--unit: 1rem;
padding: var(--unit);
}
.button--small {
--unit: 0.5rem;
}
.button--large {
--unit: 1.5rem;
}
通过在按钮组件作用域内更改变量--unit,我们创建了按钮的不同变体。
HSL代表色调,饱和度,亮度。色相的值决定了颜色,饱和度和亮度值可以控制颜色的深浅。
:root {
--primary-h: 221;
--primary-s: 71%;
--primary-b: 48%;
}
.button {
background-color: hsl(var(--primary-h), var(--primary-s), var(--primary-b));
transition: background-color 0.3s ease-out;
}
/* 使背景更暗 */
.button:hover {
--primary-b: 33%;
}
这里何通过减小变量--primary-b使按钮变暗。
如果您使用过Photoshop,Sketch,Figma或Adobe XD之类的设计程序,那么我们会想在调整元素大小的同时按住Shift键以避免扭曲它。
在CSS中,没有直接的方法来做到这一点,但是我们有一个简单的解决方法,使用CSS变量。
假设有一个图标,并且其宽度和高度应该相等。我定义了变量--size,用于宽度和高度。
.icon {
--size: 22px;
width: var(--size);
height: var(--size);
}
现在,您只需更改--size变量的值即可模拟Shift调整大小的效果。
CSS 变量对于网格非常有用。假设希望网格容器根据定义的首选宽度显示其子项。与为每个变体创建类并复制CSS相比,使用变量更容易做到这一点。
.wrapper {
--item-width: 300px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
grid-gap: 1rem;
}
.wrapper-2 {
--item-width: 500px;
这样,我们可以创建一个完整的网格系统,该系统灵活,易于维护,并且可以在其他项目中使用。可以将相同的概念应用于grid-gap属性。
wrapper {
--item-width: 300px;
--gap: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
}
.wrapper.gap-1 {
--gap: 16px;
}
以全值表示,例如,类似渐变的东西。如果整个系统中使用渐变或背景,将其存储到CSS变量中可能是一件好事。
:root {
--primary-gradient: linear-gradient(150deg, #235ad1, #23d1a8);
}
.element {
background-image: var(--primary-gradient);
}
或者我们可以存储一个值。以角度为例:
.element {
--angle: 150deg;
background-image: linear-gradient(var(--angle), #235ad1, #23d1a8);
}
.element.inverted {
--angle: -150deg;
}
我们可以在 CSS 变量中包含多个值,这在需要根据特定上下文将元素放置在不同位置的情况下很有用。
.table {
--size: 50px;
--pos: left center;
background: #ccc linear-gradient(#000, #000) no-repeat;
background-size: var(--size) var(--size);
background-position: var(--pos);
}
现在,网站比以往任何时候都更需要深色和浅色模式。使用CSS变量,我们可以存储它们的两个版本,并根据用户或系统偏好在它们之间切换。
:root {
--text-color: #434343;
--border-color: #d2d2d2;
--main-bg-color: #fff;
--action-bg-color: #f9f7f7;
}
/* 添加到`<html>`元素的类*/
.dark-mode {
--text-color: #e9e9e9;
--border-color: #434343;
--main-bg-color: #434343;
--action-bg-color: #363636;
}
在某些情况下,您将需要使用JavaScript设置CSS变量。假设我们需要获取可扩展组件的高度。
变量--details-height-open为空,它将被添加到特定的HTML元素中。当JavaScript由于某种原因失败时,提供适当的默认值或后备值很重要。
.section.is-active {
max-height: var(--details-height-open, auto);
}
auto值是 JS 失败时的回退值,并且没有定义CSS变量——details-height-open。
网站wrapper 可以有多种变化。有时候是需要一个小包装一个页面,一个大包装另一个页面。在这种情况下,合并CSS变量可能是有用的。
.wrapper {
--size: 1140px;
max-width: var(--size);
}
.wrapper--small {
--size: 800px;
}
我们可以在style属性中添加--item-width变量,仅此而已。例如,这种方法可以帮助建立网格原型。
HTML
<div class="wrapper" style="--item-width: 250px;">
<div></div>
<div></div>
<div></div>
</div>
CSS
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
grid-gap: 1rem;
}
事例:https://codepen.io/shadeed/pen/7d3e0d575a5cecb86233fc7d72fa90d4
另一个有用的用例是大小调整元素。假设我们需要四种不同大小的用户头像,并且只能使用一个变量来控制其大小。
<img src="user.jpg" alt="" class="c-avatar" style="--size: 1" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 2" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 3" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 4" />
.c-avatar {
display: inline-block;
width: calc(var(--size, 1) * 30px);
height: calc(var(--size, 1) * 30px);
}
组合CSS变量和媒体查询对于调整整个网站中使用的变量非常有用。我能想到的最简单的示例是更改间距值。
:root {
--gutter: 8px;
}
@media (min-width: 800px) {
:root {
--gutter: 16px;
}
}
使用--gutter变量的任何元素都将根据视口大小更改其间距,这是不是很棒吗?
是的,CSS变量确实继承。如果父元素中定义了CSS变量,那么子元素将继承相同的CSS变量。我们看下面的例子:
HTML
<div class="parent">
<p class="child"></p>
</div>
css
.parent {
--size: 20px;
}
.child {
font-size: var(--size);
}
.child元素可以访问变量--size,因为它从父元素继承了它。很有趣,那它在实际的项目中有啥用呢?
我们有一组以下需求的操作项
HTML
<div class="actions">
<div class="actions__item"></div>
<div class="actions__item"></div>
<div class="actions__item"></div>
</div>
CSS
.actions {
--size: 50px;
display: flex;
gap: calc(var(--size) / 5);
}
.actions--m {
--size: 70px;
}
.actions__item {
width: var(--size);
height: var(--size);
}
请注意,这里是如何将变量--size用于flexbox gap属性的。这意味着间距可以是动态的,并且取决于--size变量。
另一个有用的例子是使用CSS变量继承来定制CSS动画:
@keyframes breath {
from {
transform: scale(var(--scaleStart));
}
to {
transform: scale(var(--scaleEnd));
}
}
.walk {
--scaleStart: 0.3;
--scaleEnd: 1.7;
animation: breath 2s alternate;
}
.run {
--scaleStart: 0.8;
--scaleEnd: 1.2;
animation: breath 0.5s alternate;
}
这样,我们就不需要定义@keyframes两次,它将继承.walk和.run元素的定制CSS 变量。
当var()函数中的CSS变量无效时,浏览器将根据所使用的属性用初始值或继承值替换。
:root {
--main-color: 16px;
}
.section-title {
color: var(--main-color);
}
我使用16px是color属性的值。这是完全错误的。由于color属性是继承的,因此浏览器将执行以下操作:
下面解释浏览器工作的流程图。
我们可能无法控制网页中的所有资源,其中一些必须在线托管。在这种情况下,您可以将链接的URL值存储在CSS变量中。
:root {
--main-bg: url("https://example.com/cool-image.jpg");
}
.section {
background: var(--main-bg);
}
但是,能想知道是否可以使用url()插入 CSS 变量。考虑以下
:root {
--main-bg: "https://example.com/cool-image.jpg";
}
.section {
background: url(var(--main-bg));
}
由于var(--main-bg)被视为url本身,因此无效。当浏览器计算出该值时,该值将不再有效,并且将无法按预期运行。
CSS 变量也可以表示多个值,看下面的例子:
:root {
--main-color: 35, 90, 209;
}
.section-title {
color: rgba(var(--main-color), 0.75);
}
在示例中,我们有一个rgba()函数,并且RGB值存储在CSS变量中,以逗号分隔。如果我们想根据元素调整alpha值,这样做可以提供灵活性。唯一的缺点是无法使用DevTools颜色选择器来调整rgba值。
另一个例子是将它与background属性一起使用。
:root {
--bg: linear-gradient(#000, #000) center/50px;
}
.section {
background: var(--bg);
}
.section--unique {
background: var(--bg) no-repeat;
}
如果你阅读过CSS变量规范,则可能会读到“动画污染”一词。这个想法是,在@keyframes规则中使用CSS变量时,无法对其进行动画处理。
html
<div class="box"></div>
CSS
.box {
width: 50px;
height: 50px;
background: #222;
--offset: 0;
transform: translateX(var(--offset));
animation: moveBox 1s infinite alternate;
}
@keyframes moveBox {
0% {
--offset: 0;
}
50% {
--offset: 50px;
}
100% {
--offset: 100px;
}
}
动画无法顺利进行。它将仅对值 (0, 50px, 100px)进行动画处理。根据CSS规范:
@keyframes规则中使用的任何自定义属性都会受到动画污染,这将影响通过动画属性中的var()函数引用它时如何处理它。
如果我们希望上述动画能够正常工作,则应采用老式的方法。这意味着,我们需要用要设置动画的实际CSS属性替换变量。
@keyframes moveBox {
0% {
transform: translateX(0);
}
50% {
transform: translateX(50px);
}
100% {
transform: translateX(100px);
}
}
你可能不知道可以使用 CSS 变量进行计算。考虑下面示例:
.c-avatar {
display: inline-block;
width: calc(var(--size, 1) * 30px);
height: calc(var(--size, 1) * 30px);
}
.c-avatar 大小会有不同的变化。我将默认值设置为1,所以默认大小为(30px * 30px)。注意不同的类变化以及更改--size值如何导致化身的大小变化。
.c-avatar--small {
--size: 2;
}
.c-avatar--medium {
--size: 3;
}
.c-avatar--large {
--size: 4;
}
我们可以在浏览器DevTools中使用一些有用的技巧,这样就能更轻松地使用CSS变量。
使用CSS变量时,看到颜色或背景值的视觉指示器是否有用?Chrome和Edge证明了这一点。
要查看CSS变量的计算值,只要将鼠标悬停或单击即可。
当我们需要从使用CSS变量的所有元素中禁用CSS变量时,可以通过从定义它的元素中取消选中它来实现。参见下图:
本文介绍了 CSS 变量的很多内容,希望能对你有些帮助,二创不易,还望点个赞+转发。
作者:Ahmad Shadeed 译者:前端小智 来源:ishadeed
原文:https://ishadeed.com/article/css-vars-101/
html的文件结构大家都是知道的了,总体分为head和body部分
我们要实现变色,在head部分实现格式
<style>
.tablex {border-collapse: collapse;}
.tablex tr {}
.tablex tr td {text-align:center; line-height:30px;}
.tablex tr td:hover { background-color:#f00; color:#fff;}
</style>
然后在body部分,使用table时候,注明class="tablex".这样的话,就实现了我们所说的效果了。
附上完整代码:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>测试鼠标移到到表格单元格背景颜色改变的</title>
<style>
.table1 {border-collapse: collapse;}
.table1 tr {}
.table1 tr td {text-align:center; line-height:30px;}
.table1 tr td:hover { background-color:#006030; color:#006030;}
</style>
</head>
<body>
<table class="table1" width="70%" border="1">
<tr>
<td>测试</td>
<td>测试</td>
<td>测试</td>
<td>测试</td>
</tr>
<tr>
<td>测试</td>
<td>测试</td>
<td>测试</td>
<td>测试</td>
</tr>
<tr>
<td>测试</td>
<td>测试</td>
<td>测试</td>
<td>测试</td>
</tr>
<tr>
<td>测试</td>
<td>测试</td>
<td>测试</td>
<td>测试</td>
</tr>
<tr>
<td>测试</td>
<td>测试</td>
<td>测试</td>
<td>测试</td>
</tr>
</table>
</body>
</html>
在任何一个浏览器中运行,效果如下
南大盛联20年来一直致力于高端IT培训--打造高级软件人才实战培训专家,学生对我们的认可是我们一直前进的动力;项目团队全球招聘,特聘来自海外的老师进行任教,采用100%商业项目进行实战培训,线上线下同步进行。
课程全部紧随市场需求进行设计,并且动态进行调整;7天免费试听,0首付开始学习,学完后进行100%推荐就业,不满意工作岗位2次推荐。
选定一个平台,认识一群志同道合的朋友,你的未来人生路必定不一样。
目前已经开设下面这些培训项目
Java培训
安卓培训
JavaWeb培训
Linux培训
云服务器布置培训
HTML5培训
SEO培训
视频剪辑培训
UI培训
欢迎您们分享给自己愿意分享的朋友,大家一起来进步;相互转告,咨询,学习。
南大盛联培训理念:我懂,我也能让你懂。
今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。
这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。
以下是本文所涉及到的知识点,break or continue ?
原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。
我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。
那么multipart/form-data表示什么呢?
multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。
multipart/form-data 结构
看下 http 请求的消息体
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。
每一个表单项又由Content-Type和Content-Disposition组成。
Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。
Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。
解析
客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。
可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。
不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。
至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。
使用 form 表单上传文件
在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。
DEMO
这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。
HTML
<form method="post" action="http://localhost:8100" enctype="multipart/form-data">
选择文件:
<input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
标题:<input type="text" name="title"/><br/><br/><br/>
<button type="submit" id="btn-0">上 传</button>
</form>
复制代码
服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。
在项目开发中,文件上传本身和业务无关,代码基本上都可通用。
在这里我们使用koa-body库来实现解析和文件的保存。
koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。
然后在后续中间件内得到已保存的文件的信息,再做二次处理。
NODE
/**
* 服务入口
*/
var http=require('http');
var koaStatic=require('koa-static');
var path=require('path');
var koaBody=require('koa-body');//文件保存库
var fs=require('fs');
var Koa=require('koa2');
var app=new Koa();
var port=process.env.PORT || '8100';
var uploadHost=`http://localhost:${port}/uploads/`;
app.use(koaBody({
formidable: {
//设置文件的默认保存目录,不设置则保存在系统临时目录下 os
uploadDir: path.resolve(__dirname, '../static/uploads')
},
multipart: true // 开启文件上传,默认是关闭
}));
//开启静态文件访问
app.use(koaStatic(
path.resolve(__dirname, '../static')
));
//文件二次处理,修改名称
app.use((ctx)=> {
var file=ctx.request.files.f1;//得道文件对象
var path=file.path;
var fname=file.name;//原文件名称
var nextPath=path+fname;
if(file.size>0 && path){
//得到扩展名
var extArr=fname.split('.');
var ext=extArr[extArr.length-1];
var nextPath=path+'.'+ext;
//重命名文件
fs.renameSync(path, nextPath);
}
//以 json 形式输出上传文件地址
ctx.body=`{
"fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
}`;
});
/**
* http server
*/
var server=http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ...... ');
复制代码
CODE
https://github.com/Bigerfe/fe-learn-code/
*请认真填写需求信息,我们会在24小时内与您取得联系。