【CSS @property】CSS自定义属性说明与demo

CSS @property

@property - CSS: Cascading Style Sheets | MDN
At 规则 - CSS:层叠样式表 | MDN
Custom properties (--*): CSS variables - CSS: Cascading Style Sheets | MDN
CSS Houdini - Developer guides | MDN

📚 什么是@property?

@property CSS at-rule 是 CSS Houdini API [🔗] 的一部分,它允许开发者显式地定义他们的CSS 自定义属性, 允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承**。

  • @property 规则 提供了一个直接在样式表中注册自定义属性的方式,而无需运行任何 JS 代码。
  • 有效的 @property 规则会注册一个自定义属性,就像 【CSS.registerProperty🔗】 函数被使用同样的参数调用了一样。

在过去,我们使用CSS自定义变量(CSS Variables)来存储和复用值,但它们并不具备类型检查和默认值设定的功能。

而CSS @property则弥补了这一空白,使得自定义属性更加功能丰富和强大。

💎 语法

css 复制代码
@property --property-name {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}
  • --property-name : 自定义属性名称
  • syntax: 定义了自定义属性接受的值的类型。
    • CSS 基本数据类型 - CSS:层叠样式表 | MDN
    • 可能是(长度)、(数字)、(百分比)、(长度百分比)、(颜色)、(图像)、(URL地址)、(整数)、(角度)、(时间)、(分辨率)、(变换函数)或(自定义标识符),或者是这些数据类型和关键字值的列表。
    • +(空格分隔)和 # 字号(逗号分隔)的乘法器表示期望的是一个值的列表,
      • 例如 <color># 意味着期望的语法是一个以逗号分隔的 <color>值列表
    • 竖线(|)可以为预期的语法创建"或"条件,
      • 例如 <length> | auto 接受 <length>或auto,而 <color># | <integer># 期望的是以逗号分隔的 <color>值列表 或以 逗号分隔的<integer>值列表
  • inherits: 指定该自定义属性是否可以被子元素继承,默认为 false。
  • initial-value:设置自定义属性的默认值。

@property 规则中 syntaxinherits 描述符是必需的;

如果其中任何一项缺失,整条规则都将失效并且会被忽略。
initial-value 描述符仅在 syntax 描述符为通用 syntax 定义时是可选的,否则initial-value也是必需的------如果此时该描述符缺失,整条规则都将失效且被忽略。

未知的描述符自身都是无效的,且会被忽略。但是不会造成整条@property规则的失效。

例子 1:

html 复制代码
<div class="container">
  <div class="item one">Item one</div>
  <div class="item two">Item two</div>
  <div class="item three">Item three</div>
</div>
  • 定义两个自定义属性,--item-size--item-color,用它们来定义三个子元素 item 的宽度和高度以及背景颜色。
css 复制代码
/* --item-size and --item-color */
@property --item-size {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 40%;
}

@property --item-color {
  syntax: "<color>";
  inherits: false;
  initial-value: aqua;
}
  • 自定义属性 --item-size:
    • 该属性接受的值的类型只是百分比 <percentage>;
    • 初始值设置为40%;
    • 属性是可继承的,这意味着,当用作项目大小的值时,它的大小将始终相对于其父级的大小。
  • 自定义属性 --item-color :
    • 该属性接受的值的类型 只是 <color>类型
    • 初始值是 关键字aqua
    • 属性不继承
css 复制代码
.container {
  display: flex;
  height: 200px;
  border: 1px dashed black;
  /* 使用自定义属性 */
  /* 在父元素 设置了自定义属性的值 */
  --item-size: 20%;
  --item-color: orange;
}

/* 使用自定义属性 设置 item的 宽高 和背景颜色 */
.item {
  width: var(--item-size);
  height: var(--item-size);
  background-color: var(--item-color);
}

/* 设置自定义属性在元素自己身上的值 */
.two {
  --item-size: initial;
  --item-color: inherit;
}

.three {
  /* 无效值 */
  --item-size: 1000px;
  --item-color: xyz;
}

