呜啦!日常碎碎念,偶尔掉落优质前端博文推荐、学习资源等
网页:https://tg.cosine.ren
本频道的搜索Bot 来辣 👉 @cosSearchBot
私聊直接发消息就可以搜索啦~
🔖tags
#优质博文 #资源推荐 #博客更新 #碎碎念 #项目更新 #手工 #书摘 #阮一峰的科技周刊 #新动态
图频:Cosine 🎨 Gallery @CosineGallery
猫片: @cosine_cat
网页:https://tg.cosine.ren
本频道的搜索Bot 来辣 👉 @cosSearchBot
私聊直接发消息就可以搜索啦~
🔖tags
#优质博文 #资源推荐 #博客更新 #碎碎念 #项目更新 #手工 #书摘 #阮一峰的科技周刊 #新动态
图频:Cosine 🎨 Gallery @CosineGallery
猫片: @cosine_cat
#碎碎念 #项目更新
于是把 tg channel 部署了个网页先🥰 确实简洁好用
(其实一开始不部署是因为我觉得我搜索 bot 够用了,完全没考虑这茬)
(这个 tag 打的其实不太符合但是就这样吧)
https://tg.cosine.ren
感谢 BroadcastChannel
于是把 tg channel 部署了个网页先
(其实一开始不部署是因为我觉得我搜索 bot 够用了,完全没考虑这茬)
(这个 tag 打的其实不太符合但是就这样吧)
https://tg.cosine.ren
感谢 BroadcastChannel
#书摘
《CSS 新世界》符合CSS世界“流”概念的逻辑属性margin-inline-end
在CSS2.1时代,CSS属性的定位都是基于方向的,而不是“流”。这样的设计其实是有问题的,基于方向进行定位虽然符合现实世界认知,但和CSS世界基于“流”的底层设计理念不符,margin-right就是一个基于方向的CSS属性,因为right表示右侧,和现实世界的右侧匹配。
通常情况下,我们这么使用是不会有任何问题的。但是,如果开发者使用direction属性改变了文档的水平流向,希望按钮从右往左排列,就会有预期之外的表现,此时margin-right产生的间隙就不是我们想要的,margin-left 才是我们想要的。
但是,如果我们一开始设置的不是符合现实世界认知的margin-right属性,而是符合CSS世界“流”概念的逻辑属性margin-inline-end,代码如下:
也就是说,当文档流的方向是从左往右的时候,margin-inline- end属性的渲染表现就等同于margin-right属性;当文档流的方向是从右往左的时候,margin-inline-end属性的渲染表现就等同于margin-left属性。
存在非常适合使用这类CSS逻辑属性的场景,那就是对称布局,例如,模拟微信对话的效果就是典型的对称布局。只需要使用CSS逻辑属性实现一侧的布局效果,然后另外一侧的布局效果我们只需要使用一句direction:rtl就完成了。
https://memo.cosine.ren/m/419
《CSS 新世界》符合CSS世界“流”概念的逻辑属性margin-inline-end
在CSS2.1时代,CSS属性的定位都是基于方向的,而不是“流”。这样的设计其实是有问题的,基于方向进行定位虽然符合现实世界认知,但和CSS世界基于“流”的底层设计理念不符,margin-right就是一个基于方向的CSS属性,因为right表示右侧,和现实世界的右侧匹配。
通常情况下,我们这么使用是不会有任何问题的。但是,如果开发者使用direction属性改变了文档的水平流向,希望按钮从右往左排列,就会有预期之外的表现,此时margin-right产生的间隙就不是我们想要的,margin-left 才是我们想要的。
但是,如果我们一开始设置的不是符合现实世界认知的margin-right属性,而是符合CSS世界“流”概念的逻辑属性margin-inline-end,代码如下:
button {
margin-inline-end: 10px;
}
那么我们使用direction属性改变文档的水平流向是不会出现布局上的任何问题的margin-inline-end
是一个“流淌”在文档流中的CSS逻辑属性,表示内联元素文档流结束的方向。也就是说,当文档流的方向是从左往右的时候,margin-inline- end属性的渲染表现就等同于margin-right属性;当文档流的方向是从右往左的时候,margin-inline-end属性的渲染表现就等同于margin-left属性。
存在非常适合使用这类CSS逻辑属性的场景,那就是对称布局,例如,模拟微信对话的效果就是典型的对称布局。只需要使用CSS逻辑属性实现一侧的布局效果,然后另外一侧的布局效果我们只需要使用一句direction:rtl就完成了。
https://memo.cosine.ren/m/419
#书摘
《CSS 新世界》3.1.3 深入了解min-content关键字
1. 元素的 padding-box、border-box和margin-box的尺寸表现规则不会因为元素的不同而有所不同,但是content-box不一样,它随着内容的不同,首选最小宽度也会不同。
- 替换元素(按钮、视频和图片等元素)的首选最小宽度是当前元素内容自身的宽度。
- CJK文字,指的是中文、日文、韩文这几种文字。这里以中文为代表加以说明。如果是一段没有标点的中文文字,则首选最小宽度是单个汉字的宽度。如果包含避头标点或避尾标点,同时line-break的属性值不是anywhere,则最终的首选最小宽度需要包含标点字符的宽度
(连续的中文破折号都会被认为是一个字符单元。)
- 非CJK文字(除中文、日文、韩文之外的文字,如英文、数字和标点等字符)的首选最小宽度是由字符单元的宽度决定的,所有连续的英文字母、数字和标点都被认为是一个字符单元,直到遇到中断字符。
首先无论是哪个浏览器,Space空格(U+0020)都能中断字符单元,并且忽略Space空格前后字符的类型。而其他字符的中断规则在每个浏览器中都是不一样的。
2. 一个元素最终的首选最小宽度是所有内部子元素中最大的那个首选最小宽度值
https://memo.cosine.ren/m/418
《CSS 新世界》3.1.3 深入了解min-content关键字
min-content
关键字实际上就是CSS2.1规范中提到的“preferred minimum width”或者“minimum content width”,即“首选最小宽度”或者“最小内容宽度”。1. 元素的 padding-box、border-box和margin-box的尺寸表现规则不会因为元素的不同而有所不同,但是content-box不一样,它随着内容的不同,首选最小宽度也会不同。
- 替换元素(按钮、视频和图片等元素)的首选最小宽度是当前元素内容自身的宽度。
- CJK文字,指的是中文、日文、韩文这几种文字。这里以中文为代表加以说明。如果是一段没有标点的中文文字,则首选最小宽度是单个汉字的宽度。如果包含避头标点或避尾标点,同时line-break的属性值不是anywhere,则最终的首选最小宽度需要包含标点字符的宽度
(连续的中文破折号都会被认为是一个字符单元。)
- 非CJK文字(除中文、日文、韩文之外的文字,如英文、数字和标点等字符)的首选最小宽度是由字符单元的宽度决定的,所有连续的英文字母、数字和标点都被认为是一个字符单元,直到遇到中断字符。
首先无论是哪个浏览器,Space空格(U+0020)都能中断字符单元,并且忽略Space空格前后字符的类型。而其他字符的中断规则在每个浏览器中都是不一样的。
2. 一个元素最终的首选最小宽度是所有内部子元素中最大的那个首选最小宽度值
https://memo.cosine.ren/m/418
#书摘 #css #前端
《CSS 选择器世界》 默认选项:default伪类
CSS :default伪类选择器只能作用在表单元素上,匹配处于默认状态的表单元素。
虽然:default伪类用来标记默认状态,以避免选择混淆,但实际上,它更有实用价值的应用应该是“推荐标记”。
例如,某产品有多个支付选项,其中商家推荐使用微信支付
以前的做法是默认选中微信支付选项,并在后面加上“(推荐)”。这样实现有一个缺点:如果以后要改变推荐的支付方式,需要修改单选框的checked属性和“(推荐)”文字的位置。
有了:default伪类,可以让它变得更加简洁,也更容易维护。
由于:default伪类的匹配不受之后checked属性值变化的影响,因此“(推荐)”会一直跟在“微信”的后面,功能不会发生变化。这样做之后维护更方便了,例如,如果以后想将推荐支付方式更换为“支付宝”,则直接设置“支付宝”对应的
读者可以手动输入 https://demo.cssworld.cn/selector2/11/1-3.php 体验与学习。
https://memo.cosine.ren/m/401
《CSS 选择器世界》 默认选项:default伪类
CSS :default伪类选择器只能作用在表单元素上,匹配处于默认状态的表单元素。
虽然:default伪类用来标记默认状态,以避免选择混淆,但实际上,它更有实用价值的应用应该是“推荐标记”。
例如,某产品有多个支付选项,其中商家推荐使用微信支付
以前的做法是默认选中微信支付选项,并在后面加上“(推荐)”。这样实现有一个缺点:如果以后要改变推荐的支付方式,需要修改单选框的checked属性和“(推荐)”文字的位置。
有了:default伪类,可以让它变得更加简洁,也更容易维护。
input:default + label::after {
content: '(推荐)';
}
<p><input type="radio" name="pay" id="pay0"> <label for="pay0">支付宝</label></p>
<p><input type="radio" name="pay" id="pay1" checked> <label for="pay1">微信</label></p>
<p><input type="radio" name="pay" id="pay2"> <label for="pay2">银行卡</label></p>
由于:default伪类的匹配不受之后checked属性值变化的影响,因此“(推荐)”会一直跟在“微信”的后面,功能不会发生变化。这样做之后维护更方便了,例如,如果以后想将推荐支付方式更换为“支付宝”,则直接设置“支付宝”对应的
<input>
单选框为checked状态即可,“(推荐)”文字会自动跟在“支付宝”的后面,整个过程我们只需要修改一处代码。读者可以手动输入 https://demo.cssworld.cn/selector2/11/1-3.php 体验与学习。
https://memo.cosine.ren/m/401
#书摘 #css #前端
《CSS 选择器世界》 占位符显示伪类 :placeholder-shown
:placeholder-shown 伪类的匹配和 placeholder 属性密切相关。:placeholder-shown顾名思义就是“占位符显示伪类”,表示当输入框的placeholder内容显示的时候,匹配该输入框。使用场景如下
1.可用于实现Material Design风格占位符交互效果:输入框处于聚焦状态时,输入框的占位符内容以动画形式移动到左上角作为标题存在。
首先,使浏览器默认的 placeholder 效果不可见,只需将 color 设置为 transparent,CSS如下:
然后,用下面的.input-label元素替代浏览器原生的占位符而成为我们看到的占位符。我们可以采用绝对定位:
最后,在输入框聚焦以及占位符不显示的时候对
效果达成!显然,这要比使用JavaScript写各种事件和判断各种场景简单多了。
眼见为实,读者可以手动输入 https://demo.cssworld.cn/selector2/11/1-1.php 体验与学习。
2.:placeholder-shown与空值判断
由于placeholder内容只在空值状态的时候才显示,因此我们可以借助:placeholder- shown伪类来判断一个输入框中是否有值。
例如:
可以看到输入框中尚未输入内容的时候出现了空值提示信息
https://memo.cosine.ren/m/400
《CSS 选择器世界》 占位符显示伪类 :placeholder-shown
:placeholder-shown 伪类的匹配和 placeholder 属性密切相关。:placeholder-shown顾名思义就是“占位符显示伪类”,表示当输入框的placeholder内容显示的时候,匹配该输入框。使用场景如下
1.可用于实现Material Design风格占位符交互效果:输入框处于聚焦状态时,输入框的占位符内容以动画形式移动到左上角作为标题存在。
首先,使浏览器默认的 placeholder 效果不可见,只需将 color 设置为 transparent,CSS如下:
/* 默认placeholder颜色透明不可见 */
.input-fill:placeholder-shown::placeholder {
color: transparent;
}
然后,用下面的.input-label元素替代浏览器原生的占位符而成为我们看到的占位符。我们可以采用绝对定位:
.input-fill-x {
position: relative;
}
.input-label {
position: absolute;
left: 16px; top: 14px;
pointer-events: none;
}
最后,在输入框聚焦以及占位符不显示的时候对
<label>
元素进行重定位(缩小并移动到上方):
.input-fill:not(:placeholder-shown) ~ .input-label,
.input-fill:focus ~ .input-label {
transform: scale(0.75) translate(0, -32px);
}
效果达成!显然,这要比使用JavaScript写各种事件和判断各种场景简单多了。
眼见为实,读者可以手动输入 https://demo.cssworld.cn/selector2/11/1-1.php 体验与学习。
2.:placeholder-shown与空值判断
由于placeholder内容只在空值状态的时候才显示,因此我们可以借助:placeholder- shown伪类来判断一个输入框中是否有值。
例如:
textarea:placeholder-shown + small::before,
input:placeholder-shown + small::before {
content: '尚未输入内容';
color: red;
font-size: 87.5%;
}
<input placeholder=" "> <small></small>
<textarea placeholder=" "></textarea> <small></small>
可以看到输入框中尚未输入内容的时候出现了空值提示信息
https://memo.cosine.ren/m/400
#书摘 #css #前端
《CSS 选择器世界》 :target 伪类与锚点
假设浏览器地址栏中的地址如下:
则
URL锚点可以和页面中id匹配的元素进行锚定,浏览器的默认行为是触发滚动定位,同时进行:target伪类匹配。
举个例子,假设页面有如下HTML代码:
以及如下CSS代码:
则第二行列表的颜色为天蓝色,同时文字加粗显示。
这就是:target伪类的作用——匹配URL锚点对应的元素。
https://memo.cosine.ren/m/399
《CSS 选择器世界》 :target 伪类与锚点
假设浏览器地址栏中的地址如下:
https://www.cssworld.cn/#cs-anchor
则
#cs-anchor
就是“锚点”,对应术语是哈希,即JavaScript中location.hash的返回值。URL锚点可以和页面中id匹配的元素进行锚定,浏览器的默认行为是触发滚动定位,同时进行:target伪类匹配。
举个例子,假设页面有如下HTML代码:
<ul>
<li id="cs-first">第1行,id是cs-first</li>
<li id="cs-anchor">第2行,id是cs-anchor</li>
<li id="cs-last">第3行,id是cs-last</li>
</ul>
以及如下CSS代码:
li:target {
font-weight: bold;
color: skyblue;
}
则第二行列表的颜色为天蓝色,同时文字加粗显示。
这就是:target伪类的作用——匹配URL锚点对应的元素。
https://memo.cosine.ren/m/399
#书摘 #css #前端
《CSS 选择器世界》 姗姗来迟的关联伪类 :has()
:has() 伪类是一个功能非常强大的伪类,它可以实现类似父选择器和前面兄弟选择器的功能。
:has()伪类的语义非常明确,和渲染表现保持一致。举个简单的例子,下面的CSS代码表示如果
类似地,我们还可以使用+或者~这样的选择符实现“前面兄弟选择器”的效果,即根据后面的兄弟元素选择前面的元素。例如:
理论上,有了:has()伪类,页面中任意DOM元素变化都可以被其他DOM元素感知到
https://memo.cosine.ren/m/398
《CSS 选择器世界》 姗姗来迟的关联伪类 :has()
:has() 伪类是一个功能非常强大的伪类,它可以实现类似父选择器和前面兄弟选择器的功能。
:has()伪类的语义非常明确,和渲染表现保持一致。举个简单的例子,下面的CSS代码表示如果
<a>
元素里面有 <img>
元素,则 <a>
元素就匹配:
a:has(img) { display: block; }
类似地,我们还可以使用+或者~这样的选择符实现“前面兄弟选择器”的效果,即根据后面的兄弟元素选择前面的元素。例如:
h5:has(+ p) { font-size: 1rem; }
理论上,有了:has()伪类,页面中任意DOM元素变化都可以被其他DOM元素感知到
https://memo.cosine.ren/m/398
#书摘 #css #前端
《CSS 选择器世界》 实用的优先级调整伪类
的优先级等同于p选择器,参数中的选择器的优先级被完全忽略。
我们可以巧妙地借助这一特性来降低某些全局 CSS 的优先级。相比使用@layer规则降低 CSS 的优先级,使用 :where() 伪类的方法更敏捷且兼容性更好。
https://memo.cosine.ren/m/397
《CSS 选择器世界》 实用的优先级调整伪类
:where()
:where()
伪类的优先级永远是0,完全忽略其中参数选择器的优先级。例如:
:where(.article, section) p {}
的优先级等同于p选择器,参数中的选择器的优先级被完全忽略。
我们可以巧妙地借助这一特性来降低某些全局 CSS 的优先级。相比使用@layer规则降低 CSS 的优先级,使用 :where() 伪类的方法更敏捷且兼容性更好。
https://memo.cosine.ren/m/397
#书摘 #css #前端
《CSS 选择器世界》 任意匹配伪类:
1.
先讲解
:is()伪类的一大作用是简化选择器。例如,平时开发中经常会遇到类似下面的CSS代码:
此时就可以使用:is()伪类进行简化:
这种简化只是一维的,:is()伪类的优势并不明显,但如果选择器是交叉组合的,:is()伪类就大放异彩了。例如,有序列表和无序列表可以相互嵌套,假设有两层嵌套,则最里面的
如果使用:is()伪类进行简化,则只有下面这几行代码:
2.
按道理讲,下面两行CSS语句中的选择器所匹配的元素是没有任何区别的,因为此时:is()伪类仅仅是一个无关紧要的语法糖,既不影响选择器的优先级,也不影响匹配的规则:
如果是在常规的开发场景中,确实如此,但要是在Vue或者React等成熟的框架中,则情况就会不同,可以利用这种特性让我们的开发变得更顺畅。
以Vue框架为例,在Vue框架中,无论是构建模块还是组件,都会使用设置了scoped属性的样式,目的是让CSS私有,避免和外部CSS发生冲突。例如:
此时框架会给类名.logo创建随机的属性选择器,这样可以确保.logo匹配的元素在当前Vue模块中是唯一的。
但是当我们需要匹配的元素是动态生成的时候(业务逻辑插入或者第三方组件),这种给类名添加随机属性选择器的特性可能会导致元素无法匹配。例如运行下面这段JavaScript代码:
此时插入的
如果此时希望可以匹配这个

