推广 热搜: csgo  vue  2023  angelababy  gps  信用卡  新车  htc  落地  控制 

css盒子模型元素盒子大小计算 听说过CSS in JS,那你听说过JS in CSS吗

   2023-08-30 网络整理佚名2570
核心提示:JS是一种解决css问题想法的集合,而不是一个指定的库。将css放在js中使我们更方便的使用js的变量、模块化、tree-。甚至我们还可以编写自己的css自定义属性等。提供了两种自定义属性的注册方式,分别是在js和css中。我们还可以在css中注册,也可以达到上面的效果css那个demo[8]用使用过。2d上下文,根据元素的大小控制图像,还可以使用自定义属性。

JS 中的 CSS

JS 中的 CSS 是解决 CSS 问题的思想的集合,而不是特定的库。 从JS中CSS的字面意思可以看出,它将css样式写在文件中,不需要将.css、.less等文件分开。 将css放入js中,可以让我们更方便的使用js变量、模块、tree-。 它还解决了css中的一些问题,例如:更容易解决基于状态的样式,更容易跟踪依赖关系,以及生成唯一的选择器来锁定范围。 虽然CSS in JS并不是一个很新的技术,但是在国内的普及度并不高。 由于Vue和Vue都有自己的一套定义样式方案,React本身并不关心用户如何定义组件的样式[1],因此JS中的CSS在React社区中更流行。

目前为止,在 JS 中实现 CSS 的第三方库有很多:()。 像JSS[2]、-[3]等。这里不再赘述(相关链接已经放在下面),本文的重点是CSS中的JS。

CSS中的JS是什么?

上面我们提到CSS in JS就是把CSS写进去,那么我们可以推断JS in CSS可以使用CSS中的脚本,如下所示。 Paint API 的功能可以用 CSS 编写。 还可访问:ctx、geom。 甚至我们可以编写自己的css自定义属性等等。 这些功能的实现都是基于CSS[4]。

.el {
  --color: cyan;
  --multiplier: 0.24;
  --pad: 30;
  --slant: 20;
  --background-canvas: (ctx, geom) => {
    let multiplier = var(--multiplier);
    let c = `var(--color)`;
    let pad = var(--pad);
    let slant = var(--slant);
    ctx.moveTo(0, 0);
    ctx.lineTo(pad + (geom.width - slant - pad) * multiplier, 0);
    ctx.lineTo(pad + (geom.width - slant - pad) * multiplier + slant, geom.height);
    ctx.lineTo(0, geom.height);
    ctx.fillStyle = c;
    ctx.fill();
  };
  background: paint(background-canvas);
  transition: --multiplier .4s;
}
.el:hover {
  --multiplier: 1;
}

解决了什么问题CSS和JS标准开发流程对比

在当今的Web开发中,它几乎占据了大部分的项目代码。 我们在项目开发中可以使用ES 2020,甚至提案中的新特性(如:[5]),即使浏览器尚不支持,我们也可以编写或使用Babel等工具进行翻译,所以我们可以将最新的功能应用到生产环境中(如下图所示)。

标准开发流程.png

但 CSS 不同。 除了制定CSS标准需要时间之外,浏览器版本和实战进度的差异也是旷日持久的(如下图所示)。 最多就是用Sass、Sass之类的工具来帮助我们翻译浏览器。 可接受的 CSS。 开发者可以操作的是通过JS控制DOM和CSSOM来影响页面的变化,但是他们几乎无法控制接下来的Paint和CSSOM。 为了解决以上问题,为了让CSS的魔力不受浏览器的限制,它诞生了。

CSS标准制定流程.png

CSS

我们可以将上面提到的功能写在提案中,并且只需要很短的时间就可以将新功能投入到生产环境中。 这时候我脑子里第一个闪现的就是CSS。 只要CSS足够强大,CSS就可能有同样的发展速度。 遗憾的是,编写 CSS 是极其困难的,大多数情况下如果不执行而不影响性能就无法使用。 这是因为它是一种动态脚本语言[6]。 它带来了很大的可扩展性,也正因为如此,我们可以轻松地使用它。 但 CSS 不是动态的。 在某些情况下,我们可以在编译时将一种形式的 CSS 转换为另一种形式(例如 [7])。 如果你的依赖于DOM结构或者某个元素的布局、定位等,那么我们的就无法在编译时执行,而需要在浏览器中运行。 不幸的是,在浏览器中实现这个方案并不容易。

页面渲染流程.png

如上图所示,就是从浏览器获取HTML到渲染到屏幕上的整个过程。 我们可以看到只有彩色(粉色、蓝色)部分是可控的。 首先,我们无法控制浏览器解析HTML和CSS并将其转换为DOM和CSSOM的过程,也无法对Paint做任何事情。 整个过程中我们唯一可以完全控制的就是DOM,而CSSOM是部分可控的。