🍀 分析:

  • 两个自定义属性 --item-size: 20%--item-color: orange; 设置在父级容器 container 上,覆盖了定义时设置的默认值: --item-size:40%--item-color:aqua 。其中--item-size 为可继承; --item-color 不可继承。

  • 对 class 为item的子元素,通过自定义属性设置了 宽高背景颜色

    • 这个时候,宽高的值是 相对于父容器的宽的20% 。因为,父容器重新设置 --item-size的值。
  • 对于 one,没有设置这些自定义属性。

    • --item-size 是可继承的,因此使用其父容器上设置的值20% 。
    • --item-color 是不可继承的,因此不考虑父级上的 orange。而是使用默认的初始值 aqua。
  • 对于 two ,对两个自定义属性 --item-size--item-color 设置了 CSS全局关键字,这两个属性对于所有值类型都是有效值,因此无论语法描述符的值如何都是有效的。

    • --item-size:initial : 使用该属性的初始值。在 @property 声明中设置的初始值 initial-value40%
    • --item-color:inherit : 表示从其父元素(也就是container)继承 orange。即使自定义属性被设置为不被继承,也要显式地从其父级继承orange
  • 对于 three, --item-size--item-color都是无效值。

    • --item-size 值为 1000px。虽然 1000px 是一个 <length> 值,但是@property 声明时要求该值是一个<percentage>类型。因此该声明无效并被忽略,这意味着使用了父级上可继承的 20%
    • --item-color 值为 xyz 也是无效的。
      • 首先,值 xyz不是 CSS 数据类型 [<color>🔗](https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value)的关键字 <color-name>的有效值。所以会被忽略,所以直接显示的是 item定义的样式。
      • 其次,--item-color不能被继承,因此使用 aqua 的默认值,也不使用父级的值 orange

例子 2:使用 CSS @property 实现背景色渐变动画

css 复制代码
@property --colorA {
  syntax: "<color>";
  inherits: false;
  initial-value: red;
}

@property --colorB {
  syntax: "<color>";
  inherits: false;
  initial-value: yellow;
}

@property --colorC {
  syntax: "<color>";
  inherits: false;
  initial-value: blue;
}



.box {
  width: 300px;
  height: 300px;
  background: linear-gradient(45deg,
              var(--colorA),
              var(--colorB), 
              var(--colorC));
  animation: animate 3s linear infinite alternate;
}

@keyframes animate {
  20% {
    --colorA: blue;
    --colorB: #F57F17;
    --colorC: red;
  }

  40% {
    --colorA: #FF1744;
    --colorB: #5E35B1;
    --colorC: yellow;
  }

  60% {
    --colorA: #E53935;
    --colorB: #1E88E5;
    --colorC: #4CAF50;
  }

  80% {
    --colorA: #76FF03;
    --colorB: teal;
    --colorC: indigo;
  }
}
html 复制代码
<div class="box"></div>

例子3: 使用自定义属性完成图片切换

html 复制代码
    <div class="section">
        <div class="box bg mask1"></div>
        <div class="box bg mask2"></div>
    </div>
css 复制代码
$img1: 'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/191/191-bigskin-6.jpg';
$img2: 'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/191/191-bigskin-8.jpg';
$mask1: linear-gradient(45deg, #000 0, #000 var(--per), transparent calc(var(--per) + 10%), transparent);
$mask2: conic-gradient(#000 0, #000 var(--per), transparent calc(var(--per) + 10%), transparent);
@property --per {
  syntax: '<percentage>';
  inherits: false;
  initial-value: -10%;
}
.section {
  width: 100%;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}
.section div {
  margin: 20px;
}
.section {
  .box {
    width: 600px;
    height: 300px;
  }
  .bg {
    background: url($img1);
    background-repeat: no-repeat;
    background-position: 50%;
    background-size: cover;
    position: relative;

    &::after {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      background: url($img2);
      background-size: cover;
      background-position: 50%;

      animation: animate 2s ease-in-out infinite alternate;
    }
  }
  .mask1 {
    &::after {
      mask: $mask1;
    }
  }
  .mask2 {
    &::after {
      mask: $mask2;
    }
  }
}

@keyframes animate {
  0% {
    --per: -10%;
  }
  100% {
    --per: 100%;
  }
}
相关推荐
蜗牛快跑2132 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy3 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
帅帅哥的兜兜1 小时前
CSS:导航栏三角箭头
javascript·css3
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss