第三章 定位元素

最后更新于:2022-04-01 01:18:13

## 3.1 理解盒模型 其实 HTML 页面中每个元素其实都是一个「盒子」,默认情况下这些盒子的边框不可见,背景也是透明的,所以我们不能直接的看到页面中盒子的结构,但是我们可以借助一些 Web Developer 工具条可以方便地显示盒子的边框和背景,让我们能很直观的看到这些盒子的结构。 每个盒子都有三组属性: * 外边距(margin): 可以设置盒子与相邻盒子之间的距离。 * 边框(border): 可以设置边框的宽度、样式和颜色。 * 内边距(padding):可以设置盒子内容区和边框之间的距离。 一个盒子有四条边,所以这些属性也各有四个属性,分别是上(top)、右(right)、下(bottom)和左(left),为了更直观的了解盒模型的结构,这里放上一张盒模型的结构图: ![盒模型](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a3550f8066d.png) 尽管这三组属性共有 12 个属性值,但我们也可以对它们进行简写,这里以 `margin` 为例: ~~~ margin-top:1px; margin-right:1px; margin-botton:1px; margin-left:1px; ~~~ 缩写后的代码如下: ~~~ margin:1px 1px 1px 1px; ~~~ 缩写的顺序是上 -> 右 -> 下 -> 左,顺时针的方向。相对的边的值相同,则可以省掉,代码如下: ~~~ margin:1px;// 四个方向的边距相同,等同于margin:1px 1px 1px 1px; margin:1px 2px;// 上下边距都为1px,左右边距均为2px,等同于margin:1px 2px 1px 2px margin:1px 2px 3px;// 右边距和左边距相同,等同于margin:1px 2px 3px 2px; margin:1px 2px 1px 3px;// 注意,这里虽然上下边距都为1px,但是这里不能缩写。 ~~~ ### 3.1.1 盒子的边框(border) 边框(border)有四个相关属性: * 宽度(border-width):可以使用 thin、 medium 和 thick 等文本值,也可以使用**除百分比和负值以外**的任何绝对值。 * 样式(border-style):有 none、 hidden、 dotted、 dashed、 solid、 double、 groove、 ridge、 inset 和 outset 等文本值。 * 颜色(border-color):可以使用任何颜色值,包括 rgb、 hsl、十六进制颜色值和颜色关键字。 * 圆角(border-radius):属于 CSS3 新增属性,可使用百分比、相对值和绝对值。 > CSS 推荐标准并没有明确规定 border-width 的几个文本值的确切宽度,所以实际宽度会因浏览器而异。 > border-radius 不影响盒子的定位。 ### 3.1.2 盒子的内边距(padding) 内边距是盒子内容区与盒子边框之间的距离。在没有设置内边距的情况下,内容紧挨着边框: ![内边距](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35510bf118.png) 设置内边距后,内容区与边框有一定的距离(padding 的大小): ![内边距](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35511046bd.png) ### 3.1.3 盒子外边距(margin) 与内边距和边框相比,外边距就要显得复杂的多了,首先是外边距叠加,**垂直方向上的外边距会叠加**,例如有三个段落应用了如下规则: ~~~ p { height:50px; border:1px solid #000; background: #fff; margin-top: 50px; margin-bottom: 30px; } ~~~ 由于第一段的下边距与第二段的上边距相邻,你可能会觉得它们两个盒子边框之间的外边距只和是 80px,但实际上是 50px,像这样上下外边距相遇时,它们会相互重叠,直到一个外边距碰到另一个盒子的边框。就上面例子而言,第二段较宽的上外边距会碰到第一段的边框,也就是说较宽的外边距决定两个盒子之间的距离。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35511383cb.png) ### 3.1.5 外边距的单位 在设置段落文本外边距时应该注意,为了避免因增大字号导致段落间外边距不变引起的整体不协调的问题,在设置段落的上下外边距是应该使用 `em` 单位,这样当字体大小调整时,段落的上下外边距也会根据字体的大小来调整距离,这样页面的整体布局就会比较协调一致,而左右外边距则可以用 `px` 绝对单位,确保左右外边距不会因字体大小的调整而发生改变,比如可以这么设置: ~~~ p { font-size: 1em; margin: .75em 30px; } ~~~ 这样段落垂直距离就会始终保持字体高度的四分之三的高度,水平外边距不会因字体的调整而发生改变了。 ## 3.2 盒子有多大 作者在本章介绍了块级元素和行内元素的不同行为。 ### 3.2.1 没有宽度的盒子 作者在这一节中专门提到了一个 「没有宽度」的概念:没有显式地设置元素的 `width` 属性。如果不设置块级元素的 `width` 属性,那么这个属性的默认值就是 `auto` ,结果就是会让元素的宽度扩展到与父元素同宽,对于块级元素和行内元素更具体的介绍请看笔者的上一篇文章[CSS 设计指南 学习笔记 一](http://www.cleardesign.me/stylin-with-css-note-1)。 盒模型结论一: > 没有设置宽度的元素始终会扩展到填满其父元素的宽度为止,添加水平外边距、水平边框和水平内边距都会导致内容宽度的减少,减少量等于水平外边距、水平边框和水平内边距的和。 ### 3.2.2 有宽度的盒子 盒模型结论二: > 为设定了宽度的盒子添加外边距、边框和内边距,会导致盒子扩展的更宽,实际上,盒子的 `width` 属性设定的只是盒子内容区的宽度,而不是盒子要占据的( margin-left + border-left + padding-left + width + padding-right + border-right + margin-right )水平宽度。 所以一定要记住的是,给设定了 `width` 的元素添加外边距、边框和内边距所展示的行为与默认的 `auto` 状态下的行为会有截然不同的表现。 拓展: 但是与布局相关的元素大部分都同时设置了 `margin`、 `border`、 `padding` 和 `width`,这就导致了在布局时的各种计算保证总宽度( margin-left + border-left + padding-left + width + padding-right + border-right + margin-right )保持不变,这样不仅麻烦,有的时候还比较容易出错,为了解决这一问题, CSS3 新增了一个 `box-sizing` 属性,通过它可以将设置了 `width` 的元素也设定成具有默认的 `auto` 状态下的行为。这样就省去了许多计算 `width` 的时间,同时也不会出错,而且它的浏览器支持情况也是一片大好( 除了 IE 6 和 IE 7 不支持,其他个别老版本的浏览器需要添加浏览器私有前缀才支持 )。 可以这样使用这个属性: ~~~ * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } ~~~ ![Browser Supported](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35511aff8f.png) ## 3.3 浮动与清除 浮动和清除是页面布局的一大利剑,分别是 `float` 和 `clear`,浮动可以让原来上下堆叠的块级元素变成左右并列,可以实现文字绕图片排列效果。浮动的元素会脱离常规的文档流,原来紧跟其后的元素会在空间允许的情况下向上提升到与浮动元素平起平坐。如果浮动元素后面有两个段落,而你只想让第一段与浮动元素并列(就算旁边还能放下第二段,也不想让它上来),就可以使用 `clear` 属性清除浮动。 ### 3.3.2 围住浮动元素的三种方法 浮动元素脱离了文档流,所以我们看不到包含它的父元素了,这种情况有时候并不是我们想要的,所以作者在本章介绍了如何围住浮动元素的三种方法。 方法一:为父元素添加 `overflow: hidden;` 强制它包围浮动元素。 这种方法在某些情况下也不适用,比如通过浮动设置的水平排列的菜单,对其父元素设置 `overflow: hidden;` 后,尽管父元素围住了它,但是如果菜单有下拉选项的话,当鼠标移动到上面的时候下拉菜单并不会显示,因为设置了 `overflow: hidden;`,所以超出父元素范围的内容都被隐藏掉了。 方法二:同时浮动父元素 父元素设置浮动后,不管其子元素是否是浮动,父元素都会紧紧地包围住它的子元素,因此需要用 `width: 100%;` 再让父元素的宽度与浏览器容器同宽。同样,尽管父元素围住了它,但是这样会导致页面中出现大量的浮动元素,而浮动元素有往往不好控制,并不利于页面的布局。 方法三:添加非浮动的清除元素 第三种强制父元素包含其浮动的子元素的方式就是给父元素的最后添加一个非浮动的子元素,然后清除该子元素,因此父元素一定会包含这个子元素以及前面的浮动元素: ~~~ // HTML <section> <p>It's fun to float</p> <div class="clearfix"></div> </section> // CSS p { float: left; } .clearfix { clear:both; } ~~~ 尽管这个方法能解决上面提到的两种方法中的问题,但它还不是最好的方法,因为它会在文档中添加无意义的标签,这违反了标签语义化的规则,对搜索引擎并不友好。所以如果你要清楚浮动但既不想浮动父元素又不想对父元素设置 `overflow: hidden;` 也不想增加无意义的标签的话,可以使用伪元素来清除浮动: ~~~ .clearfix::after { content: " "; display: table; clear: both; } ~~~ 然后在父元素中添加 `clearfix` 类,因为搜索引擎并不会抓取伪元素,所以这种方法并没有增加无意义的标签,这里应该注意的是,CSS3 标准是用两个冒号来区别伪元素和伪类,而 CSS2.1 中不管是伪元素还是伪类都是用单个冒号表示,然而 IE8 并不支持双冒号的伪元素,所以问题就来了,如果你要遵循 CSS3 的标准使用双冒号的话就不兼容 IE8 了,如果使用但冒号的话又不符合 CSS3 标准规范,当然现在大多数还是使用但冒号的,选择哪种还是看个人的选择。 ## 3.4 定位 CSS 布局的核心是 `position` 属性,对元素应用这个属性可以相对于它在常规文档流中的位置重新定位,`position` 属性有 4 个值: `static`、 `relative`、 `absolute` 和`fixed`。 ### 3.4.1 静态定位(static) 静态定位下的块级元素会在默认文档流中上下堆叠,想要突破 `static` 定位提供的这种按顺序布局元素的方式,就必须对元素的 `position` 属性的值改为其他三个值。 ### 3.4.1 相对定位(relative) 所谓的相对定位就是相对于元素原来的位置(static 状态下的位置)进行定位,也就是说在不设置 `top`、 `right`、 `bottom` 或 `left` 的话,和它在默认(static)情况下的表现是相同的,但是如果对它设置了 `top`、 `right`、 `bottom` 或 `left` 的话,就会相对与它默认的位置进行定位。相对定位的元素可以遮住静态(static)定位的元素。可以给 `top`和 `left` 属性设定负值,把元素向上和向左移动。 ### 3.4.2 绝对定位(absolute) 绝对定位跟静态定位和相对定位是绝对不一样的,静态定位和相对定位并不会脱离文档流,会占居原来的位置,而绝对定位会把元素彻底从文档流中拿出来,然后再相对于其他元素(这里的其他元素指的是定位上下文,默认是 `body` 元素)定位。 绝对定位的一个重要的概念就是**定位上下文**,把元素的 `position` 属性设定为 `relative`、 `absolute` 或 `fixed` 后,继而可以使用 `top`、 `right`、 `bottom` 和 `left` 属性,相对于「另一个元素」移动该元素的位置。这里的「另一个元素」就是该元素的定位上下文。 绝对定位的默认定位上下文是 `body`,这是因为 `body` 是标记中所有元素的唯一的祖先元素,而实际上,绝对定位元素的任何祖先元素都可以成为该绝对定位元素的定位上下文,只要把相应的祖先元素的 `position` 属性的值设定为 `relative` 即可。 ### 3.4.3 固定定位 从完全脱离文档流的角度说,固定定位与绝对定位类似。但不同之处在于,固定定位的定位上下文是视口(浏览器窗口),因此它不会随页面的滚动而移动。最常见的情况是用它来创建不随页面滚动而移动的导航元素。 ## 3.5 显示属性 `display` 属性的值很多,但常用的除了前面提到的控制块级元素、行内元素和行内块级元素的 `block`、 `inline` 和 `inline-block` 以外,还有一个比较常用的就是 `none`,把元素的 `display` 属性的值设定为 `none` 后,该元素及所包含在其中的元素,都不会在页面中显示。他们原先战局的所有空间都会被「回收」,就好像相关元素根本不存在一样。 与此类似的属性还有 `visibility`,这个属性常用的两个值是 `visible`(默认值) 和 `hidden`,把元素的 `visibility` 属性的值设定成 `hidden` ,元素会被隐藏,但它还会占据页面中原来的空间位置。 笔者觉得有点类似定位中 `absolute` 和 `relative` 的感觉,就是 `absolute` 定位的元素的原来的位置会被「回收」(脱离文档流),就好像元素根本不存在一样(指的是原来占据的位置不存在一样),`relative` 定位的元素还会占据页面中原来的空间位置。 ## 3.6 背景 背景支持为元素添加背景颜色也背景图片。 ### 3.6.1 CSS 背景属性 CSS 规定以下与背景相关属性: ~~~ background-color: ; // 背景颜色 background-image: url(); // 背景图片 background-repeat: ; // 背景重复 background-position: ; // 背景位置 background-size: ; // 背景尺寸 CSS3 新增属性 background-attachment: ; // 背景粘附 background-clip: ; // 背景 background-origin: ; // 背景 ~~~ ### 3.6.5 背景位置 ~~~ background-position:关键字 px em 百分比; ~~~ 用于控制背景位置的 `background-position` 属性,是所有背景属性中最复杂的。`background-position` 有 5 个关键字值: `top`、 `right`、 `bottom`、 `left` 或 `center`,这些关键字值任意两个组合起来都可以作为该属性的值。比如 `top` `right` 表示把图片放在元素的右上角位置,`center` `center` 表示把图片放在元素的中心位置。除了这些关键字值以外还可以用百分比、`px` 和 `em` 等单位。 拓展 要是只设置一个值,则将其用来设定水平位置,而垂直位置会被设为 `center`。 在使用**关键字**和**百分比**的情况下,情况有点特殊,设定的值会同时应用于元素和图片,也就是说,如果设定了 `80%` `20%`,则图片水平 `80%` 的位置与元素 `33%` 的位置对齐,垂直方向也一样,如下图: ![background-position](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35512296df.png) 其他单位数值就不一样了,如果用像素单位来设定位置: ~~~ background-position: 80px 20px; ~~~ 那么图片的左上角会被放在距元素左边 `80px` 上边 `20px` 的地方。 ### 3.6.6 背景尺寸 `background-size` 是 CSS3 新增的属性,但却的到了浏览器很好的支持,这个属性用来控制背景图片的尺寸,可以给它设定的值及含义如下: * `50%`:缩放图片,使其填充背景区的一半。 * `100px` `50px`:把图片调整到 `100px` 宽,`50px` 高。 * `cover`:拉大图片,使其完全填满背景区,并保持宽高比例。 * `contain`:缩放图片,使其恰好适应整个背景区域,并保持宽高比例。 ### 3.6.7 背景粘附 `background-attachment` 属性控制滚动元素内的背景图片是否随元素滚动而移动,这个属性默认是 `scroll`,即背景图片随元素移动,如果把它的值改为 `fixed`,那么背景图片不会随元素滚动而移动。 ### 3.6.8 简写背景属性 ~~~ background: [background-color] [background-image] [background-repeat] [background-attachment] [background-position] / [ background-size] [background-origin] [background-clip]; ~~~ 声明中少些了哪个属性(比如没写 `no-repeat`),就会使用相应属性的默认值(`repeat`)。 ### 3.6.9 其他 CSS3 背景属性 CSS3 新增的一些背景属性: * `background-clip`:控制背景绘制区域的范围,比如可以让背景颜色和背景图片只出现在内容区,而不出现在内边距区域,默认情况下背景绘制区域是扩展到边框外边界的。 * `background-origin`:控制背景定位区域的原点,可以设定为元素盒子左上角以外的位置。 * `background-break`:控制分离元素(比如跨越多行的行内元素盒子)的显示效果。 `background-size`、 `background-clip` 和 `background-origin` 的浏览器支持情况还是挺不错的: ![Browser Supported](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a3551267f7e.png) ### 3.6.10 多背景图片 CSS3 还可以给元素背景条件多个背景图片: ~~~ p { background-image: url(img/1.png), url(img/2.png), url(img/3.png); background-position:20% 20%, 30px 50px, center center; background-repeat: repeat, no-repeat, repeat; } ~~~ 在 CSS 中,我们把每张图片的声明都单独放在了一行,以逗号分隔,以便看清他们的位置、重复的设定值等等。要注意的是,代码中先列出的图片显示在上方,或者说更接近前景,还有就是对每张背景图设置重复或者位置的时候,也要用逗号一一对应隔开。 ### 3.6.11 背景渐变 渐变就是在一定长度内两种或多种颜色之间自然过度。渐变分两种,一种是线性渐变,一种是径向渐变。线性渐变是从元素的一端延伸到另一端,径向渐变则是从元素的一点向四周发散,下面来看一个简单的线性渐变例子: ~~~ // HTML <div class="gradient effect-1"></div> <div class="gradient effect-2"></div> <div class="gradient effect-3"></div> // CSS .gradient { width: 200px; height: 200px; margin: 0 20px; } /* 默认为从上到下 */ .effect-1 { background: -webkit-linear-gradient(#45b29a, #fff); background: -moz-linear-gradient(#45b29a, #fff); background: -o-linear-gradient(#45b29a, #fff); background: linear-gradient(#45b29a, #fff); } .effect-2 { background: -webkit-linear-gradient(left, #45b29a, #fff); background: -moz-linear-gradient(left, #45b29a, #fff); background: -o-linear-gradient(left, #45b29a, #fff); background: linear-gradient(to right, #45b29a, #fff); } .effect-3 { background: -webkit-linear-gradient(45deg, #45b29a, #fff); background: -moz-linear-gradient(45deg, #45b29a, #fff); background: -o-linear-gradient(45deg, #45b29a, #fff); background: linear-gradient(45deg, #45b29a, #fff); } ~~~ ![Gradient](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35512c54a9.png) 上面展示了三种简单的渐变效果,默认情况下渐变方向是从上到下的如图一,例 2 起点关键字 `left` 意思是渐变方向从左到右,例 3 中的 `45deg` (顺时钟旋转 45 度)相当于把起点从默认的中上设定到了又上。 #### 3.6.11.1 渐变点 渐变点就是渐变方向上的点,可以在这些点上设定颜色和不透明度。可以添加任意多个渐变点: ~~~ // HTML <div class="gradient effect-1"></div> <div class="gradient effect-2"></div> <div class="gradient effect-3"></div> <div class="gradient effect-4"></div> // CSS .gradient { width: 200px; height: 200px; margin: 0 20px; } /* 50% 处有一个渐变点 */ .effect-1 { background: -webkit-linear-gradient(#45b29a, #fff 50%, #45b29a); background: -moz-linear-gradient(#45b29a, #fff 50%, #45b29a); background: -o-linear-gradient(#45b29a, #fff 50%, #45b29a); background: linear-gradient(#45b29a, #fff 50%, #45b29a); } /* 20% 和 80%处有一个渐变点 */ .effect-2 { background: -webkit-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%); background: -moz-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%); background: -o-linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%); background: linear-gradient(#45b29a 20%, #fff 50%, #45b29a 80%); } /* 25%、50% 和 75% 处有一个渐变点 */ .effect-3 { background: -webkit-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a); background: -moz-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a); background: -o-linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a); background: linear-gradient(#45b29a, #fff 25%, #45b29a 50%, #fff 75%, #45b29a); } /* 为同一个渐变点设定两种颜色可以的到突变的效果 */ .effect-4 { background: -webkit-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a); background: -moz-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a); background: -o-linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a); background: linear-gradient(#45b29a, #fff 25%, #45b29a 25%%, #45b29a 75%, #fff 75%, #45b29a); } ~~~ ![Gradient](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a355131058a.png) 例 1,如果不是使用百分比或其他值声明渐变点的位置,三种颜色会均匀分布于整个渐变。 例 2,演示了起点和终点不是 0% 和 100% 时的情形。此时,在第一个渐变点(20%)之前,是第一个渐变点声明的实色,而在该点之后,则是从该颜色到下一个渐变点颜色的过度。同样,在最后一个渐变点(80%)之后,该渐变点的颜色会以实色扩展到元素结束。 例 3,简单展示了相同颜色在几个渐变点之间变来变去的效果。 例 4,展示了在同一个渐变点声明两种不同颜色,能实现一种突变的效果。 #### 3.6.11.2 径向渐变 在创建径向渐变的时候,可以使用参数指定形状、位置、尺寸、颜色和不透明度: ~~~ // HTML <div class="gradient effect-1"></div> <div class="gradient effect-2"></div> <div class="gradient effect-3"></div> // CSS .gradient { width: 300px; height: 200px; margin: 0 20px; } .effect-1 { background: -webkit-radial-gradient(#fff, #45b29a); background: -moz-radial-gradient(#fff, #45b29a); background: -o-radial-gradient(#fff, #45b29a); background: radial-gradient(#fff, #45b29a); } .effect-2 { background: -webkit-radial-gradient(circle, #fff, #45b29a); background: -moz-radial-gradient(circle, #fff, #45b29a); background: -o-radial-gradient(circle, #fff, #45b29a); background: radial-gradient(circle, #fff, #45b29a); } .effect-3 { background: -webkit-radial-gradient(50px 30px, circle, #fff, #45b29a); background: -moz-radial-gradient(50px 30px, circle, #fff, #45b29a); background: -o-radial-gradient(50px 30px, circle, #fff, #45b29a); background: radial-gradient(50px 30px, circle, #fff, #45b29a); } ~~~ ![Gradient](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35513732ed.png) 例 1,展示了默认的渐变形状,即渐变效果会填充元素,这里是矩形,如果元素是正方形,那渐变就是圆形: ![Gradient](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35513c0b0f.png) 例 2,设定了关键字 `circle`,于是渐变形状变得均匀,并在元素最近的边达到终点,形成了圆形渐变。而长边剩下的区域则填充了终点的颜色。 例 3,位置参数 `50px 30px` 把渐变的圆心放到了靠近左上角的位置。 ## 总结 本章的内容不少,都是一些很重要的概念,比如盒模型、定位元素、浮动与清除浮动和元素背景属性。 到目前为止,也对 《CSS 设计指南》 的重点知识进行了总结,当然可能有些地方总结的不够好,如有不对的地方欢迎指出和讨论。
';