CSS草案提到,这种程度的暴露是不确定的,兼容性不稳定,缺乏对关键功能的支持。 例如,浏览器中的CSSOM不会告诉我们它如何处理跨域样式表,也不会解析浏览器无法解析的CSS语句,也就是说——如果我们要使用CSS让浏览器支持它尚不支持的属性,因此我们无法在 CSSOM 中执行此操作。 我们只能遍历DOM,查找或标记,获取CSS样式,解析,重写,最后添加回DOM树中间。 尴尬的是,所有的DOM树都这样刷新,会导致页面重新渲染(如下图)。

即便如此,可能有人会说:“除了这个方法,我们也没有选择,何况也不会对网站的性能产生很大的影响”。 嗯,某些网站就是这种情况。 但是如果我们需要一个交互式页面怎么办? 比如、、keyup等,这些事件会随时被触发,这意味着页面会随时重新渲染,交互不会像以前那么流畅,甚至会导致页面崩溃,这对于用户体验来说是极其糟糕的。

综上所述,如果我们想让浏览器解析它不识别的样式(低版本浏览器使用网格布局),但我们无法干预渲染过程,只能手动更新 DOM,这会带来很多问题的出现,而正是致力于解决这些问题。

蜜蜂

它是一组低级 API,公开 CSS 引擎的各个部分。 每个链接对应的新API如下图所示(灰色部分尚未被主流浏览器实现),以便开发者可以添加浏览器渲染引擎的样式和布局过程扩展CSS。 它是由来自 Apple、Opera、HP、Intel 和 . 它们使开发人员可以直接访问 CSS 对象模型 (CSSOM),允许开发人员编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 功能,而无需等待它们在浏览器中本机实现。

CSS API

& API

虽然目前有CSS变量允许开发者控制属性值,但它们无法约束类型或定义更严格。 通过新的CSS API,我们可以扩展CSS变量,我们可以定义CSS变量的类型、初始值和继承。 。 CSS 变量使其更加强大和灵活。

CSS 变量的当前状态:

.dom {
  --my-color: green;
  --my-color: url('not-a-color'); // 它并不知道当前的变量类型
  color: var(--my-color);
}

提供了两种注册自定义属性的方式,分别是在js中和在css中。

CSS.registerProperty({
  name: '--my-prop', // String 自定义属性名
  syntax: '', // String 如何去解析当前的属性,即属性类型,默认 *
  inherits: false, // Boolean 如果是true,子节点将会继承
  initialValue: '#c0ffee', // String 属性点初始值
});

我们也可以在css中注册来实现上面的效果

@property --my-prop {
  syntax: '';
  inherits: false;
  initial-value: #c0ffee;
}

这个API中最令人兴奋的功能是为自定义属性添加动画,像这样:: -- 0.4s;,这个功能我们在前面介绍什么是css中的js的demo[8]中使用过。 我们还可以使用+来使属性支持一种或多种类型,或者使用| 分开。 更多房产价值:

属性值 描述 长度 值 数量

百分比长度或百分比,calc将是由长度和百分比组成的表达式彩色图像URL整数角度时间分辨率转换函数ident

是渲染引擎的扩展,它在概念上类似于 Web [9],但有几个重要的区别:

设计为并行,每个实例必须始终有两个或多个实例,它们中的任何一个都可以在调用时运行较小范围的受限 API,这些 API 无法访问全局范围(渲染引擎在以下情况下调用它们的函数除外):需要,而不是我们手动调用

是一个通过调用方法添加的模块(它是一个 )。例如,我们都需要放入

//加载单个
await demoWorklet.addModule('path/to/script.js');
// 一次性加载多个worklet
Promise.all([
  demoWorklet1.addModule('script1.js'),
  demoWorklet2.addModule('script2.js'),
]).then(results => {});
registerDemoWorklet('name', class {
  // 每个Worklet可以定义要使用的不同函数
  // 他们将由渲染引擎在需要时调用
  process(arg) {
    return !arg;
  }
});

生命周期

对于渲染引擎的生命周期来说,渲染引擎启动主线程,然后就会启动多个进程,就可以运行了。 理想情况下,这些进程应该是与主线程分开的线程,这样它们就不会阻塞主线程(但它们也不需要阻塞),然后在主线程中加载浏览器的调用。 异步加载一个负载,然后在需要时加载到两个或多个可用管道中,渲染引擎将通过从加载的管道中调用适当的处理程序来执行。 可以对任何并行实例进行调用。 类型化OM

Typed OM 是现有 CSSOM 的扩展,并实现了 API 和 & API 相关功能。 它将 css 值转换为有意义类型的对象,而不是像现在这样的字符串。 如果我们尝试将字符串类型的值转换为有意义的类型并返回可能会产生很大的性能开销,因此这个 API 可以让我们更高效地使用 CSS 值。

