标签 CSS 下的文章

CSS 最核心的几个概念

CSS 最核心的几个概念

本文将讲述 CSS 中最核心的几个概念,包括:盒模型、position、float等。这些是 CSS 的基础,也是最常用的几个属性,它们之间看似独立却又相辅相成。为了掌握它们,有必要写出来探讨一下,如有错误欢迎指正。

元素类型

HTML 的元素可以分为两种:

  • 块级元素(block level element)
  • 内联元素(inline element 有的人也叫它行内元素)

两者的区别在于以下三点:

  1. 块级元素会独占一行(即无法与其他元素显示在同一行内,除非你显式修改元素的 display 属性),而内联元素则都会在一行内显示。
  2. 块级元素可以设置 width、height 属性,而内联元素设置无效。
  3. 块级元素的 width 默认为 100%,而内联元素则是根据其自身的内容或子元素来决定其宽度。

最常见块级元素应该是  <div> 吧,内联元素有  <span>  <a>  <img> 等等,完整的元素列表可以谷歌一下。

具体来说一下吧,

1
2
3
4
.example {
width: 100px;
height: 100px;
}

我们为  <div> 设置上面的样式,是有效果的,因为其是块级元素,而对  <span> 设置上面的样式是没用的。要想让  <span> 也可以改变宽高,可以通过设置  display: block; 来达到效果。当 display 的值设为 block 时,元素将以块级形式呈现;当 display 值设为 inline 时,元素将以内联形式呈现。

若既想让元素在行内显示,又能设置宽高,可以设置:

1
display: inline-block;

inline-block 在我看来就是让元素对外呈内联元素,可以和其他元素共处与一行内;对内则让元素呈块级元素,可改变其宽高。


HTML 代码是顺序执行的,一份无任何 CSS 样式的 HTML 代码最终呈现出的页面是根据元素出现的顺序和类型排列的。块级元素就从上到下排列,遇到内联元素则从左到右排列。这种无样式的情况下,元素的分布叫普通流,元素出现的位置应该叫正常位置(这是我瞎起的),同时所有元素会在页面上占据一个空间,空间大小由其盒模型决定。

盒模型

页面上显示的每个元素(包括内联元素)都可以看作一个盒子,即盒模型( box model )。请看 Chrome DevTools 里的截图:

可以显而易见的看出盒模型由 4 部分组成。从内到外分别是:

1
content -> padding -> border -> margin

按理来说一个元素的宽度(高度以此类推)应该这样计算:

1
总宽度 = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right

但是不同浏览器(你没有猜错,就是那个与众不同的浏览器)对宽度的诠释不一样。符合 W3C 标准的浏览器认为一个元素的宽度只等于其 content 的宽度,其余都要额外算。于是你规定一个元素:

1
2
3
4
5
6
.example {
width: 200px;
padding: 10px;
border: 5px solid #000;
margin: 20px;
}

则他最终的宽度应为:

1
宽度 = width(200px) + padding(10px * 2) + border(5px * 2) + margin(20px * 2) = 270px;

而在 IE(低于IE9) 下,最终宽度为:

1
宽度 = width(200px) + margin(20px * 2) = 240px;

我个人觉得 IE 的更符合人类思维,毕竟 padding 叫内边距,边框算作额外的宽度也说不下去。W3C 最后为了解决这个问题,在 CSS3 中加了 box-sizing 这个属性。当我们设置  box-sizing: border-box;时,border 和 padding 就被包含在了宽高之内,和 IE 之前的标准是一样的。所以,为了避免你同一份 css 在不同浏览器下表现不同,最好加上:

1
2
3
4
5
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}

这里还有两种特殊情况:

  • 无宽度 —— 绝对定位(position: absolute;) 元素
  • 无宽度 —— 浮动(float) 元素

它们在页面上的表现均不占据空间(脱离普通流,感觉像浮在页面上层一样,移动它们不影响其他元素的定位)。这就涉及到另外两个核心概念 position 和 float。

position

position 这个属性决定了元素将如何定位。它的值大概有以下五种:

position 值 如何定位
static position的默认值。元素将定位到它的正常位置(上文提到过),其实也就相当于没有定位。元素在页面上占据位置。不能使用 top right bottom left 移动元素位置。
relative 相对定位,相对于元素的正常位置来进行定位。元素在页面占据位置。可以使用 top right bottom left 移动元素位置。
absolute 绝对定位,相对于最近一级的 定位不是 static 的父元素来进行定位。元素在页面不占据位置。 可以使用 top right bottom left 移动元素位置。
fixed 绝对定位,相对于浏览器窗口来进行定位。其余和 absolute 一样,相当于一种特殊的 absolute。
inherit 从父元素继承 position 属性的值。

