原生CSS嵌套写法实例
使用Sass等CSS预处理器的核心原因之一是嵌套,而现在标准浏览器CSS也已实现类似语法。在构建系统时,是否可以放弃对预处理器的依赖?CSS嵌套可以节省输入时间,并使语法更易于阅读和维护。到目前为止,你必须像这样键入完整的选择器路径:
.parent1 .child1, .parent2 .child1 { color: red; } .parent1 .child2, .parent2 .child2 { color: green; } .parent1 .child2:hover, .parent2 .child2:hover { color: blue; }
现在,你可以将子选择器嵌套在父选择器中,比如:
.parent1, .parent2 { .child1 { color: red; } .child2 { color: green; &:hover { color: blue; } } }
你可以嵌套任意层级的选择器,但要注意不要超过两到三级。嵌套层级没有技术层面的限制,但是会让代码更难阅读,并且让最终CSS变得很冗长。
直到2023年四月,暂没有浏览器支持CSS嵌套语法。你需要使用 CSS 预处理器(如 Sass、Less 或 PostCSS)进行构建步骤,以便将嵌套代码转换为常规的全选择器语法。嵌套功能现已在Chrome 112+和Safari 16.5+中实现,Firefox将在2023年晚些时候提供支持。
CSS原生嵌套规则
你可以将任何选择器嵌套到另一个选择器中,但必须以符号开头,如&,.(用于HTML class),#(用于HTML id),@(用于媒体查询),:,::,*,+,~,>,或 [。换句话说,它不能直接引用HTML元素。下面的代码无效,<p>选择器不会被解析:
.parent1 { /* FAILS */ p { color: blue; } }
修复该问题最简单的方法就是使用&,其与Sass相同的方式引用当前选择器:
.parent1 { /* WORKS */ & p { color: blue; } }
或者,可以这么解决:
• > p - 但这将仅对 .parent1 的直接子元素进行样式调整
• :is(p) - 但是:is()使用最优先选择器的优先级
• :where(p) - 但是:where()的优先级为0
在这个简单的示例中,它们都可以工作,但在以后使用更复杂的样式表时,你可能会遇到优先级问题。
&还允许你在父选择器上定位伪元素和伪类。例如:
p.my-element { &::after {} &:hover {} &:target {} }
如果你不使用&,你的目标将是选择器的所有子元素,而不是p.my-element本身。(在Sass中也会出现同样的情况)。需要注意的是,你可以在选择器的任何位置使用&,比如:
.child1 { .parent3 & { color: red; } }
这会转换为下列非嵌套语法:
.parent3 .child1 { color: red; }
你甚至可以在一个选择器中使用多个&符:
ul { & li & { color: blue; } }
这会作用于嵌套的<ul>元素(ul li ul),如果你不想被逼疯我建议还是不要这么使用了!最后,你可以嵌套媒体查询。下面的代码为段落元素应用了cyan颜色,除非浏览器宽度至少为800px,否则将变为purple:
p { color: cyan; @media (min-width: 800px) { color: purple; } }
CSS原生嵌套问题
原生嵌套在:is()中包裹父选择器,这可能会导致与Sass输出的差异。考虑下列的嵌套代码:
.parent1, #parent2 { .child1 {} }
在浏览器中解析时,这实际上变成了以下内容:
:is(.parent1, #parent2) .child1 {}
.parent1中的.child1元素的优先级为101,因为:is()使用了其最优先选择器的优先级--在本例中,是#parent2 ID。Sass编译的代码与此相同:
.parent1 .child1, #parent2 .child1 { }
在本例中,.parent1 中的 .child1 元素的特异性为 002,因为它匹配两个类(#parent2 被忽略)。它的选择器比原生选项的优先级低,在级联中被覆盖的可能性更大。你可能还会遇到一个更微妙的问题。考虑下列代码:
.parent .child { .grandparent & {} }
原生CSS等价于:
.grandparent :is(.parent .child) {}
这与下列排序错误的HTML元素相匹配:
<div class="parent"> <div class="grandparent"> <div class="child">MATCH</div> </div> </div>
由于CSS解析器会执行以下操作,因此MATCH会改变样式:
1. 在DOM层次结构中的任意位置,找到所有类为child的元素,同时祖先元素的类为parent。
2. 在找到包含MATCH的元素后,解析器会检查该元素是否有一个祖先为grandparent的元素--同样是在DOM层次结构中的任意位置。找到后,解析器会相应地对该元素应用样式。
在Sass中不是这种情况,最终会编译成这样:
.grandparent .parent .child {}
上面的HTML没有样式化,因为元素的类没有遵循严格的grandparent、parent和child顺序。最后,Sass使用字符串替换,所以像下面这样的声明是有效的,可以匹配任何具有outer-space类的元素:
.outer { &-space { color: black; } }
而原生CSS会忽略&-space选择器。
还需要CSS预处理器吗
在短期内,现有的CSS预处理器仍然必不可少。
Sass开发团队已经宣布,他们将支持.css文件中的原生CSS嵌套,并按原样输出代码。他们将一如既往地编译嵌套的SCSS代码,以避免破坏现有代码库,但当全球浏览器支持率达到98%时,他们将开始输出:is()选择器。
我猜测PostCSS插件等预处理器目前会扩展嵌套代码,但当浏览器支持率越来越高时,就会移除该功能。
当然,使用预处理器还有其他很好的理由--比如将部分代码捆绑到单一文件中,以及精简代码。但如果嵌套是你唯一需要的功能,那么你当然可以考虑在小型项目中使用本地CSS。
总结
CSS嵌套是最有用、最实用的预处理器功能之一。浏览器供应商努力创造了一个本地CSS版本,其相似性足以让Web开发人员满意。虽然两者之间存在细微差别,而且在使用(过于)复杂的选择器时可能会遇到不寻常的优先级问题,但很少有代码库需要进行彻底修改。
原生嵌套可能会让你重新考虑对CSS预处理器的需求,但它们仍能提供其他好处。Sass和类似工具仍然是大多数开发人员工具包的重要组成部分。
前端开发
网站建设
网站开发
阅读排行
-
1. 几行代码就能实现Html大转盘抽奖
大转盘抽奖是网络互动营销的一种常见形式,其通过简单易懂的界面设计,让用户在游戏中体验到乐趣,同时也能增加商家与用户之间的互动。本文将详细介绍如何使用HTML,CSS和JavaScript来实现大转盘抽奖的功能。
查看详情 -
2. 浙江省同区域公司地址变更详细流程
提前准备好所有需要的资料,包含:房屋租赁合同、房产证、营业执照正副本、代理人身份证正反面、承诺书(由于我们公司其中一区域已有注册另外一公司,所以必须需要承诺书)
查看详情 -
3. 微信支付商户申请接入流程
微信支付,是微信向有出售物品/提供服务需求的商家提供推广销售、支付收款、经营分析的整套解决方案,包括多种支付方式,如JSAPI支付、小程序支付、APP支付H5支付等支付方式接入。
查看详情 -
4. 阿里云域名ICP网络备案流程
根据《互联网信息服务管理办法》以及《非经营性互联网信息服务备案管理办法》,国家对非经营性互联网信息服务实行备案制度,对经营性互联网信息服务实行许可制度。
查看详情 -
5. 微信小程序申请注册流程
微信小程序注册流程与微信公众号较为相似,同时微信小程序支持通过已认证的微信公众号进行注册申请,无需进行单独认证即可使用,同一个已认证微信公众号可同时绑定注册多个小程序。
查看详情