现在添加了一个新的基类来读取 CSS 值。 它有很多子类可以更准确地描述CSS值的类型:

子类描述关键字和其他标识符(如或网格)位置信息(x,y)表示图像属性对象的值,表示为单个单位(如50px)的单个值,也可以表示为没有单位的单个值或更复杂的百分比值,例如 calc、min 和 max。这包括子类 , ,, 以及由 , , , , , , 和 组成的 CSS t-list

使用 Typed OM 主要有两种方式:

通过设置和获取 typed 内联样式 通过获取元素的完整 Typed OM 样式

使用设置并获取

myElement.attributeStyleMap.set('font-size', CSS.em(2));
myElement.attributeStyleMap.get('font-size'); // CSSUnitValue { value: 2, unit: 'em' }
myElement.attributeStyleMap.set('opacity', CSS.number(.5));
myElement.attributeStyleMap.get('opacity'); // CSSUnitValue { value: 0.5, unit: 'number' };

在线演示[10]

使用

.foo {
  transform: translateX(1em) rotate(50deg) skewX(10deg);
  vertical-align: baseline;
  width: calc(100% - 3em);
}

const cs = document.querySelector('.foo').computedStyleMap();
cs.get('vertical-align');
// CSSKeywordValue {
//  value: 'baseline',
// }
cs.get('width');
// CSSMathSum {
//   operator: 'sum',
//   length: 2,
//   values: CSSNumericArray {
//     0: CSSUnitValue { value: -90, unit: 'px' },
//     1: CSSUnitValue { value: 100, unit: 'percent' },
//   },
// }
cs.get('transform');
// CSSTransformValue {
//   is2d: true,
//   length: 3,
//   0: CSSTranslate {
//     is2d: true,
//     x: CSSUnitValue { value: 20, unit: 'px' },
//     y: CSSUnitValue { value: 0, unit: 'px' },
//     z: CSSUnitValue { value: 0, unit: 'px' },
//   },
//   1: CSSRotate {...},
//   2: CSSSkewX {...},
// }

蜜蜂

开发者可以通过这个API实现自己的布局算法,我们可以像原生CSS一样使用我们的自定义布局(如:flex、:table)。 在[11]中我们可以看到有多少开发人员想要实现各种复杂的布局,其中一些布局无法单独使用 CSS 来完成。 虽然这些布局让人耳目一新,令人印象深刻,但它们的页面性能往往很差,在一些低端设备上性能问题仍然很明显。

CSS API 向开发人员公开了一种方法,该方法接收布局名称 (name) 作为稍后在 CSS 中使用的属性值,以及包含布局逻辑的类。

my-div {
  display: layout(my-layout);
}

// layout-worklet.js
registerLayout('my-layout', class {
  static get inputProperties() { return ['--foo']; }
  
  static get childrenInputProperties() { return ['--bar']; }
  
  async intrinsicSizes(children, edges, styleMap) {}
  async layout(children, edges, constraints, styleMap) {}
});

await CSS.layoutWorklet.addModule('layout-worklet.js');

目前大部分浏览器不支持

蜜蜂

我们可以在 CSS -image 中使用它,我们可以使用 2d 上下文,根据元素的大小控制图像,还可以使用自定义属性。

await CSS.paintWorklet.addModule('paint-worklet.js');

registerPaint('sample-paint', class {
  static get inputProperties() { return ['--foo']; }
  static get inputArguments() { return ['']; }
  static get contextOptions() { return {alpha: true}; }
  paint(ctx, size, props, args) { }
});

蜜蜂

该 API 允许我们根据用户输入以非阻塞方式控制关键帧动画。 也可以更改 DOM 元素的属性,但这些属性不会导致渲染引擎重新计算布局或样式,例如 或滚动条位置 ( )。 该 API 的用法与 Paint API 和 API 略有不同。 我们还需要通过新的进行注册。

// animation-worklet.js
registerAnimator('sample-animator', class {
  constructor(options) {
  }
  animate(currentTime, effect) {
    effect.localTime = currentTime;
  }
});

await CSS.animationWorklet.addModule('animation-worklet.js');
// 需要添加动画的元素
const elem = document.querySelector('#my-elem');
const scrollSource = document.scrollingElement;
const timeRange = 1000;
const scrollTimeline = new ScrollTimeline({
  scrollSource,
  timeRange,
});
const effectKeyframes = new KeyframeEffect(
  elem,
  // 动画需要绑定的关键帧
  [
    {transform: 'scale(1)'},
    {transform: 'scale(.25)'},
    {transform: 'scale(1)'}
  ],
  {
    duration: timeRange,
  },
);
new WorkletAnimation(
  'sample-animator',
  effectKeyframes,
  scrollTimeline,
  {},
).play();

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON