什么?CSS 要支持内联条件语句!

CSS 工作组(WG)决定在 CSS 中添加一个内联的 if() 函数。本文解读 if() 函数的设计理念与应用场景,对比其与 style queries 的差异,展示在复杂条件处理上的独特优势。

CSS 工作组决定在 CSS 中添加一个内联的 if() 函数

上周,CSS 工作组(WG)决定在 CSS 中添加一个内联的 if() 函数。但这意味着什么,为什么它如此令人兴奋呢?

上周,我们在西班牙的拉科鲁尼亚举行了一次 CSS 工作组的面对面会议。这次会议中有一个决议我特别兴奋:一致同意在 CSS 中添加一个内联的 if() 函数。虽然我不是第一个提出内联条件语法的人,但我尝试将各种无休止的讨论缩减为一个可以快速实现的最小可行产品(MVP),与实现者讨论了想法,并最终发布了一个具体的提案并推动了小组决议。非常富有诗意的是,相关的讨论恰好发生在我的生日那天,所以从某种意义上说,我得到了 if() 作为最独特的生日礼物。😀

这也表明,提案被拒绝并不是某个功能的终结。事实上,一个功能在被接受之前被多次拒绝是相当常见的:CSS Nesting、:has()、容器查询(container queries)都是一系列被拒绝提案中的最后迭代。if() 本身在 2018 年似乎被拒绝了,当时我提出的语法与之非常相似。那么有什么不同呢?那时样式查询(style queries)已经发布,我们可以简单地引用相同的语法作为条件(再加上 Tab 的 @when 提案中的 media() 和 supports()),而在 2018 年的提案中,条件的工作方式在很大程度上是未定义的。

我在各种社交媒体上发布了这个消息,而开发者的反应非常积极:Twitter、LinkedIn、Mastodon。
我甚至有大公司的朋友写信告诉我,他们内部的 Slack 群聊对此事炸开了锅。这证实了我一直以来的怀疑,也是我向 CSS 工作组提出的一个理由:这是一个巨大的痛点。希望这些积极反应的数量和强度能帮助浏览器优先考虑这个功能,并将其尽早纳入他们的开发路线图。

在这些平台上,除了“我迫不及待地想要这个功能上线!”是最常见的情绪外,还有一些其他问题反复出现,以及相当程度的困惑,我觉得这些问题值得回答。

Q&A

if() 的用途是什么?它会取代样式查询(style queries)吗?

恰恰相反,if() 是对样式查询的补充。如果你能用样式查询完成某件事,那么请尽管使用样式查询——它们几乎肯定是更好的解决方案。但是有些事情是样式查询无法做到的。我来解释一下。

推动引入 if() 的用例是,组件(在广义上)经常需要定义更高级别的自定义属性,这些属性的值不仅直接在声明中使用,而且会在各种声明中设置不相关的值。

例如,考虑一个 --variant 自定义属性(受 Shoelace 的 variant 属性的启发)。它可能看起来像这样:

--variant: success | danger | warning | primary | none;

这个属性需要设置背景色、边框色、文本色、图标等。实际上,它的实际值在任何地方都不会被直接使用,它只用于设置其他值。

样式查询(style queries)让我们部分实现了这一功能:

.callout {@container (style(--variant: success)) {  &::before {  content: var(--icon-success);  color: var(--color-success);  }}/* (其他变体) */  
}

但是,样式查询仅在后代(子)元素上工作。我们无法做到以下这点:

.callout {  @container (style(--variant: success)) {  border-color: var(--color-success-30);  background-color: var(--color-success-95);  &::before {  content: var(--icon-success);  color: var(--color-success-05);  }}  /* (其他变体) */  
}

通常,我们需要在元素本身上设置的声明很少,有时甚至只有一个。然而,即使只有一个也是多余的,使得在许多(可能是大多数)高级别自定义属性用例中使用自定义属性变得不可行。因此,组件库最终会使用诸如 pill、outline、size 等呈现属性。

虽然呈现属性乍看之下可能没问题,甚至对开发者体验来说更好(字符更少——至少与每个元素设置一个变量相比),但它们存在几个可用性问题:

  • 减少灵活性
    它们不能基于选择器、媒体查询等条件来应用。更改它们需要更多的JavaScript。如果它们被用在另一个组件内部,你就束手无策了,而使用(可继承的)自定义属性,你可以在父组件上设置属性,它会向下继承。

  • 冗长性
    它们必须应用到单个实例上,并且不能继承。即使使用某种形式的模板或组件化来减少重复,在使用开发工具进行调试时,仍然需要遍历这些属性。

  • 缺乏一致性
    由于几乎每个成熟的组件也支持自定义属性,用户必须记住哪些样式是通过属性设置的,哪些是通过自定义属性设置的。这种区分往往是任意的,因为它不是由用例驱动的,而是由实现的便利性驱动的。

使用if(),上述示例变得可能:

.callout {border-color: if(style(--variant: success) ? var(--color-success-30) :style(--variant: danger) ? var(--color-danger-30) :var(--color-neutral-30));background-color: if(style(--variant: success) ? var(--color-success-95) :style(--variant: danger) ? var(--color-danger-95) :var(--color-neutral-95));@container (style(--variant: success)) {&::before {content: var(--icon-success);color: var(--color-success-05);}}
}

虽然这是主要的用例,但事实证明,将媒体查询和兼容性条件也作为if()的条件语法的一部分是非常容易的。由于它是一个函数,它的参数(包括条件!)可以存储在其他自定义属性中。这意味着你可以做像这样的事情:

:root {--xl: media(width > 1600px);--l: media (width > 1200px);--m: media (width > 800px);
}

然后定义如下值:

padding: if(var(--xl) ? var(--size-3) :var(--l) or var(--m) ? var(--size-2) :var(--size-1)
);

就像JavaScript中的三元运算符一样,当只有值的一小部分发生变化时,使用这种方式可能更易于使用和阅读:

animation: if(media(prefers-reduced-motion) ? 10s : 1s) rainbow infinite;

那么这个功能已经在浏览器里实现了吗?

信不信由你,这是我收到的一个真实问题😅。不,这个功能目前还没有在浏览器中实现,而且还需要一段时间。最乐观的估计也大约是2年左右,如果这个过程没有在任何时候停滞不前(这通常会发生)。

目前我们只是在该特性上达成了共识。接下来的步骤是:

  1. 就该特性的语法达成共识。语法辩论往往会持续很长时间,因为每个人在语法上都有自己的看法。目前的辩论主要集中在:

    • 条件与分支之间应该使用什么分隔符?

    • 如何表示没有值?我们是简单地允许像var()中那样的空值(例如,你可以写var(–foo,)),还是引入一个专门的语法来表示“空值”?

    • 最后一个值是否应该是可选的?

  2. 为该特性编写规范。

  3. 获取第一个实现。这通常是最难的部分。一旦一个浏览器实现了,其他浏览器加入就会容易得多。

  4. 在所有主要浏览器中发布该功能。

我确实有一个页面,我在那里追踪我的一些标准提案,这应该有助于阐明这些步骤的时间表是什么样的。事实上,你也可以在那里追踪if()的特定进度。

这是CSS中的第一个条件语句吗?

许多回答都是类似“哇,CSS终于有条件语句了!”这样的。

朋友们……CSS从一开始就有条件语句。每个选择器本质上都是一个条件语句!

此外:

@media@supports 规则也是条件语句。别忘了还有 @container
var(--foo, fallback) 是一种有限类型的条件语句(本质上类似于 if(style(--foo: initial) ? var(--foo) : fallback)),这就是为什么它成为大多数模拟内联条件语句的解决方案的基础。

这会让CSS变成命令式的吗?

一个普遍的误解是非线性逻辑(条件语句、循环)使一种语言成为命令式语言。

声明式与命令式并不关乎逻辑,而是关于抽象层次。我们是在描述目标还是实现它的方法?用烹饪术语来说,食谱是命令式的,而餐厅菜单是声明式的。

条件逻辑实际上可以使一种语言更加声明式,如果它有助于更好地描述意图的话。

考虑以下两段CSS代码:

正常写法

button {border-radius: calc(.2em + var(--pill, 999em));
}.fancy.button {/* Turn pill on */--pill: initial;
}

使用if() 写法

button {border-radius: if(style(--shape: pill) ? 999em : .2em);
}.fancy.button {--shape: pill;
}

我会说后者是更加声明式的,即它更接近于指定目标而不是如何实现它。通过使用--shape自定义属性,我们是在声明一个按钮应该具有什么形状,而不是直接指定它应该如何根据条件改变其border-radius。这种方法使代码更加清晰和易于理解,因为我们是在定义目标样式,而不是实现细节。

这会让CSS成为一种编程语言吗?

一种非常常见的回应是CSS现在是否是一种编程语言(要么是询问它是否是,要么是断言它现在是)。要回答这个问题,首先需要回答什么是编程语言。

如果图灵完备性让一种语言成为编程语言,那么CSS十多年前就已经是编程语言了。但话说回来,Excel或Minecraft也是。那么这究竟意味着什么呢?

如果是因为命令式特性,那么不,CSS不是一种编程语言。但许多实际的编程语言也不是!

但一个更深层次的问题是,这重要吗?是因为它让选择专注于CSS变得合法化了吗?是因为即使你只写HTML和CSS也可以被认为是程序员吗?如果这只是为了面子问题,那么我们应该从核心上解决这个问题,并努力让CSS的专业知识合法化,无论CSS是否是一种编程语言。毕竟,任何了解几种备受尊敬的编程语言和CSS的人都可以证明,CSS更难掌握。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序大作为|小程序开发详细流程,新手也能轻松掌握

随着移动互联网的快速发展,小程序作为一种轻量级应用,因其无需下载安装、即点即用、用完即走的特点,受到了广大用户的青睐。那么开发小程序都有哪些开发流程呢?可以用哪种方式开发?选择合适的开发方式,一起…

小程序知识点:Vant!!!

小伙伴们好啊,今天我们来学习vant。 介绍: 特性: 提供60多个高质量组件,覆盖移动端各类场景性能极佳,组件平均体积不到1kb单元测试覆盖率90%,提供稳定性保障完善的中英文文档和示例支持Vue2&Vue3支持…

华为设备telnet 远程访问配置实验简述

一、实验需求: 1、AR1模拟电脑telnet 访问AR2路由器。 二、实验步骤: 1、AR1和AR2接口配置IP,实现链路通信。 2、AR2配置AAA模式 配置用户及密码 配置用户访问级别 配置用户telnet 访问服务 AR2配置远程服务数量 配置用户远程访问模式为AAA 配置允许登录…

批量推送邮件如何高效实现?邮件推送技巧?

批量推送邮件有哪些注意事项?如何优化邮件推送效果? 无论是市场营销、客户服务还是内部沟通,批量推送邮件都发挥着关键作用。然而,如何高效实现批量推送邮件却是一个需要深思的问题。AokSend将探讨一些提高批量推送邮件效率的方法…

2005年上半年软件设计师【上午题】试题及答案

文章目录 2005年上半年软件设计师上午题--试题2005年上半年软件设计师上午题--答案2005年上半年软件设计师上午题–试题

stm32没有mmu,不能跑linux操作系统

stm32能跑linux操作系统吗? 答案:想要运行linux,芯片需要MMU,STM32没有MMU,所以不能运行Linux,WinCE等;但是可以运行ucosii、freertos、uLinux、vxWorks等。 根本原因:linux系统是…

【Sa-Token|4】Sa-Token微服务项目应用

若微服务数量多,如果每个服务都改动,工作量大,则可以只在网关和用户中心进行改动,也是可以实现单点登录的。 这种方式可以通过在网关服务中生成和验证 Sa-Token,并将其与现有的 Token关联存储在 Redis 中。用户中心提供…

自学鸿蒙HarmonyOS的ArkTS语言<三>路由跳转及传参

【官方文档传送门】 一、导入模块 import router from ohos.router二、新增页面配置 三、常用api 1、跳转到应用内的指定页面 build() {Row() {Button(下一页).onClick(() > {router.pushUrl({url: pages/Index2,params: {name: test}})})}.height(100%)}2、用应用内的某…

【Java】已解决java.net.UnknownHostException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.net.UnknownHostException异常 在Java的网络编程中,java.net.UnknownHostException是一个常见的异常,它通常表明在尝试解析主机名时出现了问题。…

