先来看一个DIV + CSS 布局的网页。
<body> <div class="nagivagor">...</div> <div class="sider">...</div> <div class="main">...</div> </body>
Web最原始的时候,页面是用table布局的,后面演变为DIV + CSS布局。对于一个大型网页,我们洋洋洒洒的定义了很多的class属性,以便区分不同的样式。使用class属性有两个缺点:
- class属性本身没有语义,它纯粹是用来为CSS样式服务的,属于多余属性。
- 使用class属性,并没有把样式和元素绑定起来;同一个class属性,文本框可以用,下拉框也可以用,甚至按钮也可以用,这样其实非常混乱。
所以在CSS 3中,提倡使用选择器来将样式与元素直接绑定起来。这样的话,在样式表中什么样式与什么元素向匹配变得一目了然,修改起来也方便。
1. 属性选择器
根据属性的值,来选择元素。
- [attribute=value]: attribute等于value。
- [attribute*=value]: attribute包含value。
- [attribute^=value]: attribute以value开头。
- [attribute$=value]: attribute以value结尾。
<body>
<style>
[title=special] {
background-color: yellow;
}
[title*=september] {
background-color: red;
}
[title^=as] {
background-color: blue;
}
[title$=asml] {
background-color: green;
}
</style>
<div title="special">Special</div>
<div title="2011-september-1">2011-september-1</div>
<div title="2011-september-2">2011-september-2</div>
<div title="2011-september-3">2011-september-3</div>
<div title="as-section1">AS Section 1</div>
<div title="as-section2">AS Section 2</div>
<div title="as-section3">AS Section 3</div>
<div title="description1-asml">AS Section 1</div>
<div title="description2-asml">AS Section 2</div>
<div title="description3-asml">AS Section 3</div>
</body>
|
Special
2011-september-1
2011-september-2
2011-september-3
AS Section 1
AS Section 2
AS Section 3
AS Section 1
AS Section 2
AS Section 3
|
2. 伪类选择器Pseudo-classes
使用pseudo-classes,可以根据元素状态的变化,动态地应用CSS样式。
2.1 用户交互性state
2.1.1 :hover
鼠标悬停元素上的state。
<style>
a:hover {
background: black;
color: white;
text-decoration: none;
}
</style>
<p>
This is a link: <a>Hover over me</a>
</p>
|
This is a link: Hover over me |
2.1.2 :active
元素激活的状态,例如点击Button时,鼠标释放前的状态。
<style>
#button-active:active {
transform: scale(1.2);
box-shadow: none;
}
</style>
<button id="button-active">鼠标按下别动</button>
|
2.1.3 :focus, :focus-within, :focus-visible
:focus元素获得焦点的state。
<body>
<style>
#button-focus:focus {
outline: 2px dashed blue;
outline-offset: 2px;
}
</style>
<button id="button-focus">点击让我获得焦点</button>
|
:focus-within,当内部的元素获得焦点时的state。
<style>
table#table-focuse-within tr:focus-within {
background-color: yellow;
}
</style>
<table id="table-focuse-within" border="1">
<tr><td>张三</td><td><button>广东</button></td></tr>
<tr><td>李四</td><td><button>广西</button></td></tr>
</table>
|
|
:focus-visible,表示使用键盘(e.g. TAB)让元素获得焦点。
比如这个场景,使用鼠标让元素获得焦点时,不显示边框。但当用键盘 TAB 键让元素获得焦点时,显示边框。因为键盘访问元素时,若没有边框,用户不知道当前是哪个元素获得focus。
注:个人网站模板让focus-visible失效了,copy下面代码到本地HTML可以查看效果;或者点击此链接查看codepen上的示例。
<style>
#test-focus-visible:focus {
outline: none;
}
#test-focus-visible:focus-visible {
outline: 2px solid red;
}
</style>
<p>
点击下面按钮,没有边框;<br/>
用TAB访问到下面的按钮,会显示边框.<br/>
</p>
<button id="test-focus-visible">我是一个按钮</button>
|
点击下面按钮,没有边框; |
2.1.4 :target
:target表示的是通过URL访问id匹配的元素(即锚点),这里我给”2.1.4 :target”加了一个id (id=”target-test”)。
<h2 id="target-test">2.1.4 :target</h2>
CSS属性为:
<style>
#target-test:target {
background: lightgoldenrodyellow;
}
</style>
点击高亮本章节,当跳转到页面某个地方,需要高亮时,这个就很有用。
2.1.5 :link, :visited
通常应用于<a>标签。
- a:link,表示链接没访问时的state。
- a:visited,表示链接访问后的state。
<style>
a.test-a-style:link {
color: blue;
}
a.test-a-style:visited {
color: red;
}
</style>
<a class="test-a-style" href="https://www.google.com" target="_blank">打开Google</a><br/>
<a class="test-a-style" href="javascript:void()">Not Visited URL</a>
|
2.2 输入控件的state
2.2.1 :enabled, :disabled
:enabled表示标签激活的状态,:disabled表示标签失效的状态,例如button:
<style>
button:disabled {
background: grey;
border-color: grey;
cursor: not-allowed;
}
button:enabled {
border: 5px solid gold;
}
</style>
<button>I am a enabled button</button><br>
<button disabled=true>I am a disabled button</button>
|
|
2.2.2 :checked, :indeterminate
- :checked,表示radio button或checkbox选中的状态。
- :indeterminate,表示checkbox部分选中的状态。
<style>
:checked {
box-shadow: 0px 0px 5px 2px green;
}
:indeterminate {
box-shadow: 0px 0px 5px 2px orange;
}
</style>
<input type="checkbox">没选中</input><br>
<input type="checkbox" checked>选中</input><br>
<input id="test-indeterminate" type="checkbox">部分选中</input>
<script>
document.getElementById("test-indeterminate").indeterminate = true;
</script>
|
没选中 |
2.2.3 :placeholder-shown
当输入框有placeholder属性,但又没有值时的state。
<style>
input#test-placeholder:placeholder-shown {
box-shadow: 0px 0px 5px 2px green;
}
</style>
<input id="test-placeholder" placeholder="请输入文本" />
|
2.2.4 :in-range, :out-of-range
但输入框时number类型,且有min,max属性时有效
- :in-range,表示输入值在范围内
- :out-of-range,表示不在范围内
<style>
input#test-range:in-range {
background: green;
color: white;
}
input#test-range:out-of-range {
background: white;
color: red;
}
</style>
<input id="test-range" type="number" min="1" max="9" />
|
2.2.5 :required, :optional
对于一个输入框,有required属性,会触发:required样式,否则触发:optional样式。
<style>
input#test-required:required {
background: green;
}
input#test-optional:optional {
background: yellow;
}
</style>
<p><input id="test-required" required /></p>
<p><input id="test-optional" /></p>
|
2.2.6 :valid, :invalid
- :valid 表示文本框验证正确的state
- :invalid表示文本框验证失败的state
<style>
input:invalid {
border-color: red;
}
input:valid {
border-color: green;
}
</style>
<input type="email" />
|
|
2.3 元素位置、顺序、个数选择
2.3.1 :first-child, :last-child
选择第一个子元素,或者最后一个子元素。
<style>
article#first-last-test p:first-child {
background: lightskyblue;
font-weight: bold;
}
article#first-last-test p:last-child {
background: lightyellow;
font-weight: bold;
}
</style>
<article id="first-last-test">
<p>我是第一章节</p>
<p>我是第二章节</p>
<p>我是第三章节</p>
<p>我是最后一章节</p>
</article>
|
我是第一章节 我是第二章节 我是第三章节 我是最后一章节 |
2.3.2 :only-child
只有一个child时,对此child应用CSS。
<style>
article#test-only-child li:only-child {
background: lightyellow;
}
</style>
<article id="test-only-child">
<p>One item in a list</p>
<ul>
<li>I am the only list item</li>
</ul>
<p>Multiple items in a list</p>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
</article>
|
One item in a list
Multiple items in a list
|
2.3.3 :first-of-type 和 :last-of-type
- div:first-of-type,表示第一个<div>,此<div>有可能不是第一个child
- p:last-of-type,表示最后一个<p>,此<p>有可能不是最后一个child
<style>
.my-parent div:first-of-type {
color: red;
}
</style>
<div class="my-parent">
<p>A paragraph</p>
<div>A div</div>
<div>Another div</div>
</div>
|
A paragraph A div
Another div
|
如果将:first-of-type替换为:first-child,则没有任何元素会标红,因为<div>并不是第一个child,而是第二个child。
2.3.4 :nth-child 和 :nth-of-type
用于指定某个index上的元素,index是从1开始。
<style>
.test-nth-child li:nth-child(2) {
background: yellow;
}
</style>
<article class="test-nth-child">
<ul>
<li>I am one of many list items</li>
<li>I have a highlight because I am the second child</li>
<li>Nullam id dolor id nibh ultricies vehicula ut id elit.</li>
<li>Cras mattis consectetur purus sit amet fermentum.</li>
</ul>
</article>
|
|
2.3.5 :only-of-type
只有一个element时,选中该element。
<style>
.test-only-of-type strong:only-of-type {
background: yellow;
}
</style>
<article class="test-only-of-type">
<p>The only <strong>bold element</strong> in this paragraph gets a highlight style.
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Nullam id dolor id
nibh ultricies vehicula ut id elit.</p>
</article>
|
The only bold element in this paragraph gets a highlight style. |
2.4 空element选择 :empty
空element是指element里面没有任何东西,包括child element,文本以及空白符(TAB,换行,回车)。下面的element就不是空元素,因为它里面有换行符。
<div> </div>
:empty选择器可以控制空元素,例如WYSIWYG文本编辑器中,想要隐藏空元素。
<style>
.test-empty :empty {
display: none;
}
</style>
<article class="test-empty">
<p>Donec ullamcorper nulla non metus auctor fringilla.</p>
<p></p>
<p>Curabitur blandit tempus porttitor.</p>
</article>
|
Donec ullamcorper nulla non metus auctor fringilla. Curabitur blandit tempus porttitor. |
2.5 函数选择器
2.5.1 :is() 选择多个
如果你想选择 .post 里的所有 h2, li 和 img 子元素,你可以这么写:
.post h2,
.post li,
.post img {
…
}
使用 :is() 函数,可以写的更精简:
.post :is(h2, li, img) {
…
}
以逗号分隔的写法如果某个写错了,整个就都不work了;:is() 函数中某个有错误,其它的正常选择。
2.5.2 :not() 取反
a:not([class]) {
color: blue;
}
|
选择超链接,没有class属性 |
img:not([alt]) {
outline: 10px red;
}
|
选择图片,没有alt属性 |
<style>
.test-not p:not(.main) {
display: none;
}
</style>
<article class="test-not">
<p class="main">Donec ullamcorper nulla non metus auctor fringilla.</p>
<p></p>
<p>Curabitur blandit tempus porttitor.</p>
</article>
|
隐藏没有 .main 的 <p>
Donec ullamcorper nulla non metus auctor fringilla. Curabitur blandit tempus porttitor. |
3. 伪元素选择器
伪元素是一个附加至选择器末的关键词,允许你对被选择元素的特定部分修改样式。
3.1 ::before, ::after
- ::before 用于在选择元素后动态添加一个子元素
- ::after 用于在选择元素前动态添加一个子元素
<style>
#test-before-after::before {
content: "<strong>before content</strong>";
color: red;
}
#test-before-after::after {
content: "after content";
background-color: yellow;
}
</style>
<p id="test-before-after">I am a paragraph. </p>
|
I am a paragraph. |
::before和::after必须设置content属性,否则不起作用。content里的字符串如果含有HTML标签,不会被解析。如果没有内容,只是想当个block使用,例如显示图片,可以把content设置为空字符串,例如下面的代码:
.callout::before {
content: "";
background-image: url('XXX');
background-size: cover;
width: 1.25rem;
height: 1.25rem;
display: block;
position: absolute;
left: 1rem;
}
3.2 ::first-letter
如果是英文,设置第一个字母;如果是中文,设置第一个字。
<style>
p#test-first-letter::first-letter {
color: goldenrod;
font-weight: bold;
}
</style>
<p id="test-first-letter">
你好。The first letter of this paragraph is
<code>goldenrod</code>, which is a
<em>great</em> color.
</p>
|
你好。The first letter of this paragraph is |
3.3 ::first-line
设置一段文字的第一行样式。
<style>
p#test-first-line::first-line {
color: goldenrod;
font-weight: bold;
}
</style>
<p id="test-first-line">
The first line of this paragraph is <code>goldenrod</code>,
which is a <em>great</em> color. Here is some lipsum to fill
it out Praesent commodo cursus magna, vel scelerisque nisl
consectetur et. Sed posuere consectetur est at lobortis.
</p>
|
The first line of this paragraph is |
3.4 ::backdrop
::backdrop CSS 伪元素 是在任何处于全屏模式的元素下的即刻渲染的盒子(并且在所有其他在堆中的层级更低的元素之上)。
设置弹出的对话框幕布。
/* Backdrop 只有通过 dialog.showModal() 打开对话框时会被显示 */
dialog::backdrop {
background: rgba(255,0,0,.25);
}
另一个示例是将视频全屏显示时的背景颜色改为蓝灰色而不是大多数浏览器默认的黑色。
video::backdrop {
background-color: #448;
}
显示效果:
3.5 ::marker
设置list元素前面的图标或数字样式。只有少部分样式可以设置给::marker:
- color
- content
- white-space
- font
- animation和transition
可以通过content设置marker图标,例如变成加号。
<style>
ul#test-marker ::marker {
color: hotpink;
content: '\002B'' '; /* Plus symbol with space */
}
ul#test-marker ::marker {
font-size: 1.5em;
}
</style>
<main>
<ul id="test-marker">
<li>Unfortunately, there is no fear that the seller is not a bear.</li>
<li>he lion's laughter, the gate and the main ac, at the entrance to the United States.</li>
<li>Curabitur blandit tempus porttitor.</li>
</ul>
</main>
|
|
3.6 ::selection
设置选中文本的样式。
<style>
p#test-selection::selection {
background: green;
color: white;
}
</style>
<main>
<p id="test-selection">
Select the text in this paragraph to see the effect.
Vestibulum id ligula porta felis euismod semper.
</p>
</main>
|
Select the text in this paragraph to see the effect. |
3.7 ::placeholder
有些元素有些提示性的元素,例如<input>的placeholder属性,通过::placeholder可以设置提示文字的样式。
<style>
#test-placeholder input::placeholder {
color: red;
background-color: yellow;
}
</style>
<main id="test-placeholder">
<label for="email">Email address</label>
<input type="email" placeholder="E.G name@example.com" id="email" />
</main>
|
|
3.8 ::cue
用于设置HTML5 video里字幕的样式。
video::cue {
font-size: 1rem;
color: red;
}
|
点击打开视频页面 |
4. CSS 选择器参考大全
本文并未包含所有的选择器,下面是w3schools上的一个链接,用一个表格罗列了所有的选择器。
CSS Selector Reference: https://www.w3schools.com/cssref/css_selectors.asp
5. 参考
- Learn CSS: https://web.dev/learn/css/ (大部分翻译而来)
- Mozilla CSS中文教程: https://developer.mozilla.org/zh-CN/docs/Web/CSS