Web 前端学习笔记(二):CSS 基础
上一篇整理了 HTML 的结构,这一篇进入 CSS ——负责”长什么样”的部分。同样,每节都附了可以直接打开的 demo。
一、三种导入方式
CSS 有三种写进页面的方式:
1. 外部样式 —— 单独写成 .css 文件,用 <link> 引入。实际项目里基本都用这种,因为可以被多个页面复用,也能被浏览器缓存。
1 | <link rel="stylesheet" href="css/style.css"> |
1 | /* css/style.css */ |
2. 内部样式 —— 写在 <head> 里的 <style> 标签中,只对当前页面生效。
1 | <style> |
3. 内联样式 —— 直接写在标签的 style 属性上,只作用于这一个元素。
1 | <h1 style="color: red;">这是一个应用了内联样式的一级标题</h1> |
优先级到底怎么算
常见说法是”内联 > 内部 > 外部”,这个说法不准确。真实规则是两条:先比选择器权重,权重相同才比先后顺序。
权重从高到低:
| 写法 | 权重 |
|---|---|
内联 style="" |
1000 |
id 选择器 #header |
100 |
类/伪类/属性选择器 .highlight |
10 |
元素选择器 h2 |
1 |
通用选择器 * |
0 |
关键在于:内部样式和外部样式本身没有高低之分,谁在后面谁生效(这也是为什么 <link> 通常写在 <style> 前面)。动手验证一下——把 demo 里 <link> 挪到 </style> 后面,h3 的颜色就会从外部样式的黄色生效,而不是被内部样式覆盖。
内联样式因为权重是 1000,除非用 !important,否则永远赢。这也是不建议用内联样式的原因:它会让你后面想覆盖样式时非常痛苦。
二、CSS 选择器
选择器决定”这条样式规则作用在谁身上”。常用的一共九类:
1 | /* 元素选择器:所有 h2 */ |
子代选择器和后代选择器差一个字,差别很大
.father > .son里的>表示直接子元素,孙子辈不匹配;.father p中间是空格,表示所有后代,不管嵌套多深都匹配。
demo 里的结构是这样的:
1 | <div class="father"> |
.son 同时被两条规则命中,为什么显示的是 yellowgreen 而不是 pink?因为 .father > .son 是两个类(权重 20),而 .father p 是一个类加一个元素(权重 11),前者胜出。.grandson 只被第二条命中,所以是粉色。
其他常用伪类与伪元素
1 | /* 选中第一个子元素 */ |
伪类和伪元素的区别看冒号个数::hover 是伪类(选中元素的某种状态),::after 是伪元素(凭空生成一块内容)。上面这个 ::after 就是经典的清除浮动写法,下一篇会详细讲。
三、常用属性与 display
font 复合属性
1 | /* 顺序:font-weight font-size font-family */ |
复合写法更简洁,但要注意 font-size 和 font-family 必须写,且 font-size 和 font-family 的顺序不能颠倒,否则整条声明会失效。不确定的时候分开写更稳妥:
1 | h1 { |
line-height 行高
1 | p { line-height: 40px; } |
行高决定每行文字占的高度,是控制段落疏密的主要手段。用无单位数字(比如 1.6)比用像素更好——它会按当前字号自动换算,字号变化时不用跟着改。
行内元素设置宽高无效
这是最容易困惑的一点:
1 | .block { |
1 | <div class="block">这是一个块级元素</div> |
<span> 的宽高完全不生效,它的尺寸由内容撑开。但有个例外:<img>、<input> 这类替换元素虽然也是行内元素,宽高却是生效的——因为它们的尺寸由外部资源决定。demo 里的两张 youda.gif 就设了 100×150 并且确实生效了。
display 转换元素类型
既然行内元素不能设宽高,那就把它转成能设的:
1 | /* 让 div 变成行内元素:会和其他行内元素排在同一行,但宽高失效 */ |
| display 值 | 是否独占一行 | 能否设宽高 |
|---|---|---|
block |
是 | 能 |
inline |
否 | 不能(替换元素除外) |
inline-block |
否 | 能 |
inline-block 是这三者里最实用的一个:做导航菜单、按钮、卡片排列时经常用到。下一篇的 Flex 布局则是更现代的替代方案。
四、盒子模型
每个元素都可以看成一个盒子,从里到外一共四层:
1 | ┌─────────── margin(外边距,盒子与其他盒子的距离)───────────┐ |
border 复合属性
1 | .demo { |
边框样式可选值:
| 值 | 效果 |
|---|---|
solid |
实线 |
dashed |
虚线 |
dotted |
点线 |
double |
双线 |
none |
无边框 |
四边的值按”上右下左”顺时针来
1 | .border-demo { |
这个顺时针规则适用于 margin、padding、border-width 等一系列属性,记住一次到处能用。顺便记一下简写规律:
| 写了几个值 | 含义 |
|---|---|
10px |
四边都是 10px |
10px 20px |
上下 10px,左右 20px |
10px 20px 30px |
上 10px,左右 20px,下 30px |
10px 20px 30px 40px |
上 10px,右 20px,下 30px,左 40px |
元素的真实宽度
标准盒模型下,元素占据的宽度不是 width,而是:
1 | 实际宽度 = width + padding-left + padding-right + border-left + border-right |
所以 demo 里那个 width: 300px 的盒子,加上左右边框各 30px、40px,实际宽得多。
补充一个练习里没写、但很实用的属性:box-sizing: border-box。加上它之后,width 就代表包含 padding 和 border 的总宽,算尺寸时省事很多。现代项目几乎都会在样式开头全局设置:
1 | * { |
margin 的一个经典现象
相邻的上下两个块级元素,如果都有 margin,它们之间不会相加,而是取较大值,这叫外边距合并(margin collapse)。所以给上面元素设 margin-bottom: 40px、下面元素设 margin-top: 30px,实际间距是 40px 而不是 70px。布局时算间距对不上,多半是这个原因。
小结
| 知识点 | 核心记忆点 |
|---|---|
| 导入方式 | 内联权重 1000 最高;内部和外部比的是顺序,不是类型 |
| 选择器 | > 是直接子元素,空格是所有后代;: 伪类,:: 伪元素 |
| display | 行内元素不能设宽高,替换元素(img/input)例外;inline-block 兼顾两者 |
| 盒子模型 | 四边值按”上右下左”;实际宽度要加上 padding 和 border;上下 margin 会合并 |
下一篇进入布局,把浮动、定位和 Flex 放到一起对比——它们解决的其实是同一类问题,只是不同年代的方案。
本系列其他文章