第二章 CSS 工作原理

最后更新于:2022-04-01 01:18:10

在本章中作者主要讲解了 CSS 如何对 HTML 添加样式的,并且解释了层叠的工作机制比如当元素的同一个属性被多次设置样式后到底应该选择何种样式,这就要靠 CSS 的层叠机制来决定最终应用哪种样式了。 每个 HTML 元素都有一组样式属性,这些属性涉及元素在文档流中显示时的不同方面,比如在文档流中的位置、边框、背景、颜色等等。CSS 就是一种先选择 HTML 元素,然后设定选中元素 CSS 属性的机制。CSS 选择符和要应用的样式构成一条 CSS 规则。 ## 2.2 上下文选择器 上下文选择器的格式如下: ~~~ 标签1 标签2 { 声明} ~~~ 其中标签2就是我们要选择的目标,而且只有在标签1是标签2的祖先元素(不一定是父级元素)的情况下才会被选中。上下文选择器严格来讲应该叫「后代组合式选择器(Descendant Comninator Selector)」。 还有一点要注意的是,上下文选择器以空格作为分隔符,而分组选择器则以逗号作为分隔符,不要弄混。 ## 2.3 特殊的上下文选择器 前面一节作者介绍的上下文选择器是以某个祖先元素作为上下文的,只要目标元素在 DOM 结构「上游」存在这么一个祖先元素即可,无论这个祖先元素和目标元素隔了多少层级都没有关系,但有的时候我们需要比「某个祖先元素」更具体的上下文,这时候我们就可以使用一些特殊的选择器了,比如自选择器 `>`、 紧邻兄弟选择器`+`、一般兄弟选择器 `~` 和通用选择器 `*`。 ### 2.3.1 子选择器 > ~~~ 标签1 > 标签2 ~~~ 这里的标签2必须是标签1的子元素,也就是说标签1必须是标签2的父元素,而不能是标签2的任何其他祖先元素。 ### 2.3.2 紧邻兄弟选择器 + ~~~ 标签1 + 标签2 ~~~ 在这里标签2必须紧跟在兄弟标签1的后面,否则无效。 ### 2.3.3 一般兄弟选择器 ~ ~~~ 标签1 ~ 标签2 ~~~ 在这里标签2必须跟(不一定要紧跟,只需在标签1的后面即可)在其兄弟标签1后面。 ### 2.3.4 通用选择器 * ~~~ * ~~~ 通用选择器 `*` 是一个是一个通配符,代表文档流中的任意元素,不过通用选择器 `*` 通常会搭配一些其他选择器来使用,比如: ~~~ section > * ~~~ 代表 `section` 的所有子元素,不过一般情况下很少通过通配符来选择某个元素下的所有子元素,因为这涉及到浏览器性能问题,它会影响网页的渲染时间,我们写的时候是从左到右写的,但是浏览器渲染却是从右到左的,就上面这段代码来说,浏览器会先遍历所有的元素,然后在找出哪些元素的父元素是 `section`,另外举一个例子,有选择器: ~~~ div.container #main > .article {} ~~~ 浏览器在渲染时,先把所有类中包含 `article` 的元素取出来组成一个集合,然后对每一个集合中的元素进行遍历,如果元素的父元素的 `id` 不为 `main` 则把元素从集合中删去。 再然后从这个元素的父元素开始向上找,没有找到一个标签名为 `div` 并且类名中有 `container` 的元素,就把元素从集合中删去,直到匹配所有的条件,所以在能不使用通配符的情况就尽量不要使用它。 ## 2.4 ID 和类选择器 作者在这一节介绍了 `id` 和 `class` 选择器,为我们选择元素提供了另一种手段,利用它们可以不考虑元素在文档流中的层次结构,只要在元素中添加了 `id` 和 `class` 属性和值,我们就可以通过它们的值来找到目标元素。 > 可以给 `id` 和 `class` 属性设定任何值,但不能以数字或者特殊符号开头。 ### 2.4.3 什么时候用 id,什么时候用 class `id` 的用途是在页面中唯一地标识元素,所以每个页面中每一个 `id` 属性值都是独一无二的。而 `class` 的目的是为了标识一组具有相同特征的元素,也就是说一个页面中可以出现多个相同的类。 对于什么时候用 `id` 这个问题作者的观点是: > 每一个顶级区域都应该添加一个 `id`,从而得到非常明确的上下文关系,以便编写 CSS 时只选择嵌套在相应区域内的标签。 对于什么时候使用 `class`,由于 `class` 的目的是为了标识一组具有相同特征的元素,所以如果当页面中有一组元素具有某种相同的特征,就应该毫不犹豫的时候 `class`了。 但是这里也应该注意不要乱用类,避免造成类泛滥,例如: ~~~ <nav> <ul> <li class="boy"><a href="#">Alan</a></li> <li class="girl"><a href="#">Andrew</a></li> <li class="boy"><a href="#">Angela</a></li> <li class="boy"><a href="#">Angus</a></li> <li class="girl"><a href="#">Anne</a></li> <li class="girl"><a href="#">Annette</a></li> </ul> </nav> ~~~ 上面这个例子就是一个典型的类泛滥。 ### 2.4.4 id 和 class 的小结 对于什么时候用 id 和什么时候用 class,我想每个人都有不同的看法,这里写说一下笔者的观点,笔者认为能不实用 `id` 就尽量不使用 `id`,实际情况是笔者基本不在 CSS 中使用 `id`,因为在 CSS 的层叠机制中,`id` 的权重是 `class` 的10倍,其实很多情况下对某个元素设置某个不一样的样式来覆盖之前的样式并没有效果就是因为之前的样式权重太高,而为了达到效果就要编写权重更高的选择器,所以只有在某个元素需要被 JavaScript 找到的时候才会在某个元素中添加 `id` ,以便可以通过`document.getElementById()` 方法来快速获取需要的元素。 ## 2.5 属性选择器 属性选择器包括属性名选择器和属性值选择器,它们是通过元素的属性和值来获取元素的: ~~~ 标签名[属性名] 标签名[属性名="属性值"] ~~~ 例如: ~~~ img[title] {border: 2px solid blue;} a[target="_blank"] {background-image: url(_blank.png);} ~~~ 上面第一段代码意思是,如果某个 `img` 标签带有 `title` 这个属性,那么就为它添加一个宽度为 2px 的蓝色实线边框。第二段代码的意思是,如果某个 `a` 标签带有`target` 这个属性,并且这个属性的值为 `_blank` 那么就为这个元素添加一个背景图。 拓展: 其实除了以上两种属性选择器,还有其他几种属性选择器作者并没有列出来,这里这几种其他的属性选择器作一个简单的介绍: ~~~ 标签名[name^="value"] 让你匹配属性为 `name` 并且属性值以 `value` 开始的标签,如:a[href^= "http://"]则匹配所有具有 `href` 属性并且属性值以 `http://` 开始的标签。 标签名[name$="value"] 让你匹配属性为 `name` 并且属性值以 `value` 结束的标签,如:a[href$=".com"]则匹配所有具有 `href` 属性并且属性值以 `http://` 结束的标签。 标签名[name*="value"] 让你匹配属性为 `name` 并且属性值包含 `value` 的标签,如:a[href*= "renren"]则匹配所有具有 `href` 属性并且属性值包含 `http://` 的标签。 标签名[name|="value"] 让你匹配属性为 `name` 或者以 `name-` 开始的标签,如:p[lang|= "en"]则匹配具有 `lang` 属性的 `p` 标签,不管其属性值是 `en` 还是 `en-us` 。 标签名[name~="value"] 让你匹配属性为 `name` 并且其属性值是具有多个空格分隔的值,其中一个值为 `value`,如有: <a title="I'm title for learn more">Learn More</a> 就可以用 p[title~="learn"] 来选择这个元素。 ~~~ 你应该注意到了这些属性选择器与前面两种属性选择器之间的差别了,通过这些属性选择器我们可以很容易的做出许多意想不到的效果,比如: ~~~ a[href$=".pdf"] {background-image: url(pdf.png);} ~~~ 比如上面这段代码就为链接是 pdf 文档连接的 `a` 标签添加一个表示这个链接是 pdf 文档的图片,而其他 `href` 属性的值不是以 `.pdf` 结尾的 `a` 标签就不会应用这条样式声明,让用户很清楚的判断这是一个什么类型的链接。 ## 2.6 伪类 伪类这个叫法源自它们与类相似,但实际上并没有类会附加到标记中的标签上,伪类分为两种: * UI(User Interface,用户界面)伪类:会在 HTML 元素处于某个状态时(比如鼠标指针位于连接上),为该元素应用 CSS 样式。 * 结构化伪类:会在标记中纯在某种结构上的关系时(比如某个元素是一组元素的第一个或者最有一个元素),为相应的元素应用 CSS 样式。 ### 2.6.1 UI伪类 1. 链接伪类 * link: 链接就在那儿等着用户点击。 * visited:用户此前点击过这个链接。 * hover:鼠标指针正悬停在连接上。 * active:链接正在i被点击(鼠标在元素上按下,还没有释放)。 注意以上几种链接伪类要按一定的顺序才有效果,为了方便记忆作者是这么建议的:”LoVe?HA!”,大写字母就是每个伪类的第一个字母,其实也可以这么记: “LoVe,HAte”,其实都差不多就是了。 > 一个冒号(:)表示伪类,两个冒号(::)表示 CSS3 新增的伪元素。 2. :focus 伪类表单中的文本字段在用户单击它时会获得焦点,例如: ~~~ input:focus {border: 1px solid blud;} ~~~ 这段代码的意思就是当用户单击表单中的文本字段的时候,为该 `input` 标签添加宽度为 1px 的蓝色实线边框,需要注意的是,伪类的冒号要紧跟着标签名,之间不能有空格,否则该声明无效。 3. :target 伪类如果用户点击一个指向页面中其他元素的链接,则哪个元素就是目标(target),可以用 `:target` 伪类选中它,比如: ~~~ <a href="#more-info">More Information</a> ~~~ 位于页面其他地方、`id` 为 `more-info` 的那个元素就是目标元素,该元素可能是这样的: ~~~ <h2 id="more=info">This is the information you are looking for.</h2> ~~~ 那么 CSS 规则如下: ~~~ #more-info:target {background: #eee;} ~~~ 此时会在用户点击链接转向 `id` 为 `more-info` 的元素时,该目标元素的背景就会变成浅灰色。 ### 2.6.2 结构化伪类 1. first-child 、 last-child 和 nth-child(n) ~~~ e:first-child e:last-child ~~~ `first-child` 和 `last-child` 分别代表一组同胞元素中的第一个元素和最后一个元素,而 `nth-child(n)` 则代表一组同胞元素中的任何一个元素,其中 n 表示一个整数(也可以是 odd-奇数 或 even-偶数)或者也可以是一个算数表达式(2n + 1),例如: ~~~ <ul> <li>My Fast Pony</li> <li>Steady Trotter</li> <li>Slow Ol' Nag</li> </ul> ul li:first-child {color: black;} ul li:nth-child(2) {color: red;} ul li:last-child {color: blue;} ~~~ 上面的 HTML 应用了上面的 CSS 规则后,无序列表的第一个元素字体颜色就会变成黑色,第二个元素变成红色,最后一个元素就变成蓝色。 ## 2.7 伪元素 顾名思义,伪元素就是文档中若有实无的元素,下面是几个比较常用的伪元素。 1. ::first-letter 伪元素,比如: ~~~ p::first-letter {font-size: 300%;} ~~~ 这样 `p` 标签的第一个字母大小就会变成原来的 3 倍了,而其他元素则不会。 2. ::first-line 伪元素:可以选中文本段落的第一行。 3. ::before 和 ::after 伪元素 ~~~ e::before e::after ~~~ 可用在特定元素前面或后面添加特殊内容,比如: ~~~ <p class="age">25</p> .age::before { content: "Age: ";} .age::after { content: " years";} ~~~ 这里需要注意的是,对于 `::before` 和 `::after` 伪元素,其 `content` 属性是必须的,还有就是搜索引擎不会取得伪元素的信息(因为它在文档流中并不存在),因此不要通过伪元素添加一些对搜索引擎来说是重要的内容。 拓展: 其实伪元素前面冒号可以是两个也可以是一个,但是为了区别伪类,笔者建议大家还是使用两个冒号。还有一个要注意的是,比如通过 `::before` 和 `::after` 伪元素为`class` 为 `pseudo-element` 添加两个伪元素,则生成的两个伪元素分别处于 `pseudo-element` 元素的内部,也就是说是 `pseudo-element` 元素的子元素,并且分别位于`pseudo-element` 元素的内容的最前面和最后面,代码如下: ~~~ <div class="pseudo-element"> <p>Pseudo Element</p> </div> .pseudo-element::after, .pseudo-element::before { content: ""; } ~~~ ![Pseudo Element](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a354a421b07.png) 如上图所示,生成的两个伪元素分别处于 `pseudo-element` 元素的内部,并且分别位于 `pseudo-element` 元素的内容 `p` 标签的前面和后面,而不是如下图所示的位于`pseudo-element` 元素外部的前面和后面: ![Pseudo Element](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a354a4a6885.png) ## 2.9 层叠 层叠就是层叠样式表中的层叠,是一种样式在文档层次中逐层叠加的过程,目的是让浏览器面对某个标签特定属性值的多个来源确定最终使用哪个值。 层叠是 CSS 的核心机制,理解了它才能以最经济的方式写出最容易改动的 CSS,让文档外观在达到设计要求的同时,也给用户留下一些空间,让他们能根据需要更改文档的显示效果。 ### 2.9.1 样式来源 作者在这一节中介绍了样式的几种来源: ~~~ - 浏览器默认样式表 - 用户样式表 - 作者链接样式表 - 作者嵌入样式 - 作者行内样式 ~~~ 作者在书中是这么描述的: > 浏览器会按照上面的顺序依次检查每个来源的样式,并在有定义的情况下,更新对每个标签属性值的设定,整个检查更新过程结束后,再将每个标签以最终设定的样式显示出来。 ### 2.9.4 计算特指度 作者在这一节主要介绍了特指度的计算方法,相比作者个计算方式,笔者个人还是比较喜欢自己之前的计算方式,虽然差不多,如下: ~~~ // 首先规定四个等级:A - B - C - D 1\. A 等级代表内联样式:例如 `style=" "`,权值为:1000; 2\. B 等级代表 ID 选择器:例如 `#main`,权值为:100; 3\. C 等级代表类、伪类和属性选择器: `.class` 和 `[title]`,权值为:10; 4\. D 等级代表元素(标签)名或者伪元素选择器:例如 `p` 和 `::after`,权值为:1。 //计算完每个值后再将每个值加起来,哪个值大哪个值的权重就高。 ~~~ 例如: ~~~ body #main .class a[title]::after {} ~~~ 我们先分析它由哪些选择器构成,上面这条规则有一个 `id` 选择器(`#main`),一个类选择器(`.class`),一个属性选择器(`[title]`)、一个伪元素选择器(`::after`)和两个标签名选择器(`body` 和 `a`),所以它的权重就等于: ~~~ 100 × 1 + 10 × 2 + 1 × 3 = 123 ~~~ 还有一点要注意的是,权重值 001(12) 与 0020 相比,任然是 0020 的权重更高,对于权重一样的情况,则后声明的样式更高。 ## 2.10 小结 作者在本章介绍了 CSS 的一些规则,比如各种选择器的使用,层叠机制,还有权重的计算。 如果有不对或不理解的地方欢迎指出和讨论。
';

