css类选择器或逻辑,深入理解CSS中选择器的逻辑处理

在过去的很长一段时间中,我们都说 CSS 是不带有任何逻辑的,意思是在 CSS 中没有控制流,也没有某种类似于其他编程语言的方式来组织 CSS。CSS 天生缺乏逻辑性的问题导致了预处理器的出现。然而业界却对 CSS 预处理器褒贬不一,支持预处理器的人认为这弥补了 CSS 缺失的特性;而反对预处理器的人则认为 CSS 的设计初衷就不应该带有逻辑性,他们认为根本不应该引入预处理器这个概念。

然而,一种独特的思考方法最近突然蹦入了我的脑袋。它让我感到 CSS 确实拥有逻辑性!很少有人真正那么想过,这大概也是我们一直认为 CSS 的逻辑性匮乏的最大原因吧。

我发现我们可以将复合选择器理解为:主体部分 + 条件部分。首先来看一个例子:

CSS Code复制内容到剪贴板

div.sidebar .login-box a.btn span {

/*...*/

}

在这个复合选择器由主体部分是 span,而条件部分是 IF (inside .btn) AND IF (on a) AND IF (inside .login-box) AND IF (inside .sidebar) AND IF (on div)。

也就是说,一个选择器的每一部分都是一个 if 语句,需要在解析选择器时被满足(或者不满足)。有了这种微妙的而又全新的认识,如今我们回头再看看自己曾经写出的 CSS 代码,我们将会意识到选择器写的好或者坏,会对效率产生直接的影响。我们真的会写出下面这段逻辑吗?(伪代码):

CSS Code复制内容到剪贴板

@if exists(span) {

@if is-inside(.btn) {

@if is-on(a) {

@if is-inside(.login-box) {

@if is-inside(.sidebar) {

@if is-on(div) {

# Do this.

}

}

}

}

}

}

也许不会。这看上去太不直接,也太啰嗦了。我们也许只需要这么写:

CSS Code复制内容到剪贴板

@if exists(.btn-text) {

# Do this.

}

每当为选择器添加一层限制,其实我们也就是添加了额外的一个 if 语句。这会导致圈复杂度问题(Cyclomatic Complexity)。

圈复杂度

在软件工程中,圈复杂度是一种程序复杂性的一种度量标准,它一般计算程序中的控制流的数量(如 if, else, while 等)。程序中存在越多的控制流,则圈复杂度就越高。我们自然想要保证圈复杂度能够尽量地低,因为圈复杂度越高:

代码就越难推导

更多潜藏着的、可能会导致失败的问题

代码更难以修改、维护以及复用

你需要考虑更多代码执行的结果与其副作用

编写测试代码的难度也会更高

从圈复杂度的角度来思考 CSS 的解析过程,我们可以看到浏览器在渲染样式之前需要做许多的决定。我们写的选择器中的 if 语句越多,这个选择器的圈复杂度就越高,这也意味着我们写的选择器越糟糕,为了使得这一条选择器规则满足,就有需要匹配更多的条件。同时,我们写的选择器也会缺乏清晰度和复用性,因为引入了过多不必要的 if 语句会导致不准确的匹配(false positive)。

相比于将 span 嵌套于 .btn 内部并写一大堆限制条件,更好地做法应该是创建一个新的类 .btn-text 来描述这个 span。这样做更加直截了当,同时也更为简洁和健壮(越多的 @if 语句导致选择器规则越不容易被满足)。

值得注意的是浏览器解析你写的选择器的方式:从右向左。如果你在写你的选择器时,第一个想到的问题是:“这是一个 span 元素吗?” 那你通常就会把选择器写的过于冗繁。你应该从另一个角度思考,写出清晰准确的选择器规则,彻底摒弃那些冗余的条件语句。

请不要写过于宽泛的规则,导致你写的选择器在匹配开始时就选中大量的 DOM 元素——然后不得不逐步通过更多的条件语句来删减匹配的对象。从选择器的规则解析的一开始就匹配尽量少的元素才是一种更棒的方法。

圈复杂度对于 CSS 来说可能是一种比较高阶的原则,但如果我们通过它来考量那些蕴含在我们写的选择器中的逻辑性,那我们也许就能写出更加优秀的代码。

一些易于遵守的小规则,

让你的选择器最简化:每一次你想要为选择器添加规则时,你都在添加额外的 if 语句。将这些 if 语句大声地读出来,仔细考虑它们是否有添加的必要。你需要时刻保持你写的选择器足够合理与简洁。

保证圈复杂度最小化: 使用像 Parker 这样的工具来测试你写的选择器的圈复杂度(参考文档:Identifiers Per Selector)

如果你不需要这个检验条件,那就不要把它放进选择器: 有时在 CSS 中使用嵌套结构是有必要的,可在大多数时候并不是,你甚至不能完全相信Inception Rule。

从右边考虑选择器如何编写: 从需要匹配的那类元素开始,写尽量少的额外的 CSS 代码来完成一次正确的匹配。

写选择器时拥有明确的目的性: 确保你写的选择器确实是你想要的,而不是那些碰巧能使得页面正常显示的代码。

你的选择器是你的 CSS 结构最基本的组成部分,一定要确保你写的代码足够合理而简练。

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

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

相关文章

JSF基于事件的交流:新派方法

