CSS 学习笔记(三)问题集合

这篇文章主要记录我在学习 CSS 和实际使用 CSS 中遇到的各种问题和解决办法,大概也是一篇使用技巧集合,另外这篇文章我目测将一直更新下去,直到我不再从事前端开发为止……

2017年09月20日更新:文字换行,并修改了以前内容中的有问题的地方

宽度问题

我个人一直比较喜欢流体布局,这样布局的页面在几乎所有大小的浏览器中都能得到很好的展示效果,使用流体布局,宽度是一个很重要的属性,我推荐从根元素开始,就为元素设置上width: 100%属性,以后每一个子元素都为其设置好适当的宽度属性,当然最好也能用百分比来确定。

宽度高度的百分比设定

设置元素的宽度高度时,若使用百分比设定,则一定要注意其父元素是否已经明确设置了宽度高度属性,因为使用百分比形式设置子元素宽度高度时,需要依赖对应的父元素来计算出子元素的具体宽度高度,这里所说的父元素明确设置宽度高度属性是指父元素设置了 100px、100em 这样的带有单位的确定数值或者同样宽度高度同样设置为百分比的形式,若父元素的宽度高度值为带有单位的确定数值,则根据百分比直接计算出子元素的宽度高度,如果父元素的宽度高度同样是百分比形式,那么就会继续向上寻找祖元素,查看祖元素的宽度高度值,然后根据同样的规则,计算出父元素的宽度高度,再计算出子元素的宽度高度。

按钮处于 focus 状态时边框高亮

在浏览器中点击按钮、输入框甚至 a 标签时,经常会看到这些元素的边框出现高亮状态,提醒用户页面当前焦点处于此处,但有时候我们不想要这种状态,一种办法是使用 JS 触发元素的blur事件,使元素失去焦点,这种办法不推荐;另外一种办法是设置元素的 CSS 属性outline: noneoutline属性一般用于设置元素的外线条轮廓,设置为none则表示不显示,从而避免出现边框高亮效果。

上下元素高度确定,中间元素撑满剩余页面

我第一次实现这个效果时,期望使用height: 100%来实现,但很明显这样做是不成功的,百分比形式的高度是根据其父元素的高度计算出来的,如果设置成 100%,则其含义不是元素的高度为当前父元素剩余的高度,而是元素的高度等于父元素的高度。第一种实现方法是设置元素的定位属性为绝对定位position: absolute,然后设置元素的top属性为上面元素的高度,bottom属性为下面元素的高度,这样该元素就可以撑满父元素的剩余部分了,我比较倾向于使用这种方法;第二种实现方法是通过 CSS3 的一些新增属性来实现,例如使用height: calc(100% -100 px - 100px)来动态地计算出整个页面除了上下两个高度为 100px 的元素之外剩余部分的高度,或者使用height: 100%; box-sizing: border-box; padding: 100px 0来填满父元素的剩余部分。

设置定位属性为 fixed 或 absolute 时的兼容性

当为元素设置定位属性为fixedabsolute时,最好水平属性和垂直属性各自设置一个,因为有部分浏览器的默认定位值不是 0,例如 Safari 在渲染定位属性为fixed的元素时,如果不显式地设置left: 0,则默认的值不是 0,这样在页面上可能就找不到该元素了。

设置 padding 属性时元素实际尺寸发生变化

有部分元素,在设置其padding属性时,其实际尺寸会发生变化,比如原来元素的宽度为 100px,padding-left为 0,则此时元素的实际宽度就是 100px,之后设置元素的padding-left属性为 10px,这时元素的实际宽度会变成 110px。这是我们不想要的,但浏览器这样做是正确的,因为一般width指的是元素内容区域的宽度,增加padding不会影响到元素内容区域的尺寸,也就是不会影响width,但是会影响元素的总尺寸,而总尺寸是会影响元素在父元素中的存在方式的,上面所说的这个例子就属于这种情况,所以当设置元素的width为 100px 以后,再设置元素的padding-left为 10px,就会造成元素的总尺寸变为 110px。如果我们不希望这种情况出现,比较简单的方法是设置元素的宽度为 90px,也就是原来的宽度减去padding的大小,这样总尺寸就不会变化,但如果元素的宽度属性为百分比形式,这种方法就不能奏效了,应对这种情况的办法是设置元素的 CSS3 属性box-sizing: border-box,它的作用是改变元素盒模型的尺寸计算方法,如果设置为border-box,则表示元素的widthpadding+content,这样元素的padding就会被计算进元素宽度中,宽度设置好了以后,内容尺寸会随着padding的大小而自适应地发生改变,而元素的宽度也就不会因为padding的设置而发生变化了。