具体效果可以参考w3school的实例,或者自己写一下就明白了。

每个网页都可以看成是由一层一层页面堆叠起来的,如下图所示。

图片来自网络图片来自网络

position 设置为 relative 的时候,元素依然在普通流中,位置是正常位置,你可以通过 left right 等移动元素。会影响其他元素的位置。

而当一个元素的 position 值为 absolute 或 fixed 的时候,会发生三件事:

  1. 把该元素往 Z 轴方向移了一层,元素脱离了普通流,所以不再占据原来那层的空间,还会覆盖下层的元素。
  2. 该元素将变为块级元素,相当于给该元素设置了  display: block;(给一个内联元素,如  <span> ,设置 absolute 之后发现它可以设置宽高了)。
  3. 如果该元素是块级元素,元素的宽度由原来的 width: 100%(占据一行),变为了 auto。

由此观之,当 position 设置为 absolute 或 fixed,就没必要设置 display 为 block 了。而且如果你不想覆盖下层的元素,可以设置 z-index 值 达到效果。

float

float 顾名思义,就是把元素浮动,它的取值一共有四个:left right none inherit,光看名字就懂了,无需多言。

最初的 float 只是用来实现文字环绕图片的效果,仅此而已。而现在 float 的应用已不止这个,前辈们也是写了无数博文来深入浅出的讲解它。
浅如:
经验分享:CSS浮动(float,clear)通俗讲解 篇幅不长,通俗易懂,可以看完这篇文章再回过头来看本文。
深如:
CSS float浮动的深入研究、详解及拓展(一)
CSS float浮动的深入研究、详解及拓展(二)
从本质上讲解了 float 的原理。

我就不班门弄斧写原理了,只说说 float 的几个要点就行了:

  1. 只有左右浮动,没有上下浮动。
  2. 元素设置 float 之后,它会脱离普通流(和  position: absolute; 一样),不再占据原来那层的空间,还会覆盖下一层的元素。
  3. 浮动不会对该元素的上一个兄弟元素有任何影响。
  4. 浮动之后,该元素的下一个兄弟元素会紧贴到该元素之前没有设置 float 的元素之后(很好理解,因为该元素脱离普通流了,或者说不在这一层了,所以它的下一个元素当然要补上它的位置)。
  5. 如果该元素的下一个兄弟元素中有内联元素(通常是文字),则会围绕该元素显示,形成类似「文字围绕图片」的效果。(可参考CSS float浮动的深入研究、详解及拓展(一)中的讲解)。
  6. 下一个兄弟元素如果也设置了同一方向的 float,则会紧随该元素之后显示。
  7. 该元素将变为块级元素,相当于给该元素设置了  display: block;(和 position: absolute; 一样)。

原文

CSS编写原则

原文

CSS写的好可以让网页瞬间高大上,但是再高大上的网站如果效率很低也不行,尤其是在近几年「用户体验」这个词烂大街以后。前两天自己写了几个页面的CSS,顺便拜读了很多关于CSS如何写的更好的文章,现在动手总结一下。

权重

CSS中我个人觉得权重是个很需要掌握的概念。它决定哪一条样式将被应用在元素上,哪一条样式将被覆盖掉。众所周知,CSS选择器,最基本的有三种:

  • id选择器
  • class选择器
  • 标签选择器

还有一种内联样式( inline-style ),是指直接在HTML代码中添加CSS样式。以上四种的权重顺序是:内联样式(1000) > id选择器(100) > class选择器(10) > 标签选择器(1)。括号内分别是它们的权重值!。举个栗子:

1
<span style=“color : #fff;” id=“example” class=“demo”>栗子</span>
1
#example {color: #000;}
1
.dome {color: red;}
1
span {color: blue;}

如果只有第四句来定义样式,则这个 &lt;span&gt;是蓝色的,如果加上第三条语句,则变成了红色,第四句被覆盖掉了。如果用第二句,则变为黑色,第三句即被覆盖,以此类推如果用内联样式则 &lt;span&gt;变成白色了。

像我这样的菜鸟刚开始滥用各类选择器,往往会出现想覆盖父元素样式的时候覆盖不了的情况,熟不知要想覆盖,必须让这条语句的权重值大于父元素(具体可以参考这篇文章你应该知道的一些事情——CSS权重)。

尽量不要用id选择器

由于id选择器权重值过大的原因,我们要尽量少用它(内联样式估计没人会用了吧)。