第一章 HTML 标记与文档结构

最后更新于:2022-04-01 01:18:08

由于 CSS 作用的对象是 HTML ,所以作者在这章主要先讲了一些基本的 HTML 标签的用法和结构。 ## 1.2 HTML 文档剖析 作者在这节主要讲了一个 HTML 页面所需的最基本的文档结构如下: ~~~ <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 这里是网页内容 --> </body> </html> ~~~ 首先 `` 是 HTML5 中新的文档类型声明语法,相比 HTML4 的冗长文档类型声明语法来说 HTML5 是大大的简化了。 ### 1.2.2 块级元素和行内元素 作者在这一节介绍了两个比较重要的概念————块级元素和行内元素,默认情况下块级元素会始终占居一行,而行内元素并不会。除了 table 元素的 display 属性比较特殊以外,基本上所有的 HTML 元素的 display 的属性值要么是 block,要么是 inline。作者的一个思想是,无论你想了解哪个 HTML 元素,第一个要问的问题就是:它是块级元素还是行内元素,然后在编写标记的时候预想到这个元素在初始状态下是如何定位的,这样才能进一步想好将来怎么用 CSS 重新定位它,因为块级元素和行内元素在定位上有很大的区别,后面的拓展会详细说明。 块级元素盒子(一个很重要的概念————盒模型,后面会详细说明)会扩展到与父元素同宽,这也是为什么块级元素会占居一行的原因了,因为所有块级元素的父元素都是 body,而它的默认宽度就是浏览器的视口(viewport)大小,所以默认情况下块级元素的宽度也和浏览器的视口一样宽,这样以来,一个块级元素旁边也就没有空间来容纳另一个块级元素了。 相比于块级元素会扩展到与父元素同宽,然而行内元素的行为却是恰恰相反,它会尽量的「收缩包裹」其内容(也是盒模型的概念),这也就是为什么几个行内元素会并排显示在一行直到它们排满一行才会另起一行,而每个块级元素会直接另起一行的原因了。 拓展: 作者在这一节中并没有对块级元素和行内元素的一些其他特性进行详细的解释,在这里笔者对它们的一些特性知识进行拓展。首先先列出一些常见的块级元素和行内元素: ~~~ <!-- 常见的块级元素 --> div, form, table, header, aside, section, article, figure, figcaption, h1~h6, nav, p, pre, blockqoute, canvas, ol, ul, dl <!-- 常见的行内元素 --> span, a, img, label, input, select, textarea, br, i, em, strong, small, button, sub, sup, code ~~~ 之前作者提到过无论你想了解哪个 HTML 元素,第一个要问的问题就是:它是块级元素还是行内元素,因为它们在盒模型上的表现有很大的不同,不过在了解它们的不同之前我们还得先知道另外一个概念————[替换元素](http://www.w3.org/TR/html5/rendering.html#replaced-elements)和[非替换元素](http://www.w3.org/TR/html5/rendering.html#non-replaced-elements),其中替换元素就是指浏览器是根据元素的属性来判断具体要显示的内容的元素,比如 `img` 标签,浏览器是根据其 `src` 的属性值来读取这个元素所包含的内容的,常见的替换元素还有 `input` 、`textarea`、 `select`、 `object`、 `iframe` 和 `video` 等等,这些元素都有一个共同的特点,就是浏览器并不直接显示其内容,而是通过其某个属性的值来显示具体的内容,比如浏览器会根据 `input` 中的 `type` 的属性值来判断到底应该显示单选按钮还是多选按钮亦或是文本输入框。而对于非替换元素,比如 `p`、`label` 元素等等,浏览器这是直接显示元素所包含的内容。看到这里你应该大概的知道了什么是替换元素和非替换元素了。 对着两个概念有了大概的了解后就可以对 `block` 和 `inline` 在盒模型上的表现差异进行了解了,首先是 `margin` ,[W3C](http://www.w3.org/TR/CSS2/box.html#margin-properties) 对其所支持了元素对象是这么定义的: > Applies to: all elements except elements with table display types other than table-caption, table and inline-table 英语不是很好,没太明白这句话的意思,我的理解就是所有元素都支持 `margin` 除了 `display` 属性值为 `table-caption` 和 `table-inline` 以外的所有表格显示类型比如`table-row-group`、 `table-cell`、 `table-row` 和 `table-header-group`等等,但是为了验证我的理解,我发先 `display` 属性值为 `table` 的元素也支持,可能是我对原文标准的理解有误。但还有一个要特别注意的是 `margin-top` 和 `margin-bottom` 两个属性比较特殊,它们对非替换行内元素没有效果,下面是 W3C 上对于 `margin-top` 和`margin-bottom` 支持对象的介绍: > Applies to: all elements except elements with table display types other than table-caption, table and inline-table > > These properties have no effect on non-replaced inline elements. 前面一句和之前对 `margin` 的描述是一样的,这毫无疑问,下面这句话的意思是这些( `margin-top` 和 `margin-bottom` )属性对非替换行内元素没有效果比如 `a` 和`span`,注意这里是**非替换行内元素**而不单单是非替换元素或者是行内元素。比如 `img` 就是一个行内元素, `margin-top` 和 `margin-bottom` 对它是有效果的,因为它是一个替换元素而不是非替换元素,所以对于「 `margin-top` 和 `margin-bottom` 对行内元素没有效果」这种说法是不对的。 而对于 `padding` 的支持对象,W3C 是这么描述的: > all elements except table-row-group, table-header-group, table-footer-group, table-row, table-column-group and table-column 上面这句话的意思是除了表格显示类型为 `table-row-group`、 `table-header-group`、 `table-footer-group`、 `table-row`, `table-column-group` 和 `table-column` 的元素不支持,其他所有的元素都支持。 但这里有些特殊情况需要注意的是,对行内元素比如 `span` 和 `img` 设置左右内边距的效果是可见可,但是对行内元素设置上下内边距在有些情况下是不可见的,这些情况又要分为是否为替换元素和是否设置了背景色,为了能更直观的了解这些概念,我在这里做了个表格: ![padding-top,bottom是否可见](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35466a8b54.png) 所以对于「 `padding-top` 和 `padding-bottom` 对行内元素没有效果」这种说法也是不对的,因为它们只是对于没有设置背景色的行内非替换元素效果不可见而已,而对于行内替换元素来说,不管是否设置了背景色都是有效果了,并且会把父元素撑开。 说了这么多 `block` 和 `inline-block` 的区别,其实除了这两个常见的 `display` 属性以外还有一个属性也是非常常见的,那就是 `inline-block` ,没错,这就是前面两种情况的结合体,它既有 `block` 的特性又有 `inline` 的特性,比如把一个 `display` 属性值为 `block` 或者 `inline` 的元素属性值设置成 `inline-block` 后,既可以用只对行内元素有效的 `text-align: center;` 声明对其进行居中以外,还可以用 `padding-top` 和 `padding-bottom` 对元素设置上下内边距而无需对其设置背景色,并且能把父元素撑开。 对于块级元素和行内元素的拓展就暂时到这,如果有不明白或者不对的地方也欢迎指出。 ## 1.3 文档对象模型 作者在这一小节只要介绍了 HTML 结构所对应的文档对象模型(DOM,Document Object Model),DOM 是从浏览器的视角来观察页面中的元素以及每个元素的属性,由此可以得出这些元素的一个家族树。通过 DOM 可以很清晰的看出文档中每个元素之间的关系。比如下面的 HTML 代码的 DOM 的家族树就如下图: ~~~ <body> <section> <h1>The Document Object Model</h1> <p>The page's HTML markup structure defines the DOM.</p> </section> </body> ~~~ ![DOM](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-13_55a35467a90ff.png) 上面是一个非常简单的 DOM 结构图,由此你可以和直观的看出 HTML 文档流中每个元素之间的关系,比如到底是父子元素还是兄弟元素。 ## 1.4 小结 作者在本章主要讲解了 HTML 标签是怎么为内容提供结构的,以及每个元素会在屏幕上生成什么样子的盒子,比如是行内盒子还是块级盒子,最后又简单的讲解了什么是 DOM ,它是浏览器中文档的模型,而 CSS 可以修改 DOM 中的元素样式属性,从而修改页面本身的布局和外观。
';