设置 textarea 元素不可拖拽

很简单,设置元素的 CSS 属性resize: none即可。

设置背景图片的位置

很简单,直接设置 CSS 属性background-position即可,其可以设置两个值,第一个是左边距,第二个是上边距。

设置图片铺满元素,且保持纵横比

这个要求在显示图片的时候经常会遇到,解决方法是我自己实践出来的,可能不是最好的方法。

1
2
3
4
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-image: url('images/xxx.png');

其中,background-size: cover;用于实现将图片铺满整个元素,background-position: center;用于控制图片的中心与元素的中心重合,background-repeat: no-repeat;用于控制图片不重复,其实最重要的是前两个属性,第三个属性可有可无。

设置鼠标样式

如果你希望鼠标指向某一个元素的时候,鼠标的样式发生变化,可以通过设置cursor属性来实现,比较常用的值是pointer,此时鼠标的样式为指向超链接时的模样。

设置文字修饰

很简单,直接设置 CSS 属性text-decoration即可,比较常用的值是none,此时文字上没有上划线、下划线等文字修饰,比较适合于 a 标签用作按钮时使用。

文字换行

关于文字换行,其实主要的还是在处理西文文字的时候需要考虑的时候,一个很长很长的单词因为浏览器默认的不换行的原因,会导致元素内容冲出元素边界,这在很多时候都不是我们想要的;当然,在处理中文的时候,浏览器虽然会自动换行,但有时候我们并不希望出现换行效果,例如在实现元素尾部多余文字自动变为省略号的时候,就要使文字没有换行效果。

控制文字换行的属性有两个,一个是word-break,还一个是word-wrap。其中,word-break有两个属性值,一个是break-all,它代表浏览器在必要的时候可以在单词内部换行,也就是可以强行把单词截断,后半部分另起一行显示,还有一个属性值是keep-all,它只允许浏览器在碰到空格或半角字符(中文的标点符号一般都是半角的,注意是一般是)的时候换行,如果你不想发生任何意外,那就设置word-break: break-all更保险一些。

至于word-wrap,他有一个属性值(其实有两个,normal是浏览器默认的)break-word,它的作用比word-break属性值keep-all强一些,比break-all弱一些,比keep-all强一些是指它不仅会在碰到空格或全角字符的时候会产生换行效果,而且还会在其他一些情况下产生换行效果,例如中英文混排的时候,keep-all就不会产生换行效果,而break-word则会在中英文交界的地方产生换行效果,比break-all弱一些是指它会尽量使英文的换行看起来更加自然一些,而break-all则会很“粗暴”地直接将英文截断,所以在实际使用中使用word-wrap: break-word看起来应该会更好一点。

除了上面两种 CSS 属性控制文字在什么情况下产生换行效果,还有一个 CSS 属性对文字换行也具有影响作用,它就是white-space,它原本的设计目的是控制浏览器如何处理文字中的空白,但它的nowrap属性值却可以控制文本不产生换行效果,所以在这里一并将其归入文字换行的范畴。

属性值normal是浏览器默认的,它的效果是合并空白和换行符为一个空白,在没有其他文字换行属性被设置的情况下按照浏览器默认的方式正常换行。

pre非常适合显示代码类字符,它的效果是保留所有的空白和换行符,因此带有大量缩进和换行的代码类字符在这个属性的控制之下可以很好的(高保真,哈哈)显示在页面上。

pre-wrap将会保留所有的空白和换行符,也就是说它控制文字不仅在换行符处换行,而且同时按照浏览器默认的方式正常换行,比如一段很长的文字,在pre属性的控制之下就不会产生换行效果,在pre-wrap属性的控制之下就会按照浏览器默认的方式正常换行。