虽然:is()伪类因这一特性在意想不到的地方发挥着作用,但其还是有令人遗憾的地方,尤其是不支持伪元素这一点::is()伪类并不支持伪元素,例如:is(::before, ::after)是不合法的,这是个巨大的遗憾。
目前现代浏览器已经全面支持:is()伪类,大家可以在一些内部项目中大胆使用。
https://memo.cosine.ren/m/362
《CSS 选择器世界》 任意匹配伪类:
is()
:is()
伪类可以把括号中的选择器依次分配出去,这对于复杂的有很多逗号分隔的选择器或者浏览器可能不支持的选择器非常有用。
:is()
伪类本身的优先级为0,整个选择器的优先级是由:is()伪类里参数优先级最高的那个选择器决定的。例如: :is(#article, .section) p {}
优先级等同于 #article p
。这是由参数中优先级最高的选择器决定的。1.
:is()
伪类的语法和两大作用先讲解
:is()`伪类的语法。和 :
not()` 伪类不同,`:is()` 伪类的参数从一开始就支持复杂选择器或复杂选择器列表。例如,下面的写法都是合法的:
/* 简单选择器 */
:is(article) p {}
/* 简单选择器列表 */
:is(article, section) p {}
/* 复杂选择器 */
:is(.article[class], section) p {}
/* 带逻辑伪类的复杂选择器 */
.some-class:is(article:not([id]), section) p {}
:is()伪类的一大作用是简化选择器。例如,平时开发中经常会遇到类似下面的CSS代码:
.cs-avatar-a > img,
.cs-avatar-b > img,
.cs-avatar-c > img,
.cs-avatar-d > img {
display: block;
width: 100%; height: 100%;
border-radius: 50%;
}
此时就可以使用:is()伪类进行简化:
:is(.cs-avatar-a, .cs-avatar-b, .cs-avatar-c, .cs-avatar-d) > img {
display: block;
width: 100%; height: 100%;
border-radius: 50%;
}
这种简化只是一维的,:is()伪类的优势并不明显,但如果选择器是交叉组合的,:is()伪类就大放异彩了。例如,有序列表和无序列表可以相互嵌套,假设有两层嵌套,则最里面的
<li>
元素存在下面4种可能的情况:
ol ol li,
ol ul li,
ul ul li,
ul ol li {
margin-left: 2em;
}
如果使用:is()伪类进行简化,则只有下面这几行代码:
css
:is(ol, ul) :is(ol, ul) li {
margin-left: 2em;
}
2.
:is()
伪类在Vue等框架中的妙用按道理讲,下面两行CSS语句中的选择器所匹配的元素是没有任何区别的,因为此时:is()伪类仅仅是一个无关紧要的语法糖,既不影响选择器的优先级,也不影响匹配的规则:
.box .some-class {}
.box :is(.some-class) {}
如果是在常规的开发场景中,确实如此,但要是在Vue或者React等成熟的框架中,则情况就会不同,可以利用这种特性让我们的开发变得更顺畅。
以Vue框架为例,在Vue框架中,无论是构建模块还是组件,都会使用设置了scoped属性的样式,目的是让CSS私有,避免和外部CSS发生冲突。例如:
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
}
</style>
此时框架会给类名.logo创建随机的属性选择器,这样可以确保.logo匹配的元素在当前Vue模块中是唯一的。
但是当我们需要匹配的元素是动态生成的时候(业务逻辑插入或者第三方组件),这种给类名添加随机属性选择器的特性可能会导致元素无法匹配。例如运行下面这段JavaScript代码:
const html = ’<img src=”/vite.svg“ class=”logo“ />‘
const app = document.getElementById(’app‘)
app.insertAdjacentHTML(’afterbegin‘, html)
此时插入的
<img>
元素是不会被框架添加随机属性值的(如图9-3所示),而 <style>
元素中类名却自动添加了属性选择器,导致样式无法匹配。如果此时希望可以匹配这个
<img>
元素,同时CSS代码又要写在设置了scoped属性的 <style>
元素中,该怎么办?除Vue框架内置的:deep()语法外,我们还可以使用:is()伪类。不知是出于什么考虑,所有:is()伪类中的选择器在Vue框架中都是不会添加随机属性选择器的(:where()伪类也有此特性),因此,我们可以利用这个特性,让设置了scoped属性的 <style>
元素中的CSS无属性匹配。例如,CSS代码可以这样书写:
<style scoped>
* > :is(.logo) {
height: 6em;
padding: 1.5em;
}
</style>
此时,CSS代码中的.logo选择器就是干干净净的类选择器,如图9-4所示,此时,哪怕页面中的HTML元素没有被组件添加随机属性值,也能被匹配了。
虽然:is()伪类因这一特性在意想不到的地方发挥着作用,但其还是有令人遗憾的地方,尤其是不支持伪元素这一点::is()伪类并不支持伪元素,例如:is(::before, ::after)是不合法的,这是个巨大的遗憾。
目前现代浏览器已经全面支持:is()伪类,大家可以在一些内部项目中大胆使用。
https://memo.cosine.ren/m/362
#书摘 #css #前端
《CSS 选择器世界》 不容小觑的逻辑组合伪类
标签选择器、属性选择器直接匹配元素,树结构伪类通过DOM结构进行匹配,而本章要介绍的伪类则通过逻辑进行匹配,这进一步增强了CSS选择器对HTML元素匹配的能力。
目前CSS中的逻辑组合伪类主要有4个,分别是
:not()伪类从IE9浏览器就开始支持,非常实用,务必掌握。其他3个伪类适用于无须兼容IE浏览器的项目,其中的:has()伪类是一个功能强大的伪类,可以实现类似于父选择器的效果,日后定是个“大杀器”,大家一定要重点关注。现在先从:not()伪类说起
1.
-
-
- 从2021年开始,所有现代浏览器均已支持在:not()伪类中使用多个表达式,例如下面这种写法是合法的:
:not()伪类的最大用处就是可以优化过去我们重置CSS样式的策略。由于重置样式在Web开发中非常常见,因此:not()伪类的适用场景非常广泛。例如:
(1)使代码更简洁。
(2)更易于理解。
(3)最重要的是**保护了原类名的优先级,扩展性更强**,更利于维护。
对于某类重置场景,如果:not()伪类使用不当,可能会有预料之外的情况出现。例如,对于一些阅读类的网站,希望
所以,对于这种场景,:not()伪类的使用并没有想象的那么简单,不过也不是不能实现,而是需要使用:not()伪类在CSS选择器Level4规范中的新语法,也就是使用选择符:
https://memo.cosine.ren/m/357
《CSS 选择器世界》 不容小觑的逻辑组合伪类
标签选择器、属性选择器直接匹配元素,树结构伪类通过DOM结构进行匹配,而本章要介绍的伪类则通过逻辑进行匹配,这进一步增强了CSS选择器对HTML元素匹配的能力。
目前CSS中的逻辑组合伪类主要有4个,分别是
:not()
、`:is()` 、`:
where()` 和 :has()
。这4个伪类自身的优先级都是0,当伪类选择器自身和括号里的参数作为一个整体时,整个选择器的优先级各有差异,有的由参数选择器决定,如:not(),有的参数选择器的优先级也是0,如:where()。:not()伪类从IE9浏览器就开始支持,非常实用,务必掌握。其他3个伪类适用于无须兼容IE浏览器的项目,其中的:has()伪类是一个功能强大的伪类,可以实现类似于父选择器的效果,日后定是个“大杀器”,大家一定要重点关注。现在先从:not()伪类说起
1.
:not()
是否定伪类,如果当前元素与括号里的选择器不匹配,则该伪类会进行匹配。:not()伪类其他相关细节如下。-
:not(
伪类的优先级是0,即最终选择器的优先级是由括号里的表达式决定的。例如 :not(p) {}
的优先级就是p选择器的优先级。-
:not(
伪类可以不断级联。例如:input:not(:disabled):not(:read-only) {}
表示匹配所有不处于禁用状态也不处于只读状态的 <input>
元素。- 从2021年开始,所有现代浏览器均已支持在:not()伪类中使用多个表达式,例如下面这种写法是合法的:
/* 现代浏览器均支持 */
.cs-li:not(li, dd) {}
但是在过去,浏览器是无法解析上述用法的,需要使用下面这种冗长的写法代替:.cs-li:not(li):not(dd) {}
在过去,下面几种写法也不支持,但是现在没有这个限制了,只要项目无须兼容IE浏览器,就可以放心使用。/* 过去不支持,现在均支持 */
input:not(:disabled:read-only) {}
input:not(p:read-only) {}
input:not([id][title]) {}
此外,`:not()` 伪类的参数值不仅可以是选择器,还支持选择符。例如下面的语句也是可以被现代浏览器解析的:/* 现代浏览器均支持 */
input:not(.a > .b) { border: red solid; }
2. 告别重置,全部交给:not()伪类:not()伪类的最大用处就是可以优化过去我们重置CSS样式的策略。由于重置样式在Web开发中非常常见,因此:not()伪类的适用场景非常广泛。例如:
.cs-panel {
display: none;
}
.cs-panel.active {
display: block;
}
实际上,这种效果有更好的实现方式,那就是使用:not()伪类,推荐使用下面的CSS代码:.cs-panel:not(.active) {
display: none;
}
使用:not()伪类有如下优点。(1)使代码更简洁。
(2)更易于理解。
(3)最重要的是**保护了原类名的优先级,扩展性更强**,更利于维护。
对于某类重置场景,如果:not()伪类使用不当,可能会有预料之外的情况出现。例如,对于一些阅读类的网站,希望
<article>
元素内的 <ol>`、 `<ul>
元素依然保留默认的样式,不希望被重置。传统的实现一般是外部CSS重置,在 <article>
元素里再还原,CSS示意代码如下:ol, ul {
padding: 0;
margin: 0;
list-style-type: none;
}
article ol,
article ul {
all: revert;
}
有些读者学了本节的内容后会想到使用:not()伪类来实现,然后使用了如下的CSS代码::not(article) ol,
:not(article) ul {
padding: 0;
margin: 0;
list-style-type: none;
}
实际上这是有问题的。例如,有如下HTML代码:<article>
<div>
<ol>
<li>内容1</li>
<li>内容2</li>
<li>内容3</li>
</ol>
</div>
</article>
这里的 <ol>
元素的margin和padding等CSS属性样式理论上不应该被重置,但实际上这些样式都被重置了,因为 <ol>
元素外面的 <div>
元素也匹配 :not(article) ol
选择器。所以,对于这种场景,:not()伪类的使用并没有想象的那么简单,不过也不是不能实现,而是需要使用:not()伪类在CSS选择器Level4规范中的新语法,也就是使用选择符:
ol:not(article ol),
ul:not(article ul) {
padding: 0;
margin: 0;
list-style-type: none;
}
上面的例子有演示页面,读者可以通过链接https://demo.cssworld.cn/selector2/9/1-1.php 访问。https://memo.cosine.ren/m/357
#书摘 #css #前端
《CSS 选择器世界》匹配类型的子索引伪类 ——
1.
- :nth-of-type() 伪类和 :nth-child() 伪类的相同之处是它们的语法一
- :nth-of-type() 伪类和 :nth-child() 伪类的不同之处是::nth-of-type() 伪类的匹配范围是所有相同标签的相邻元素, 而:nth-child() 伪类会匹配所有相邻元素,忽略标签类型。
-
2. :nth-of-type() 伪类适用于特定标签组合且这些组合会不断重复的场景。在整个HTML中,这样的组合元素并不多见,较为典型的是“dt+dd”组合:
以及“details > summary”组合:
这段代码中的
https://memo.cosine.ren/m/355
《CSS 选择器世界》匹配类型的子索引伪类 ——
:nth-of-type()
伪类和 :nth-last-of-type()
伪类1.
:nth-of-type()
伪类匹配指定索引的当前标签类型元素,:nth-of-type()伪类从前面开始匹配,而:nth-last-of-type()伪类从后面开始匹配。- :nth-of-type() 伪类和 :nth-child() 伪类的相同之处是它们的语法一
- :nth-of-type() 伪类和 :nth-child() 伪类的不同之处是::nth-of-type() 伪类的匹配范围是所有相同标签的相邻元素, 而:nth-child() 伪类会匹配所有相邻元素,忽略标签类型。
-
2. :nth-of-type() 伪类适用于特定标签组合且这些组合会不断重复的场景。在整个HTML中,这样的组合元素并不多见,较为典型的是“dt+dd”组合:
<dl>
<dt>标题1</dt>
<dd>内容1</dd>
<dt>标题2</dt>
<dd>内容2</dd>
</dl>
以及“details > summary”组合:
<details open>
<summary>订单中心</summary>
<a href>我的订单</a>
<a href>我的活动</a>
<a href>评价晒单</a>
<a href>购物助手</a>
</details>
这段代码中的
<a>
元素就可以使用 :nth-of-type()
伪类进行匹配。https://memo.cosine.ren/m/355
#书摘 #css #前端
《CSS 选择器世界》匹配类型的子索引伪类 ——
匹配类型的子索引伪类类似于子索引伪类,区别在于,匹配类型的子索引伪类是在同级列表中相同标签元素之间进行索引与解析的。
写HTML的时候要注意使用语义化标签,甚至可以使用自定义标签,因为要想使本节中的这些伪类在项目中大放异彩,离不开标签的区分,如果全部都是类是在同级列表中相元素,就无法使用这些伪类。
1.
结果:first-of-type伪类匹配了
如果有如下HTML代码,其中有多个
标题2和内容2不会被匹配
2.
3.
:only-of-type 表示匹配唯一的标签类型的元素。例如:
使用:only-of-type伪类也可以匹配例1中的
> :only-child伪类匹配的元素,:only-of-type伪类一定匹配。但是:only-of-type伪类匹配的元素,:only-child伪类不一定匹配。
:only-of-type伪类缺少典型的应用场景,大家需要根据实际情况适时使用。
https://memo.cosine.ren/m/354
《CSS 选择器世界》匹配类型的子索引伪类 ——
:first-of-type
伪类和 :last-of-type
伪类和 :only-of-type
伪类匹配类型的子索引伪类类似于子索引伪类,区别在于,匹配类型的子索引伪类是在同级列表中相同标签元素之间进行索引与解析的。
写HTML的时候要注意使用语义化标签,甚至可以使用自定义标签,因为要想使本节中的这些伪类在项目中大放异彩,离不开标签的区分,如果全部都是类是在同级列表中相元素,就无法使用这些伪类。
1.
:first-of-type
表示当前第一个标签类型的元素。例如:
dl > :first-of-type {
color: deepskyblue;
font-style: italic;
}
<dl>
<dt>标题</dt>
<dd>内容</dd>
</dl>
结果:first-of-type伪类匹配了
<dt>
和 <dd>
元素,文字表现为深天蓝色倾斜体如果有如下HTML代码,其中有多个
<dt>
和 <dd>
元素,则对于后面的 <dt>
和 <dd>
元素,`:first-of-type` 伪类不会匹配,文字表现为默认的黑色且非倾斜体,代码如下:
<dl>
<dt>标题1</dt>
<dd>内容1</dd>
<dt>标题2</dt>
<dd>内容2</dd>
</dl>
标题2和内容2不会被匹配
2.
:last-of-type
伪类的语法和匹配规则与 :first-of-type
的类似,区别在于,`:last-of-type` 伪类匹配最后一个同类型的标签元素。在上面的代码中就是匹配标题1和内容1。3.
:only-of-type
伪类:only-of-type 表示匹配唯一的标签类型的元素。例如:
使用:only-of-type伪类也可以匹配例1中的
<dt>
和 <dd>
元素,因为这两种类型的标签均只有一个。> :only-child伪类匹配的元素,:only-of-type伪类一定匹配。但是:only-of-type伪类匹配的元素,:only-child伪类不一定匹配。
:only-of-type伪类缺少典型的应用场景,大家需要根据实际情况适时使用。
https://memo.cosine.ren/m/354
#书摘 #css #前端
《CSS 选择器世界》nth-child()的参数索引特性
对于nth-child()、nth-last-child() 以及8.4.3节要介绍的 nth-of-type()、nth-last-of-type(),还有一种大家可能没见过的语法,就是使用 of 关键字配合特性的CSS选择器,对已经匹配的树结构元素进行进一步的匹配。例如,有如下HTML结构和CSS代码:
表示匹配所有子元素集合中的偶数项的
顺便提一下,选择器:nth-child(even of dd)和选择器dd:nth-child(even)是不一样的,even关键字是相对整个子元素而言的,而不是仅相对于
另外,of后面的选择器除了标签选择器,类名选择器、属性选择器都是支持的,可以让子元素的匹配更加精准可控。可惜这个特性目前仅被Safari浏览器支持,Chrome等浏览器暂时没有支持的迹象,因此,大家先了解即可。
https://memo.cosine.ren/m/353
《CSS 选择器世界》nth-child()的参数索引特性
对于nth-child()、nth-last-child() 以及8.4.3节要介绍的 nth-of-type()、nth-last-of-type(),还有一种大家可能没见过的语法,就是使用 of 关键字配合特性的CSS选择器,对已经匹配的树结构元素进行进一步的匹配。例如,有如下HTML结构和CSS代码:
<dl>
<dt>标题</dt>
<dd>列表1</dd>
<dd>列表2</dd>
<dd>列表3</dd>
<dt>标题</dt>
<dd>列表1</dd>
<dd>列表2</dd>
<dd>列表3</dd>
<dt>标题</dt>
<dd>列表1</dd>
<dd>列表2</dd>
<dd>列表3</dd>
</dl>
dl > :nth-child(even of dd) {
color: red;
font-weight: bold;
}
表示匹配所有子元素集合中的偶数项的
<dd>
元素。顺便提一下,选择器:nth-child(even of dd)和选择器dd:nth-child(even)是不一样的,even关键字是相对整个子元素而言的,而不是仅相对于
<dd>
元素。另外,of后面的选择器除了标签选择器,类名选择器、属性选择器都是支持的,可以让子元素的匹配更加精准可控。可惜这个特性目前仅被Safari浏览器支持,Chrome等浏览器暂时没有支持的迹象,因此,大家先了解即可。
https://memo.cosine.ren/m/353
#书摘 #css #前端
《CSS 选择器世界》:nth-child()伪类和:nth-last-child()伪类
:nth-last-child()伪类和:nth-child()伪类的区别在于:
:nth-last-child()伪类是从后面开始按指定序号匹配,而:nth-child()伪类是从前面开始匹配。
除此之外,无论是在兼容性还是语法方面,两者都没有区别。因此,本节会以:nth-child()为代表对这两个伪类进行详细且深入的介绍。
1. 从:nth-child()开始说起
在介绍语法之前,有必要提一句,:nth-child()伪类虽然功能很强大,但只适用于内容动态、无法确定的匹配场景。如果数据是纯静态的,哪怕是列表,都要使用类名或者属性选择器进行匹配。没有必要使用 :nth-child(),因为这样会增加选择器的优先级,且由于DOM结构严格匹配,无法随意调整,不利于维护。
:nth-child()伪类可以匹配指定索引序号的元素,支持一个参数,且必须有参数,参数可以是关键字值或者函数符号这两种类型。
(1)关键字值的形式如下。
●
●
可以这样记忆:如果字母个数是奇数(odd有3个字母),就匹配奇数个数的元素;如果字母个数是偶数(even有4个字母),就匹配偶数个数的元素。
奇偶匹配关键字多用在列表或者表格中,可以用来实现提升阅读体验的斑马线效果。
(2)函数符号的形式如下。
● An+B:其中A和B都是固定的数值,且必须是整数;n可以理解为从0开始的自然数序列(0, 1, 2, 3, …),n前面可以有负号。第一个子元素的匹配序号是1,小于1的计算序号会被忽略。
下面来看一些示例,快速了解一下各种类型的参数的含义。
●
●
●
●
●
●
●
●
●
2. 动态列表项数量匹配技术
聊天软件中的群头像或者一些书籍的分组往往采用复合头像作为一个大的头像,可以看到如果头像数量不同,布局就会不同。(如微信群组)
借助子索引伪类自动判断列表项的个数,从而实现我们想要的布局。在这个方法中,不需要在父元素上设置当前列表项的个数,因此,HTML看起来平淡无奇:
关键在于CSS,我们可以借助伪类判断当前列表项的个数,示意代码如下:
> 其中,:first-child:nth-last-child(2) 表示当前
以上是不是一个非常巧妙的实现呢?
总之,基于上面的数量匹配原理就能自动实现不同列表项数量下的不同布局效果,而无须设置专门表示列表项数量的类名或者属性。
读者可以手动输入 https://demo.cssworld.cn/selector2/8/3-3.php 体验与学习。
https://memo.cosine.ren/m/351
《CSS 选择器世界》:nth-child()伪类和:nth-last-child()伪类
:nth-last-child()伪类和:nth-child()伪类的区别在于:
:nth-last-child()伪类是从后面开始按指定序号匹配,而:nth-child()伪类是从前面开始匹配。
除此之外,无论是在兼容性还是语法方面,两者都没有区别。因此,本节会以:nth-child()为代表对这两个伪类进行详细且深入的介绍。
1. 从:nth-child()开始说起
在介绍语法之前,有必要提一句,:nth-child()伪类虽然功能很强大,但只适用于内容动态、无法确定的匹配场景。如果数据是纯静态的,哪怕是列表,都要使用类名或者属性选择器进行匹配。没有必要使用 :nth-child(),因为这样会增加选择器的优先级,且由于DOM结构严格匹配,无法随意调整,不利于维护。
:nth-child()伪类可以匹配指定索引序号的元素,支持一个参数,且必须有参数,参数可以是关键字值或者函数符号这两种类型。
(1)关键字值的形式如下。
●
odd
:匹配第奇数个元素,如第1个元素、第3个元素、第5个元素……●
even
:匹配第偶数个元素,如第2个元素、第4个元素、第6个元素……可以这样记忆:如果字母个数是奇数(odd有3个字母),就匹配奇数个数的元素;如果字母个数是偶数(even有4个字母),就匹配偶数个数的元素。
奇偶匹配关键字多用在列表或者表格中,可以用来实现提升阅读体验的斑马线效果。
(2)函数符号的形式如下。
● An+B:其中A和B都是固定的数值,且必须是整数;n可以理解为从0开始的自然数序列(0, 1, 2, 3, …),n前面可以有负号。第一个子元素的匹配序号是1,小于1的计算序号会被忽略。
下面来看一些示例,快速了解一下各种类型的参数的含义。
●
tr:nth-child(odd)
:匹配表格的第1, 3, 5行,等同于tr:nth-child(2n+1)。●
tr:nth-child(even)
:匹配表格的第2, 4, 6行,等同于tr:nth-child(2n)。●
:nth-child(3)
:匹配第3个元素。●
:nth-child(5n)
:匹配第5, 10, 15, …个元素。其中5=5×1,10=5×2,15=5×3……●
:nth-child(3n+4)
:匹配**第4, 7, 10, …个元素**。其中4=(3´0)+4,7=(3´1)+4,10=(3´2)+4……●
:nth-child(-n+3)
:匹配**前3个元素**,因为−0+3=3,−1+3=2,−2+3=1。●
li:nth-child(n)
:匹配所有的 <li>
元素,就匹配的元素而言和li标签选择器一模一样,区别是优先级更高了。实际开发中总是避免过高的优先级,因此没有理由这样使用。●
li:nth-child(1)
:匹配第一个 <li>
元素,和li:first-child匹配的作用一样,区别是后者的兼容性更好,因此,**也没有这样使用的理由**,可以使用li:first-child代替。●
li:nth-child(n+4):nth-child(-n+10)
:匹配第4~10个 <li>
元素,这个就属于比较高级的用法了。例如,考试成绩前3名的有徽章,第4名~第10名的高亮显示,此时,这种**正负值组合**的伪类非常好用。2. 动态列表项数量匹配技术
聊天软件中的群头像或者一些书籍的分组往往采用复合头像作为一个大的头像,可以看到如果头像数量不同,布局就会不同。(如微信群组)
借助子索引伪类自动判断列表项的个数,从而实现我们想要的布局。在这个方法中,不需要在父元素上设置当前列表项的个数,因此,HTML看起来平淡无奇:
<ul class="box">
<li></li>
<li></li>
<li></li>
...
</ul>
关键在于CSS,我们可以借助伪类判断当前列表项的个数,示意代码如下:
/* 1个 */
li:only-child {}
/* 2个 */
li:first-child:nth-last-child(2) {}
/* 3个 */
li:first-child:nth-last-child(3) {}
...
> 其中,:first-child:nth-last-child(2) 表示当前
<li>
元素既匹配第一个子元素,又匹配从后往前的第二个子元素,因此,我们就能判断当前总共有两个 <li>
子元素,从而精准实现我们想要的布局了,只需要配合使用相邻兄弟选择符加号(+)以及兄弟选择符(~)。例如:
/* li列表项的数量大于或等于5时所有元素宽度为33.333% */
li:first-child:nth-last-child(n+5),
li:first-child:nth-last-child(n+5) ~ li {
width: calc(100% / 3);
}
以上是不是一个非常巧妙的实现呢?
总之,基于上面的数量匹配原理就能自动实现不同列表项数量下的不同布局效果,而无须设置专门表示列表项数量的类名或者属性。
读者可以手动输入 https://demo.cssworld.cn/selector2/8/3-3.php 体验与学习。
https://memo.cosine.ren/m/351
#书摘 #css #前端
《CSS 选择器世界》比较实用的子索引伪类
本节要介绍的伪类都是用来匹配子元素的,子元素必须是独立标签的元素,文本节点、注释节点是无法匹配的。
如果想要匹配文字,只有::first-line和::first-letter两个伪元素可以实现,且只有部分CSS属性可以应用,这里不展开介绍。
1. :first-child 伪类和 :last-child 伪类
:first-child 伪类可以匹配第一个子元素,:last-child 伪类可以匹配最后一个子元素。
2. 给力的 :only-child 伪类
:only-child 也是一个很给力的伪类,尤其在处理动态数据的时候,可以省去很多JavaScript逻辑代码。
我们先来看一下这个伪类的基本含义,:only-child,顾名思义,就是匹配没有任何兄弟元素的元素。
例如,:only-child伪类可以匹配下面的
另外,:only-child 伪类在匹配元素的时候会忽略其前后的文字内容。例如:
虽然.icon元素后面有“删除”文字,但由于没有标签嵌套,是匿名文本,因此不影响:only-child伪类匹配.icon元素。
尤其需要指出的是,使用:only-child的场景是动态场景,也就是对于某个固定的小模块,根据场景的不同,里面可能是一个子元素,也可能是多个子元素,元素个数不同,布局方式就会不同,此时就是:only-child伪类大放异彩的时候。例如,某个正在加载(loading)的模块里面可能只有一张加载图片,也可能仅有一段加载文字,也可能是加载图片和加载文字兼有,此时:only-child伪类非常好用。
https://memo.cosine.ren/m/350
《CSS 选择器世界》比较实用的子索引伪类
本节要介绍的伪类都是用来匹配子元素的,子元素必须是独立标签的元素,文本节点、注释节点是无法匹配的。
如果想要匹配文字,只有::first-line和::first-letter两个伪元素可以实现,且只有部分CSS属性可以应用,这里不展开介绍。
1. :first-child 伪类和 :last-child 伪类
:first-child 伪类可以匹配第一个子元素,:last-child 伪类可以匹配最后一个子元素。
2. 给力的 :only-child 伪类
:only-child 也是一个很给力的伪类,尤其在处理动态数据的时候,可以省去很多JavaScript逻辑代码。
我们先来看一下这个伪类的基本含义,:only-child,顾名思义,就是匹配没有任何兄弟元素的元素。
例如,:only-child伪类可以匹配下面的
<p>
元素,因为其前后没有其他兄弟元素:
<div class="cs-confirm">
<!-- 可以匹配:only-child伪类 -->
<p class="cs-confirm-p">确定删除该内容?</p>
</div>
另外,:only-child 伪类在匹配元素的时候会忽略其前后的文字内容。例如:
<button class="cs-button">
<!-- 可以匹配:only-child伪类 -->
<i class="icon icon-delete"></i>删除
</button>
虽然.icon元素后面有“删除”文字,但由于没有标签嵌套,是匿名文本,因此不影响:only-child伪类匹配.icon元素。
尤其需要指出的是,使用:only-child的场景是动态场景,也就是对于某个固定的小模块,根据场景的不同,里面可能是一个子元素,也可能是多个子元素,元素个数不同,布局方式就会不同,此时就是:only-child伪类大放异彩的时候。例如,某个正在加载(loading)的模块里面可能只有一张加载图片,也可能仅有一段加载文字,也可能是加载图片和加载文字兼有,此时:only-child伪类非常好用。
https://memo.cosine.ren/m/350
#书摘 #css #前端
《CSS 选择器世界》empty伪类应用场景
:empty伪类与::before/::after伪元素
::before 和::after 伪元素可以给标签插入内容、图形,但这样会不会影响:empty伪类的匹配呢?答案是:不会。这一特性非常实用。
无论是大项目还是小项目,都会用到:empty伪类。主要有下面几种场景。
1. 隐藏空元素
例如,某个模块里面的内容是动态的,其可能是列表,也可能是按钮,这些模块容器常包含影响布局效果的CSS属性,如margin、padding属性等。当然,这些模块里面有内容的时候,布局显示效果是非常好的。然而,一旦这些模块里面的内容为空,页面上就会有很大一块明显的空白,布局效果就不好,这种情况下使用:empty伪类予以控制就再好不过了:
无须额外的JavaScript逻辑判断,直接使用CSS就可以实现动态样式效果。唯一需要注意的是,当列表内容缺失的时候,一定要把空格也去掉,否则 :empty 伪类不会匹配。
2. 字段缺失智能提示
例如,下面的HTML代码:
用户某些字段的信息是缺失的,此时开发人员应该使用其他占位符示意这里没有内容,例如用短横线(-)或者直接使用文字提示。但多年的开发经验表明,开发人员非常容易忘记这里需要的特殊处理,最终导致布局混乱,信息难辨。
但如今,我们不用再担心这样的问题了,直接使用CSS就可以处理这种情况,代码很简单:
这样的布局效果良好,信息明确。存储的是什么数据内容,直接输出的就是什么内容,就算数据库中存储的是空字符也无须担心。
实际开发中,类似的场景还有很多。例如,表格中的备注信息通常都是空的,此时可以这样处理:
除此之外,还有一类典型场景需要用到:empty伪类,那就是Ajax动态加载数据为空的情况。当一个新用户开始使用一个产品的时候,很多模块内容是没有的。要是在过去,我们需要在JavaScript代码中做if判断,如果没有值,我们要输出“没有结果”或者“没有数据”的信息。但是现在有了:empty伪类,直接把这个工作交给CSS就可以了。例如:
总之,这种方法非常好用,可以节约大量的开发时间,同时用户体验更好,维护更方便,因为可以使用一个通用类名使整站提示信息保持统一:
ps: 个人感觉有用,但不多,但有用
https://memo.cosine.ren/m/349
《CSS 选择器世界》empty伪类应用场景
:empty伪类与::before/::after伪元素
::before 和::after 伪元素可以给标签插入内容、图形,但这样会不会影响:empty伪类的匹配呢?答案是:不会。这一特性非常实用。
无论是大项目还是小项目,都会用到:empty伪类。主要有下面几种场景。
1. 隐藏空元素
例如,某个模块里面的内容是动态的,其可能是列表,也可能是按钮,这些模块容器常包含影响布局效果的CSS属性,如margin、padding属性等。当然,这些模块里面有内容的时候,布局显示效果是非常好的。然而,一旦这些模块里面的内容为空,页面上就会有很大一块明显的空白,布局效果就不好,这种情况下使用:empty伪类予以控制就再好不过了:
.cs-module:empty {
display: none;
}
无须额外的JavaScript逻辑判断,直接使用CSS就可以实现动态样式效果。唯一需要注意的是,当列表内容缺失的时候,一定要把空格也去掉,否则 :empty 伪类不会匹配。
2. 字段缺失智能提示
例如,下面的HTML代码:
<dl>
<dt>姓名:</dt>
<dd>张三</dd>
<dt>性别:</dt>
<dd></dd>
<dt>手机:</dt>
<dd></dd>
<dt>邮箱:</dt>
<dd></dd>
</dl>
用户某些字段的信息是缺失的,此时开发人员应该使用其他占位符示意这里没有内容,例如用短横线(-)或者直接使用文字提示。但多年的开发经验表明,开发人员非常容易忘记这里需要的特殊处理,最终导致布局混乱,信息难辨。
但如今,我们不用再担心这样的问题了,直接使用CSS就可以处理这种情况,代码很简单:
dd:empty::before {
content: '暂无';
color: gray;
}
这样的布局效果良好,信息明确。存储的是什么数据内容,直接输出的就是什么内容,就算数据库中存储的是空字符也无须担心。
实际开发中,类似的场景还有很多。例如,表格中的备注信息通常都是空的,此时可以这样处理:
td:empty::before {
content: '-';
color: gray;
}
除此之外,还有一类典型场景需要用到:empty伪类,那就是Ajax动态加载数据为空的情况。当一个新用户开始使用一个产品的时候,很多模块内容是没有的。要是在过去,我们需要在JavaScript代码中做if判断,如果没有值,我们要输出“没有结果”或者“没有数据”的信息。但是现在有了:empty伪类,直接把这个工作交给CSS就可以了。例如:
.cs-search-module:empty::before {
content: '没有搜索结果';
display: block;
line-height: 300px;
text-align: center;
color: gray;
}
总之,这种方法非常好用,可以节约大量的开发时间,同时用户体验更好,维护更方便,因为可以使用一个通用类名使整站提示信息保持统一:
.cs-empty:empty::before {
content: '暂无数据';
display: block;
line-height: 300px;
text-align: center;
color: gray;
}
ps: 个人感觉有用,但不多,但有用
https://memo.cosine.ren/m/349
#书摘 #css #前端
《CSS 选择器世界》empty伪类
先来了解一下 :empty 伪类的基本匹配特性。
1. :empty 伪类用来匹配空标签元素。例如:
此时,:empty伪类会匹配
2. :empty伪类还可以匹配前后闭合的替换元素,如
在所有浏览器下都呈现为双实线
3. :empty伪类还可以匹配非闭合元素,如
4. :empty伪类可以匹配什么样的元素?如果没有深入研究,你大概会认为:empty伪类可以匹配没有任何子元素、不显示任何内容的元素。但如果深入细节,就会发现这其中存在误解。
- :empty伪类与空格
如果元素内有注释,:empty伪类是否可以匹配?多数人会觉得不匹配,这是完全正确的。例如:
但如果元素内有一个空格或者标签内有换行符呢?实际上,:empty伪类依然无法匹配。例如,有以下两种情况。
- 不能有空格:
- 不能有换行符:
因此,实际开发的时候,如果遇到:empty伪类匹配无效的场景,要仔细查看HTML代码,看看标签内是否有空格或者换行符。尤其是使用一些渲染模板的时候,明明没有任何列表内容,但:empty伪类就是无法匹配,这可能是换行符或者空格导致的。不过根据具体实践,一些流行的开发框架(如Vue等)会自动去除空格,这有利于在实际项目中灵活使用:empty伪类。
:empty伪类忽略空格的特性不符合我们的直观认知,W3C官方也收集到了很多这样的意见,所以**在CSS选择器Level 4规范中已经开始明确:empty伪类可以匹配只有空格文本节点的元素**,但是直到撰写本章的时候还没有任何浏览器支持。因此,为安全起见,实际开发中大家还是按照无空格标准来进行。
https://memo.cosine.ren/m/348
《CSS 选择器世界》empty伪类
先来了解一下 :empty 伪类的基本匹配特性。
1. :empty 伪类用来匹配空标签元素。例如:
<div class="cs-empty"></div>
.cs-empty:empty {
width: 120px;
padding: 20px;
border: 10px dashed;
}
此时,:empty伪类会匹配
<div>
元素,呈现为虚线框。2. :empty伪类还可以匹配前后闭合的替换元素,如
<button>
元素和 <textarea>
元素。例如:
<textarea></textarea>
textarea:empty {
border: 6px double deepskyblue;
}
在所有浏览器下都呈现为双实线
3. :empty伪类还可以匹配非闭合元素,如
<input>
元素、`<img>` 元素和 <hr>
元素等。但实际开发中很少有需要使用:empty伪类匹配非闭合元素的场景。4. :empty伪类可以匹配什么样的元素?如果没有深入研究,你大概会认为:empty伪类可以匹配没有任何子元素、不显示任何内容的元素。但如果深入细节,就会发现这其中存在误解。
- :empty伪类与空格
如果元素内有注释,:empty伪类是否可以匹配?多数人会觉得不匹配,这是完全正确的。例如:
<!-- 无法匹配:empty伪类 -->
<div class="cs-empty"><!-- 注释 --></div>
但如果元素内有一个空格或者标签内有换行符呢?实际上,:empty伪类依然无法匹配。例如,有以下两种情况。
- 不能有空格:
<!-- 无法匹配:empty伪类 -->
<div class="cs-empty"> </div>
- 不能有换行符:
<!-- 无法匹配:empty伪类 -->
<div class="cs-empty">
</div>
因此,实际开发的时候,如果遇到:empty伪类匹配无效的场景,要仔细查看HTML代码,看看标签内是否有空格或者换行符。尤其是使用一些渲染模板的时候,明明没有任何列表内容,但:empty伪类就是无法匹配,这可能是换行符或者空格导致的。不过根据具体实践,一些流行的开发框架(如Vue等)会自动去除空格,这有利于在实际项目中灵活使用:empty伪类。
:empty伪类忽略空格的特性不符合我们的直观认知,W3C官方也收集到了很多这样的意见,所以**在CSS选择器Level 4规范中已经开始明确:empty伪类可以匹配只有空格文本节点的元素**,但是直到撰写本章的时候还没有任何浏览器支持。因此,为安全起见,实际开发中大家还是按照无空格标准来进行。
https://memo.cosine.ren/m/348
#书摘 #css #前端
《CSS 选择器世界》 :root伪类
:root伪类用来匹配文档的根元素,下面进行详细分析。
由于没有特别需要使用:root伪类的理由,反正匹配的是
实际上,下面两个开发场景中更推荐使用:root伪类。
1. 利用:root伪类的高优先级
假设引入了某些UI组件库,如果这些组件对html标签进行了一些设置,而这些设置是开发人员不需要的,我们就可以使用:root伪类进行重置,因为:root伪类的优先级更高,不用担心不能重置。例如设置了如下的CSS:
我们就可以用如下代码重置,以确保页面内容在加载过程中不会出现晃动。
另外,借助 :root 伪类提高任意选择器的优先级也是一种常见的技巧,例如类名 .recover 不能重置某些样式,可以在其前面加上 :root,变成 :root .recover,说不定就可以重置了,毕竟任何页面都一定有根元素(除了根元素 svg 等特殊场景),这种写法要比 .recover.recover 的性能提高不少。
2. CSS变量
现代浏览器都已经支持CSS自定义属性(也就是CSS变量),其中有一些变量是全局的,如整站的颜色、主体布局的尺寸等。对于这些变量,业界约定俗成,都将它们写在:root伪类中。
大家千万不要以为将CSS变量写在:root伪类中有什么特别的作用,这只是一种写法而已,其效果和写在html标签选择器中是一样的,因为全局CSS变量一定都是用以继承的,只要是级别足够高的祖先选择器都可以。
之所以CSS变量都写在:root伪类中,可能是因为这样可以使代码的可读性更好。同样是根元素,html标签选择器负责样式,:root伪类负责变量,互相分离,各司其职。
https://memo.cosine.ren/m/347
《CSS 选择器世界》 :root伪类
:root伪类用来匹配文档的根元素,下面进行详细分析。
由于没有特别需要使用:root伪类的理由,反正匹配的是
<html>
元素,因此为何不直接使用html标签选择器呢?这样兼容性更好,优先级更低,是这样吗?实际上,下面两个开发场景中更推荐使用:root伪类。
1. 利用:root伪类的高优先级
假设引入了某些UI组件库,如果这些组件对html标签进行了一些设置,而这些设置是开发人员不需要的,我们就可以使用:root伪类进行重置,因为:root伪类的优先级更高,不用担心不能重置。例如设置了如下的CSS:
html {
overflow-y: scroll;
}
我们就可以用如下代码重置,以确保页面内容在加载过程中不会出现晃动。
:root {
overflow-y: auto;
scrollbar-gutter: stable;
}
另外,借助 :root 伪类提高任意选择器的优先级也是一种常见的技巧,例如类名 .recover 不能重置某些样式,可以在其前面加上 :root,变成 :root .recover,说不定就可以重置了,毕竟任何页面都一定有根元素(除了根元素 svg 等特殊场景),这种写法要比 .recover.recover 的性能提高不少。
2. CSS变量
现代浏览器都已经支持CSS自定义属性(也就是CSS变量),其中有一些变量是全局的,如整站的颜色、主体布局的尺寸等。对于这些变量,业界约定俗成,都将它们写在:root伪类中。
大家千万不要以为将CSS变量写在:root伪类中有什么特别的作用,这只是一种写法而已,其效果和写在html标签选择器中是一样的,因为全局CSS变量一定都是用以继承的,只要是级别足够高的祖先选择器都可以。
之所以CSS变量都写在:root伪类中,可能是因为这样可以使代码的可读性更好。同样是根元素,html标签选择器负责样式,:root伪类负责变量,互相分离,各司其职。
https://memo.cosine.ren/m/347
#书摘 #css #前端
《CSS 选择器世界》键盘焦点伪类 :focus-visible
:focus-visible 伪类虽然和 :focus-within 伪类看起来很相似,但两者的作用大相径庭,被浏览器开始支持的时间也有较大区别::focus-within伪类已被浏览器支持很多年了,而:focus-visible伪类则在2022年3月才被所有现代浏览器支持。
1. :focus-visible伪类的作用及背景变化
:focus-visible伪类匹配的场景是元素聚焦,同时浏览器认为聚焦轮廓应该显示。
是不是很拗口?规范就是这么定义的。:focus-visible的规范并没有强行约束匹配逻辑,而是交给了UA(也就是浏览器)
2. 在所有现代浏览器下,鼠标点击链接元素
3. 这就是:focus-visible伪类的作用,可以用来区分用户的操作是鼠标点击,还是键盘访问。不过,这种判断并不完全准确,因为:focus-visible伪类匹配与否是浏览器自行决定的,没有特定的规范。目前看来,浏览器会出现默认轮廓的场景都会匹配:focus-visible伪类。
在 Chrome90 版本之前的浏览器下,有些元素的焦点轮廓就算是在点击操作下也会出现的。包括下面这些场景:
● 设置了背景的
● HTML5 中的
● 设置了 HTML tabindex 属性的元素。
这其实是我们不希望看到的,因为点击鼠标是目标明确的主动操作,此时出现轮廓是没有必要的,反而让操作界面变得难看了。
但是,又不能简单地通过设置 outline:none 来处理,因为这样会使使用键盘访问时应当出现的焦点轮廓被隐藏,从而带来严重的无障碍访问问题。
在这种场景下,:focus-visible伪类可谓天降神兵,只需要一条短短的CSS规则就可以兼顾视觉表现和无障碍访问:
此时,无论对于
当然,由于现在的Chrome浏览器和Safari浏览器默认点击
:focus-visible 伪类目前的作用就变成了用来区分用户行为是鼠标行为还是键盘行为。
https://memo.cosine.ren/m/336
《CSS 选择器世界》键盘焦点伪类 :focus-visible
:focus-visible 伪类虽然和 :focus-within 伪类看起来很相似,但两者的作用大相径庭,被浏览器开始支持的时间也有较大区别::focus-within伪类已被浏览器支持很多年了,而:focus-visible伪类则在2022年3月才被所有现代浏览器支持。
1. :focus-visible伪类的作用及背景变化
:focus-visible伪类匹配的场景是元素聚焦,同时浏览器认为聚焦轮廓应该显示。
是不是很拗口?规范就是这么定义的。:focus-visible的规范并没有强行约束匹配逻辑,而是交给了UA(也就是浏览器)
2. 在所有现代浏览器下,鼠标点击链接元素
<a>
的时候是不会出现焦点轮廓的,但是使用键盘访问的时候会出现。点击链接元素时只会触发:focus伪类,而键盘访问此链接元素时不仅会触发:focus伪类,还会触发:focus-visible伪类。3. 这就是:focus-visible伪类的作用,可以用来区分用户的操作是鼠标点击,还是键盘访问。不过,这种判断并不完全准确,因为:focus-visible伪类匹配与否是浏览器自行决定的,没有特定的规范。目前看来,浏览器会出现默认轮廓的场景都会匹配:focus-visible伪类。
在 Chrome90 版本之前的浏览器下,有些元素的焦点轮廓就算是在点击操作下也会出现的。包括下面这些场景:
● 设置了背景的
<button>
按钮;● HTML5 中的
<summary>
元素;● 设置了 HTML tabindex 属性的元素。
这其实是我们不希望看到的,因为点击鼠标是目标明确的主动操作,此时出现轮廓是没有必要的,反而让操作界面变得难看了。
但是,又不能简单地通过设置 outline:none 来处理,因为这样会使使用键盘访问时应当出现的焦点轮廓被隐藏,从而带来严重的无障碍访问问题。
在这种场景下,:focus-visible伪类可谓天降神兵,只需要一条短短的CSS规则就可以兼顾视觉表现和无障碍访问:
:focus:not(:focus-visible) {
outline: 0;
}
此时,无论对于
<summary>
元素还是设置了 tabindex 属性的元素,在点击的时候都不会出现轮廓,同时,键盘访问时的 outline 轮廓依然保留,两全其美。当然,由于现在的Chrome浏览器和Safari浏览器默认点击
<button>
按钮或者 <summary>
元素时都不会出现轮廓,因此,:focus-visible伪类的作用就没有以前那么明显了。准确地说是浏览器自己优化了之前的一些无障碍访问策略,使得无须使用:focus-visible伪类手动进行相关的优化了。:focus-visible 伪类目前的作用就变成了用来区分用户行为是鼠标行为还是键盘行为。
https://memo.cosine.ren/m/336
#书摘 #css #前端
《CSS 选择器世界》7.4 非常实用的整体焦点伪类 :focus-within
整体焦点伪类 :focus-within 非常实用,且兼容性不错,目前已经可以在实际项目中使用,包括移动端项目和无须兼容IE浏览器的桌面端项目。
1. :focus-within 伪类和 :focus 伪类的区别
ChS :focus-within 伪类和 :focus 伪类有很多相似之处,那就是伪类样式的匹配离不开元素聚焦行为的触发。区别在于,:focus 伪类样式只有在当前元素处于聚焦状态的时候才匹配,而 :focus-within 伪类样式在当前元素或者当前元素的任意子元素处于聚焦状态的时候均匹配。
子元素聚焦可以使父元素的样式发生变化,这是CSS选择器世界中很了不起的革新,因为 :focus-within 伪类的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种父选择器行为需要借助用户的行为触发,属于 “后渲染”,不会与现有的渲染机制冲突,自然也不会带来性能问题,因此浏览器在规范出现后不久就快速支持了。
2. :focus-within 伪类实现无障碍访问的下拉列表
:focus-within伪类非常实用,一方面它可以用在表单控件元素上(无论是样式自定义还是交互布局),例如输入框聚焦时高亮显示前面的描述文字,我们可以不把描述文字放在输入框的后面(具体见5.4.2节中的示例),按正常的DOM顺序即可:
读者可以手动输入 https://demo.cssworld.cn/selector2/7/4-1.php 体验与学习。

另一方面,它可以用于实现完全无障碍访问的下拉列表,即使下拉列表中有其他链接或按钮也能正常访问。例如,要实现一个类似图7-10所示的下拉列表效果。
HTML结构如下:
:focus 伪类的区别
ChS :focus-within 伪类和 :focus 伪类有很多相似之处,那就是伪类样式的匹配离不开元素聚焦行为的触发。区别在于,:focus 伪类样式只有在当前元素处于聚焦状态的时候才匹配,而 :focus-within 伪类样式在当前元素或者当前元素的任意子元素处于聚焦状态的时候均匹配。
子元素聚焦可以使父元素的样式发生变化,这是CSS选择器世界中很了不起的革新,因为 :focus-within 伪类的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种父选择器行为需要借助用户的
我们在父元素 .cs-details 上使用 :focus-within 伪类来控制下拉列表的显示和隐藏,如下:
本例中共有5个
读者可以手动输入 https://demo.cssworld.cn/selector2/7/4-2.php 体验与学习。
https://memo.cosine.ren/m/334
《CSS 选择器世界》7.4 非常实用的整体焦点伪类 :focus-within
整体焦点伪类 :focus-within 非常实用,且兼容性不错,目前已经可以在实际项目中使用,包括移动端项目和无须兼容IE浏览器的桌面端项目。
1. :focus-within 伪类和 :focus 伪类的区别
ChS :focus-within 伪类和 :focus 伪类有很多相似之处,那就是伪类样式的匹配离不开元素聚焦行为的触发。区别在于,:focus 伪类样式只有在当前元素处于聚焦状态的时候才匹配,而 :focus-within 伪类样式在当前元素或者当前元素的任意子元素处于聚焦状态的时候均匹配。
子元素聚焦可以使父元素的样式发生变化,这是CSS选择器世界中很了不起的革新,因为 :focus-within 伪类的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种父选择器行为需要借助用户的行为触发,属于 “后渲染”,不会与现有的渲染机制冲突,自然也不会带来性能问题,因此浏览器在规范出现后不久就快速支持了。
2. :focus-within 伪类实现无障碍访问的下拉列表
:focus-within伪类非常实用,一方面它可以用在表单控件元素上(无论是样式自定义还是交互布局),例如输入框聚焦时高亮显示前面的描述文字,我们可以不把描述文字放在输入框的后面(具体见5.4.2节中的示例),按正常的DOM顺序即可:
<div class="cs-normal">
<label class="cs-label">用户名:</label>
<input class="cs-input">
</div>
.cs-normal:focus-within .cs-label {
color: darkblue;
text-shadow: 0 0 1px;
}
读者可以手动输入 https://demo.cssworld.cn/selector2/7/4-1.php 体验与学习。

另一方面,它可以用于实现完全无障碍访问的下拉列表,即使下拉列表中有其他链接或按钮也能正常访问。例如,要实现一个类似图7-10所示的下拉列表效果。
HTML结构如下:
:focus 伪类的区别
ChS :focus-within 伪类和 :focus 伪类有很多相似之处,那就是伪类样式的匹配离不开元素聚焦行为的触发。区别在于,:focus 伪类样式只有在当前元素处于聚焦状态的时候才匹配,而 :focus-within 伪类样式在当前元素或者当前元素的任意子元素处于聚焦状态的时候均匹配。
子元素聚焦可以使父元素的样式发生变化,这是CSS选择器世界中很了不起的革新,因为 :focus-within 伪类的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种父选择器行为需要借助用户的
我们在父元素 .cs-details 上使用 :focus-within 伪类来控制下拉列表的显示和隐藏,如下:
.cs-datalist {
display: none;
position: absolute;
border: 1px solid #ddd;
background-color: #fff;
}
/* 下拉列表展开 */
.cs-details:focus-within .cs-datalist {
display: block;
}
本例中共有5个
<a>
元素,其中一个用于触发下拉显示的 .cs-summary 元素,另外4个在下拉列表中。无论点击这5个 <a>
元素中的哪一个,都会触发父元素 .cs-details 设置的 :focus-within 伪类样式,因此可以让下拉列表一直保持显示状态;点击页面任意空白处,下拉列表自动隐藏,效果非常理想。读者可以手动输入 https://demo.cssworld.cn/selector2/7/4-2.php 体验与学习。
https://memo.cosine.ren/m/334