关于

最后更新于:2022-04-01 01:18:06

> 来源:[http://www.cleardesign.me/](http://www.cleardesign.me/) 本篇文章是对这几天看完 Charles Wyke-Smit 的 《CSS 设计指南》 后的一些学习笔记与心得,笔者好像是大一的时候开始接触网页设计,由于并不是计算机专业的,所以所有都是自己自学的,记得当时自己对 CSS 基本上什么都不懂,甚至连怎么在 CSS 中选择某个 class 和 id 都不懂,然后就直接下载一些源码来看,后来看到这些 CSS 文件中有 . 和 # ,然后就连蒙带猜的学会了怎么使用它们,然后就在源码中看到什么不懂的就直接上 W3School 中查找 API,这样也慢慢的让我掌握了 CSS 中常用的部分,并且制作网页时大多数的问题都能够得到解决。 由于期间自己的态度摇摆不定也想学 PHP、 Java、 Android 等等,然而结果可想而知,并没有坚持下来,如今大三也快结束马上要进入准大四的阶段了,感觉不能在这样下去了,前段时间一直在思考一个问题,自己到底喜欢什么,然后回想自己大学以来花的最多时间的地方是什么,最终的出的结果就是——前端,尽管前端涉及的知识很多,但这并不能阻碍我对它的热情。决定下来后的第一件事情就是系统的巩固一下自己的知识体系,然后就有了这篇 《CSS 设计指南》 的学习笔记,这本书也是比较多人推荐并且好评比较多的一本 CSS 入门书。 废话说了这么多然而并没有什么 * 用,赶紧进入正题才是,下面主要是笔者对某些章节的总结,并不是每一个章节的总结,同时也有笔者对书本内容的一些个人观点和一些拓展。
';