pre-line将会合并所有的空白为一个空白,保留所有的换行符,同时按照浏览器默认的方式正常换行,它与pre-wrap唯一的不同就是它会合并所有的空白,而pre-wrap是会保留所有的空白的。

nowrap是个大杀器,它终结一切换行效果,它会合并所有的空白和换行符为一个空白,即使设置了word-break: break-all或者其他换行设置,它只有一个弱点,就是在碰到<br />标签的时候才会产生换行效果,这样做算是给程序员留了一个后门吧,毕竟凡事不能做得太绝……

CSS 选择器权重

CSS 选择器权重在实际应用中具有很重要的作用,它控制最终应用到 DOM 元素上的 CSS 样式到底是什么样的,如果对 CSS 选择器的权重不熟悉,那么就有可能出现最后显示的效果与预想的效果出现很大的差别,因此还是很有必要了解和学习 CSS 众多选择器的权重。

首先,我们可以这样给出一个 CSS 选择器权重的表达式,0,0,0,0,0,它的意思是指每种类型的选择器(广义上的)所占的比重,其中选择器对应的比重越靠前,则这种选择器的比重越大,当 CSS 选择器产生冲突时,比重大的选择器所包含的样式优先于比重小的选择器所包含的样式。

第一位比重所对应的是!important标识符,它的比重在所有的 CSS 选择器中最大,只要 CSS 样式后面带有!important标识符,则它所对应的 CSS 样式将会优先于其他所有 CSS 选择器,一个 CSS 样式带有!important标识符,则其对应的比重为1,0,0,0,0

第二位比重所对应的是内联样式,也就是通过style属性直接写在 DOM 元素中的样式定义方式,一个 CSS 样式是通过style属性直接写在 DOM 元素中,则其对应的比重为0,1,0,0,0

第三位比重所对应的是 ID 选择器,一个 CSS 样式是通过 ID 选择器的方式应用到 DOM 元素中,则其对应的比重为0,0,1,0,0

第四位比重所对应的是类选择器、伪类选择器(常见的伪类选择器有:link:visit:hover:focus:active:enabled:disabled:checked)、属性选择器,例如.class:hover[type=text],一个 CSS 样式是通过这三种选择器中的其中一种应用到 DOM 元素中,则其对应的比重为0,0,0,1,0

第五位比重所对应的是标签选择器、伪元素选择器(常见的伪元素选择器有:before:after)例如divp:before,一个 CSS 样式是通过这两种选择器中的其中一种应用到 DOM
元素中,则其对应的比重为0,0,0,0,1

通过通配符*、子选择器、相邻选择器定义的样式,它们没有比重,换种说法就是它们的比重为0,0,0,0,0,但是它们所定义的 CSS 样式仍然要比继承的样式优先级高,通过继承获得的样式优先级在所有的 CSS 选择器中是最低的。

CSS 选择器比重的计算方法是,如果一个 CSS 样式有多个占位比重相同的 CSS 选择器,则这些 CSS 选择器的比重按位相加以后就是该 CSS 样式最后的比重,例如:

1
2
3
.a .b .c {
text-align: center;
}

上面这个 CSS 选择器中 CSS 属性text-align: center所对应的比重为0,0,0,3,0

再如:

1
2
3
#a .b p:before {
text-align: center;
}

上面这个 CSS 选择器中 CSS 属性text-align: center所对应的比重为0,0,1,3,2

CSS 选择器比重的比较方法是从左到右逐级比较,只有前面一级相等才会比较后面的比重,前面一级不等的情况下,比重大的 CSS 样式优先被应用到 DOM 元素上。


注意:上面的 CSS 选择器比重比较是建立在“距离相等”的情况下进行的,CSS 样式应用遵循就近原则,距离目标元素越近的 CSS 选择器对包含的 CSS 样式优先级越高,只有当众多 CSS 选择器它们距离目标元素的距离相同的时候,才会通过 CSS 选择器的比重比较计算出目标元素最后应用的 CSS 样式。


关于 CSS 比重的一些练习题目,可以参考这里