php基础语法_面向对象

PHP php代码标记 多种标记来区分php脚本 ASP标记&#xff1a;<% php代码 %> 短标记&#xff1a; 脚本标记: 标准标记&#xff08;常用&#xff09;&#xff1a; 简写风格&#xff1a; ASP风格&#xff1a;<% php代码 %> 注意&#xff1a;简写风格和ASP风格…

myslql事务示例

在 MySQL 中&#xff0c;事务&#xff08;Transaction&#xff09;是一组要么全部执行&#xff0c;要么全部不执行的SQL语句。这可以确保数据的一致性和完整性。事务管理的核心包括四个属性&#xff0c;即原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consiste…

RegionClip环境安装踩坑指南

RegionClip环境安装 RegionClip环境安装)问题1问题2问题3问题4问题5 RegionClip环境安装) 特别强调&#xff0c;不要单独去安装detectron2&#xff0c;会出现model.clip不存在的错误&#xff0c;通过python -m pip install -e RegionCLIP就可以问题1 问题&#xff1a;torch-c…

安卓SDK发布到maven

【参考文档】 maven central:https://vanniktech.github.io/gradle-maven-publish-plugin/central/#in-memory-gpg-key 安装gpg&#xff1a; https://central.sonatype.org/publish/requirements/gpg/#publish-or-drop-the-deployment 【流程】 1、进入Maven Central: P…

sourceTree 解决remote: HTTP Basic: Access denied报错mac

解决sourceTree中remote: HTTP Basic: Access denied报错 mac sourcetree报错报错原因解决方案 mac sourcetree报错 warning: invalid credential line: xxx.com remote: HTTP Basic: Access denied fatal参考链接&#xff1a;https://developer.aliyun.com/article/1304149 …

在分数限制下,是选择好专业还是好学校取决于你个人的兴趣、职业规划和实际情况。

分数限制下&#xff0c;选好专业还是选好学校&#xff1f; 方向一&#xff1a;专业解析 选择专业与选择学校之间的决策确实是一个复杂的过程&#xff0c;涉及到个人兴趣、职业目标以及教育资源等多个因素。我来结合实际场景&#xff0c;探讨不同专业的优势、未来挑战以及专业与…

高效学习方法笔记

part1.学习方法: 1.知识多不等于学习能力强&#xff1b; 2.考试是最有效的学习策略&#xff1b; 3.间隔练习使知识存储更牢固&#xff1b; 4.自我检索&#xff08;反思&#xff09;能更好的掌握知识&#xff1b; 5.穿插练习有助于长期记忆&#xff1b; 6.多样性练习促进知识的…

ruoyi登录功能源码分析

Ruoyi登录功能源码分析 上一篇文章我们分析了一下若依登录验证码生成的代码&#xff0c;今天我们来分析一下登录功能的代码 1、发送登录请求 前端通过http://localhost/dev-api/login向后端发送登录请求并携带用户的登录表单 在后端中的com.ruoyi.web.controller.system包下…

mysql中使用json_arrayagg(),指定数组中元素排序

背景&#xff1a; 按照某个字段分组&#xff0c;分组后将同类型的元素聚合在一个数组中&#xff0c;最后再比较数组是否相等。 使用json_arrayagg()&#xff0c;数组中元素排序为数据所属表的默认排序&#xff0c;不满足比较数组是否相等的需求。 既然要排序&#xff0c;于是写…

14-Kafka-Day03

第 5 章 Kafka 消费者 5.1 Kafka 消费方式 5.2 Kafka 消费者工作流程 5.2.1 消费者总体工作流程 一个消费者组中的多个消费者&#xff0c;可以看作一个整体&#xff0c;一个组内的多个消费者是不可能去消费同一个分区的数据的&#xff0c;要不然就消费重复了。 5.2.2 消费者…

WIC 图像处理初体验——读取像素的值

先放上运行结果&#xff1a; 可以发现红绿蓝是从后往前的。 必须以C方式编译代码&#xff01; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <wincodec.h>int main(void) {CoInitialize(nullptr);IWICImagingFactory* fac;CoCreateInstance(CLS…