在上一篇文章中 ,我们学习了基于Observer / Event Listener和Mediator模式的基于事件的通信。 由于它们的缺点,我想展示基于事件的通信的更有效方法。 我们将从Google Guava EventBus开始,以CDI (Java EE平台的上下文和依赖注入&a…

菜鸟之路-浅谈设计模式之单例设计模式

单例设计模式 定义:确保一个类仅仅有一个实例,并且自行实例化并向整个系统提供这个实例。单例模式是一种经常使用的软件设计模式。在它的核心结构中仅仅包括一个被称为单例的特殊类。通过单例模式能够保证系统中一个类仅仅有一个实例并且该实例易于外界訪…

python 32bit数据结构_python实现bitmap数据结构详解

bitmap是很常见的算法设计,例如用以Bloom Filter中;用以无反复整数金额的排列这些。bitmap一般根据数组来完成,数组中每一个原素能够当做是一系列二进制数,全部元素组成更高的二进制结合。针对Python而言,整数金额种类…

MVC如何使用开源分页插件shenniu.pager.js

最近比较忙,前期忙公司手机端接口项目,各种开发调试发布现在几乎上线无问题了;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情,一者使用aspnetcore开发了个人线上项目(要说线上其实只能ip访问,…

四. 基于环视Camera的BEV感知算法-PETR

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比5. PETRv2总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习下课程第四章——基…

Java EE 6 VS Spring 3:Java EE已经杀死了Spring? 没门!

介绍 几天前,我在听Java Spotlight Podcast的插曲85 。 在这次演讲中, Bert Ertman和Paul Bakker讨论了从Spring迁移到Java EE。 基本上,在他们的介绍中,他们说,如今,选择Spring而不是Java EE是没有意义的。…

usb检测串口是哪个角_怎样测试串口和串口线是否正常

一步:把串口线或者USB转串口线插到计算机上。二步:打开串口调试助手接着选择串口,串口线和 USB 转串口的端口号查看路径:电脑上--右键--属性--硬件--设备管理器-端口(COM 和LPT),点开端口前面的号查看即可。注释:1、US…

NodeJS常用模块介绍

收集了NodeJS开发中常用的一些模块。MVC框架 - Express Express 是轻量灵活的Nodejs Web应用框架,它可以快速地搭建网站。Express框架建立在Nodejs内置的Http模块上,并对Http模块再包装,从而实际Web请求处理的 功能。它支持多种前端模板&…

Java泛型面试问题

Java面试中的通用面试问题在相当长的时间内在Java 5周围越来越普遍,许多应用程序都转移到Java 5上,并且几乎所有新的Java开发都发生在Tiger(Java 5的代号)上。 泛型和Java 5功能(例如Enum)的重要性&#xf…

隐层元素闪一下_太阳一直依靠什么元素在燃烧,地球上的重元素又是怎么来的?...

本文基于回答网友一个这样的问题:太阳目前氢核聚变是氦碳氧稳定燃烧地球上的铁镍重元素哪里来的?可以说,这是一个毫无逻辑乱七八糟的问题,但既然邀请回答,就从中挑出几个稍显合理的问题说明一下。太阳核心每时每刻都在…

基于Token的WEB后台认证机制

基于Token的WEB后台认证机制 几种常用的认证机制 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可&#xf…

JSF基于事件的沟通:过时的方法

用JSF编写的Web应用程序由相互交互的bean组成。 在开发Web应用程序时,bean之间的通信是主要的设计模式之一。 有时,一个bean需要向其他bean发送事件,以通知它们某些更改或其他任何更改。 我们通常可以将托管bean或Spring bean注入另一个bean的…

mysql调优 基础

MySQL调优可以从几个方面来做:1. 架构层:做从库,实现读写分离;2.系统层次:增加内存;给磁盘做raid0或者raid5以增加磁盘的读写速度;可以重新挂载磁盘,并加上noatime参数,这…

saltstack

第一:安装前准备: 声明我用的是ubuntu 16.04的系统 1.修改主机名,并保证两台机器可以互相ping同主机名 ip1 master_hostname ip2 slave_hostname 第二:安装 服务器安装 yum install salt-master -y客户端安装 yum install salt…

ios 百度地图指定区域_获取百度地图可视区域范围的数据

有个业务场景,需要根据获取到的地图区域显示,根据相应的经纬度反查 左侧区域的会议室。思路:1.得到百度地图可视区域--可视区域的中心点2.可视区域的四个角的其中两个(东北角西南角)http://lbsyun.baidu.com/cms/jsapi/reference/jsapi_refer…

使用WS-Trust / STS采样器扩展JMeter

JMeter没有对WS-Security或WS-Trust的任何内置支持,这使我为JMeter开发了此STS Sampler –可以在负载测试STS时使任何人的生活变得更好。 首先,您需要拥有Apache JMeter发行版。 我正在使用v2.7。 然后,您可以从此处下载sts.sampler.zip –解…

分享一个使用闭包对一个对象继承方式

function Person(name,age){this.name name;this.age age; }//定义一个new函数 继承了对Person的继承 function New(obj){return function(){var o {"__proto__":obj.proto};obj.apply(o,arguments);}return obj; }var n new New(Person)("对象继承了person…

vue怎么改logo_vue全家桶项目构建教程

前言vue是现阶段很流行的前端框架,很多人通过vue官方文档的学习,对vue的使用都有了一定的了解,但再在项目工程化处理的时候,却发现不知道改怎么更好的管理自己的项目,如何去引入一些框架以及vue全家桶其他框架的使用&a…

EclipseLink MOXy作为JAXB提供者

EclipseLink MOXy是JAXB提供程序,并且是内置在JDK中的默认JAXB提供程序的引人注目的替代品。 首先是一个简单的测试,将Java对象编组为XML: 这是模型: XmlRootElement(nameMemberDetailsRequest, namespacehttp://bk.org/members…

monkeyrunner多点触摸

思路是:在屏幕上某个位置按着不放:device.touch(x,y,md.DOWN) 然后再做一个滑动的操作:device.drap((x1,y1),(x2,y2),0.2,10) 然后再松开按键:device.touch(x,y,md.UP) #codeing:utf-8 from com.android.monkeyrunner import Monk…