1
2
3
<div id=“example” class=“parent”>
<span class=“son”></span>
</div>

如果你使用id选择器

1
#example span {background-color: blue;}

则再写

1
.son {background-color: red;}

就没用了,甚至

1
.parent .son {background-color: red;}

都没用。你必须用:

1
#example .son {background-color: red;}

才能再改变它的背景色。这样远不如只用一个class轻松写意。尤其是#example下面层级多的话,代码就会越写越长,可见少使用id,多用class才是正道。而且id只能用一次,class可以重复使用。

尽量不要多层级的选择器

当CSS写到后来,你可能会发现经常有类似这样的一长串代码出现:

1
#example .content .right .tag span {color: blue;}

这主要还是因为你没有搞清权重的原因。每次你想为子元素重新定义样式时都要有个权重值大于父元素的一大串选择器。这样的代码不仅你看起来痛苦,浏览器看起来也痛苦(原因可参考这篇文章【高性能前端2】高性能CSS)。

所以后代选择器不仅性能低下而且代码很脆弱:HTML代码和CSS代码严重耦合,HTML代码结构发生变化时,CSS也得修改,自己改起来都痛苦,更别说万一将来有人来接盘你的代码……你考虑过他的感受么T_T。还是那句话,用class,最多两三层选择器就搞定了!

其实还有个终极神器 !importants。只要在样式语句后面加上这个就能覆盖之前之后的一切样式!这意味着你再想把它覆盖是不可能的。当你都逼到用这个神器的时候,说明你的代码实在写的不敢恭维……你一定会有更好的解决方式的,所以尽量不要用 !importants

精简

精简你的CSS代码可以提升你编写的速度,还能让代码看起来整洁、一目了然,节省时间和空间。

使用复合语法

尽量使用复合语法:

1
2
3
4
5
6
7
8
9
10
11
12
// 糟糕的写法
.someclass {
background: #000;
background-image: url(../imgs/carrot.png);
background-position: bottom;
background-repeat: repeat-x;
}
// 好的写法
.someclass {
background: #000 url(../imgs/carrot.png) repeat-x bottom;
}

类似的还有 paddingmarginfontborder等。用复合语法可以精简代码,一目了然。

减少重复

  • 利用CSS继承

如果页面中父元素的多个子元素使用相同的样式,那最好把他们相同的样式定义在其父元素上,让它们继承这些CSS样式。

1
2
3
4
5
6
7
// 糟糕的写法
.example li {font-family:Georgia, serif;}
.example p {font-family:Georgia, serif;}
.example h1 {font-family:Georgia, serif;}
// 好的写法
.example {font-family:Georgia, serif;}
  • 利用分组选择器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 糟糕的写法
.someclass {
color: red;
background: blue;
font-size: 16px;
}
.otherclass {
color: red;
background: blue;
font-size: 8px;
}
// 好的写法
.someclass, .otherclass {
color: red;
background: blue;
}
.someclass {
font-size: 16px;
}
.otherclass {
font-size: 8px;
}

移除没用的样式

移除无匹配的样式,有两个好处:

第一,删除无用的样式后可以缩减样式文件的体积,加快资源下载速度;

第二,对于浏览器而言,所有的样式规则的都会被解析后索引起来,即使是当前页面无匹配的规则。移除无匹配的规则,减少索引项,加快浏览器查找速度;

格式

命名很重要

程序猿最讨厌的事已经不是写文档了,而是命名。好的命名可以让你「见名思义」,不写注释也可以读懂;坏的命名会让你抓狂,你不得不用ctrl+F匹配它们……我还发现很多人都是根据HTML代码的结构去命名,如

[/crayon]
等等,这些并没有实际的意义,当HTML越来越复杂的时候,或者新人来接手的时候,就会时常摸不着头脑,难以调试和维护。所以我个人觉得应该多用具有实际意义的、可以见名思义的class命名。

好看一点

代码的易读性和易维护性成正比。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 糟糕的写法
.someclass-a, .someclass-b, .someclass-c, .someclass-d {
}
// 好的写法
.someclass-a,
.someclass-b,
.someclass-c,
.someclass-d {
}
// 更好看一点
.someclass {
background-image:
linear-gradient(#000, #ccc),
linear-gradient(#ccc, #ddd);
box-shadow:
2px 2px 2px #000,
1px 4px 1px 1px #ddd inset;
}

人生的悲剧只有两种:一种是没有得到自己想要的东西,另一种是得到自己想要的东西。
                                —王尔德

标签

打赏