由 transform 被占用引发的思考🤔

聊一聊关于transform被占用时的一些思考以及对 CSS 复杂属性的处理方式

一、transform 很容易被占用

所周知,CSS 中的transform是一个包含很多值的属性,例如

div{
  transformtranslate(-50%, -50%scale(1.5)
}

但是,这并不是简写,而是就该这么写,这一点和background不一样

div{
  backgroundurl('1xxx'10px 10px / 20px 20px no-repeat; 
}
/*等同于以下写法*/
div{
  background-imageurl('1xxx'); 
  background-position10px 10px;
  background-size20px 20px;
  background-repeat: no-repeat;
}

分开写的好处在于,如果只需要改变某一部分就很容易覆盖

div.div1{
  background-imageurl('2xxx'); /*只改变图片,不改变其他*/
}

回到前面,如果希望改变transform中的某一部分,就不太行了,必须把没改变的部分也写一遍,而且更改的部分也无法抽离出来作为一个公共的样式

div.scale{
  transformscale(2/*这样不行,会丢失translate*/
}
/*必须写完整*/
div.scale{
  transformtranslate(-50%, -50%scale(2)
}

那如何巧妙的解决这个问题呢?

二、目前的几种思路

1. 用其他方式来代替 transform

碰到这种情况,第一感觉可能就是放弃原有transform属性,用其他方式代替。

比如translate(-50%, -50%)一般是为了实现元素居中效果,可以用flex等其他方式实现

.parent{
  display: flex
}
div{
  margin: auto; /*通过margin:auto实现居中*/
}

再比如translate(10px, 10px)这样的偏移,可以用left或者margin-left等方式实现

div{
  position: relative;
  left10px;
  top10px;
}

或者干脆再包裹一层父级,也能避免transform被占用的问题。

<div class="wrap">
  <div class="box">
    
  </div>
</div>

不过,这些方式都是规避方式,其实还有官方解决方案

2. transform 的单独赋值

前面提到过transform并不是一个简写属性,所以没有办法像background那样对某一部分进行赋值。为了解决这个问题,从Chrome 104开始,浏览器终于正式支持单独赋值了

有兴趣的可以参考这篇文章:解放生产力!transform 支持单独赋值改变[1]

就拿前面那个例子来说

div{
  transformtranslate(-50%, -50%scale(1.5)
}

可以写成

div{
  translate: -50% -50%;
  scale1.5
}

这样如果需要改变某一部分,就只需要像普通属性一样覆盖就行了

div.scale{
  scale2
}

不过目前兼容性欠佳,谨慎使用!(适合内部项目尝鲜)

三、借助 CSS 变量拆分属性

前面的transform 的单独赋值虽然很好,但是太新了,无法立刻在项目中使用。下面介绍一个兼容性更好,使用更放心的解决方案。

还是上面这个例子

div{
  transformtranslate(-50%, -50%scale(1.5)
}

通过 CSS 变量,将transform拆分

div{
  --translate: -50%, -50%;
  --scale1.5;
  transformtranslate(var(--translate)) scale(var(--scale))
}

经过这样拆分以后,CSS 变量就成了独立属性,如果需要覆盖,只需要修改其中一个就行了,而无需关注--translate是什么样的,这样变化的部分就可以单独作为一个公共的样式了,如下

.div1{
  --translate: -50%, -50%;
}
.div1{
  --translate10px10px;
}
div.scale{
  --scale2/*无需关注其他transform,可以作为公共的样式*/
}

是不是非常清晰明了?下面是一个演示demo

[type="checkbox"]:checked+div{
  --scale1.5
}

效果如下

由 transform 被占用引发的思考🤔
Kapture 2022-11-03 at 16.25.11

完整代码可以查看以下任意链接:

  • CSS transform (codepen.io)[2]
  • CSS transform – 码上掘金 (juejin.cn)[3]
  • CSS transform (runjs.work)[4]

四、借助 @property 实现过渡动画

上面的实现看似完美,其实还是有问题的,比如加一个动画。

由于拆分成了 CSS 变量写法,所以动画的变化对象也变成了 CSS 自定义属性(--scale),如下

div{
  /**/
  animation: scale 1s infinite linear alternate;
}
@keyframes scale {
  from {
    --scale:1
  }
  to {
    --scale:1.5
  }
}

实际效果是这样的

由 transform 被占用引发的思考🤔
Kapture 2022-11-03 at 16.37.25

动是动了,但是没有过渡,太生硬了,那如何解决呢?

这就需要用到@property[5]了,是干什么的呢?简单来讲,可以自定义属性,让自定义变量像颜色一样进行过渡和动画,换句话说,现在执行动画的是--scale这个属性,而不再是transform

关于@property的应用,还可以参考这几篇文章:

所以,要实现过渡动画,只需要将这个自定义属性通过@property定义一下就行了,如下

@property --scale { 
  syntax: '<number>';
  inheritsfalse;
  initial-value: 1;
}

效果如下

由 transform 被占用引发的思考🤔
Kapture 2022-11-03 at 16.47.22

和传统实现效果一样,但是代码上更加优雅

完整代码可以查看以下任意链接:

  • CSS transform @property (codepen.io)[6]
  • CSS transform @property – 码上掘金 (juejin.cn)[7]
  • CSS transform @property (runjs.work)[8]

五、不仅仅是 transform

下面来拓展一下,打开你的格局。

除了transform,还有很多其他复杂的 CSS 属性,在现阶段并没有分开的情况下,这种通过 CSS 变量的方式就再适合不过了,比如filter

el{
  filterbrightness(0.4invert(75%grayscale(50%);
}

通过 CSS 变量分离开来就是

el{
  --brightness0.4;
  --invert75%;
  --grayscale50%;
  filterbrightness(0.4invert(75%grayscale(50%);
}

这样在做一些图片调整时,可以直接用单独的变量控制了,比如像keynote这样的

由 transform 被占用引发的思考🤔
image-20221107122041642

再比如rgb颜色值,写成一个变量不好控制,拆分成三个变量就容易多了

el{
  --r255;
  --g255;
  --b255;
  colorrgb(var(--r), var(--g), var(--b));
}

这样在做一些颜色调整交互时就非常方便,还是keynote中的例子

由 transform 被占用引发的思考🤔
image-20221107144707810

还有一些可以无限叠加的属性,比如background-image,对,又是这个,可谓是相当复杂了,在有多层背景,而且背景都是很长一段base64时,就成了这样

el{
  background-imageurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E")
}

这样一段 CSS 就像乱码一样,非常不利于阅读,分不清哪个图片是哪个,像这种情况就可以借助 CSS 变量改写成如下形式

:root{
  --背景1:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E");
  --背景2:url("
data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E");
 --背景3:url("
data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E");
}
el{
  background-image: var(--背景1), var(--背景2), var(--背景3)
}

这样对于el来说,用到了哪些背景是不是一目了然呢?

六、总结一下

以上就是本文全部内容了,也是 CSS 变量的一些实战小技巧,下面总结一下

  1. 部分 CSS 属性比较复杂,比如transform,很容易被占用
  2. 通常的解决方式是规避,比如换一种居中方式,或者用lefttop等代替
  3. 新出现的transform 的单独属性可以解决这个问题,目前还比较新,仅适合内部项目尝鲜
  4. 借助 CSS 变量可以拆分复杂的属性
  5. 借助 @property 让CSS自定义属性支持过渡动画
  6. 不仅仅是 transform,思维放开,复杂的属性都可以采取这样的思路
最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

参考资料

[1]

解放生产力!transform 支持单独赋值改变: https://juejin.cn/post/7152331836578856967

[2]

CSS transform (codepen.io): https://codepen.io/xboxyan/pen/BaVLMpv

[3]

CSS transform – 码上掘金 (juejin.cn): https://code.juejin.cn/pen/7161704312681758755

[4]

CSS transform (runjs.work): https://runjs.work/projects/4714accc300d441a

[5]

@property: https://developer.mozilla.org/zh-CN/docs/Web/CSS/@property

[6]

CSS transform @property (codepen.io): https://codepen.io/xboxyan/pen/OJERdpr

[7]

CSS transform @property – 码上掘金 (juejin.cn): https://code.juejin.cn/pen/7161709269698478083

[8]

CSS transform @property (runjs.work): https://runjs.work/projects/377a051b84d54bf6


原文始发于微信公众号(前端侦探):由 transform 被占用引发的思考🤔

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/66682.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!