CSS

摩森特沃 2021年03月29日 469次浏览

基础

样式优先原则

优先顺序

  1. 在属性后面使用 !important 会覆盖页面任意位置定义的元素样式
  2. 作为 style 属性写在元素内的样式(行内样式)
  3. id 选择器
  4. 类选择器 | 伪类选择器 | 属性选择器(后面样式覆盖前面样式)
  5. 标签选择器
  6. 通配符选择器
  7. 继承的样式
  8. 浏览器自定义样式(user agent stylesheet)

注意:优先级计算主要针对以上3-6的选择器,当优先级无法确定顺序时,后来者会覆盖之前的样式,注意,例如一个标签上有多个class,此时的先后顺序是指在css样式中出现的先后顺序,并不是在class属性中的先后顺序

优先级计算

首先有 A、B、C、D 四个值:

  • 如果本样式是内联样式,那么 A = 1,否则 A = 0,例如

样式1:

h1 { color: red; }

样式2:

<h1 style="color: blue;">hello world</h1>

样式1不是内联样式,而样式2是内联样式,所以样式1的 A 值为 0,样式2 的 A 值为 1;

  • B 的值等于 ID 选择器 出现的次数,例如

样式1:

#list #item { color: red; }

样式2:

#list {color: blue;}

样式1的 B 值为 2,样式 2 B 值为 1

  • C 的值等于 类选择器 和 属性选择器 和 伪类 出现的总次数
  • D 的值等于 标签选择器 和 伪元素 出现的总次数 。

这样就计算出了 A、B、C、D 四个值,然后将四个值组成一个四位的数字,就得到了这个样式的权重

案例

<!DOCTYPE html>
<html>
<head>
  <style>
    #parent .children {
      color: red
    }

    .parent p {
      color: blue;
    }

    .parent p.children {
      color: yellow;
    }
  </style>
</head>

<body>
<div id="parent" class="parent">
  <p class="children">
    hello world
  </p>
</div>
</body>
</html>

根据以上优先级的计算方式,对于同一个样式而言(此处指color),三个样式的得分分别为:0110、0011、0021,所以最终第一个样式胜利,文字颜色为红色;但是如果添加这个样式:

 <p style="color:black" class="children">
    hello world
  </p>

这个内联样式的得分为:1000,所以它胜利,颜色为黑色

选择器

  • id选择器(#myId)
  • 类选择器(.myclassname)
  • 标签选择器(div,h1)
  • 相邻选择器(h1+p)
  • 子选择器(ul > li)
  • 后代选择器(li a)
  • 通配符选择器(*)
  • 属性选择器(a[rel="external"])
  • 伪类选择器(a:hover,li:nth-child)

盒子模型

  • box-sizing: content-box。标准盒子,默认值,设置元素的height/width属性指的是content部分的高/宽
  • box-sizing: border-box。IE 盒子,设置元素的height/width属性指的是border+padding+content部分的高/宽

position定位

  • static:默认位置。不需要特别声明,不常用。
  • relative:不脱离文档流,参考默认位置通过top,bottom,left,right定位
  • absolute:绝对定位,参考距其最近一个不为static的父级元素通过top, bottom, left, right定位
  • fixed:固定定位,相对于整个浏览器窗口进行定位,无论页面怎么滚动
  • sticky:黏性定位,屏幕范围内该元素位置不受影响,超出范围后,会变成 fixed,根据设置的left/top等属性成固定的效果

层叠上下文

从是否定位角度划分元素

  • 定位元素,position 的值为 relative,absolute,fixed或sticky的元素
  • 未定位元素,不是定位元素的都是未定位元素

浏览器元素渲染规则

  • 浏览器渲染定位元素和非定位元素的时候,遵循以下规则
    • 对于未定位元素,按照在元素在 HTML 文档中出现的顺序决定,越后面的元素越会覆盖在上面
    • 先渲染未定位元素,再渲染定位元素

z-index的渲染规则

  • z-index只对定位元素起作用,对非定位元素无效
  • 当一个元素被显示设置z-index值,不管是正数、负数还是 0,所有这个元素和它的所有后代元素形成一个层叠上下文
  • 层叠上下文的后代元素只参与和根元素的对比,不参与和根元素以外的元素对比,当根元素和子元素对比时,根元素被的 z-index 值被视为 0

总结-独立的层叠上下文中元素排列顺序

由下到上的层叠顺序(特别注意z-index为负数和未定位元素的先后顺序):

  • 层叠上下文的根元素
  • z-index为负值的已定位元素(包括它们的子元素)
  • 未定位元素
  • z-index为auto的已定位元素(包括它们的子元素)
  • z-index为正值的已定位元素(包括它们的子元素)

样式继承

可继承的样式

  • font-size
  • font-family
  • color
  • text-align

不可继承的样式

  • border
  • padding
  • margin
  • width
  • height
  • display

设置元素隐藏的方法

  • display: none:彻底消失,会导致浏览器回流和重绘,不能再触发点击事件
  • visibility: hidden:元素隐藏,空间仍保留,会导致重绘,但是不能再触发点击事件
  • opacity: 0:设置为透明,相当于它还在那里,但是你看不到,可以触发点击事件

居中布局

水平居中

  • 行内元素: text-align:center(详细内容参照下文样式验证中的text-align部分)
  • 块级元素: margin:0 auto
  • 绝对定位和移动: absolute + transformx
  • 绝对定位和负边距: absolute + margin
  • flex弹性布局: flex + justify-content:center

垂直居中

  • 子元素为单行文本: line-height:height
  • 当不需要指定元素的高度时,可以直接给一个相同的padding-top和padding-bottom,让元素和padding一起撑起来容器
  • dislpay设置为table显示(适用于需要指定容器高度,或者不能使用padding的时候): display:table-cell + vertical-align: middle
  • flex弹性布局:flex + align-items:center,适用于不需要严格的兼容时
  • 绝对定位和移动:absolute + transform,适用于不知道元素的高度时
  • 利用position定位 + top + margin,适用于知道容器和元素的高度且其他方法不能用时

清除元素浮动的方法

  • 使用clear属性的空元素
  • 在浮动元素后使用一个空元素,如:<div ></div>
  • 在css样式中使用.clear{clear:both;}
  • 使用<br >或<hr >
  • 使用css的overflow属性,给浮动元素添加overflow:hidden;或overflow:auto;
  • 使用css的:after伪元素(注意这不是伪类,而是伪元素,代表一个元素子后最近的元素)

CSS单位

px

  • px 是像素(pixel)的缩写,相对长度单位,是网页设计常用的基本基本单位,它是相对于显示器屏幕分辨率而言的。

em

  • em 是相对长度单位
    • 当用在font-size属性上时,相对的是父元素的font-size,如果当前父元素的字体元素未设置,则相对于浏览器的默认字体尺寸设置
    • 当用在其他属性上时,相对的是元素本身的font-size大小

rem

  • rem 是相对于 HTML 根元素的字体大小(font-size)来计算的长度单位。如果你没有设置 HTML 字体大小,那么以浏览器默认为主,一般为 16px。

vw/vh

  • vw 和 vh 是相对于 viewport(视口)的宽度或者高度而定的。

一般来说:1vw = npx / 100,即浏览器宽度为 200px 的时候,1vw = 200px / 100,即 1vw = 2px。

CSS3 部分新特性

新增样式属性

  • word-wrap:对长的不可分割单词换行,例如:word-wrap:break-word
  • text-shadow:文字阴影:text-shadow: 5px 5px 5px #FF0000;对应水平阴影,垂直阴影,模糊距离,阴影颜色
  • font-face:定义自己的字体
  • border-radius:圆角(边框半径),用于创建圆角
  • border-image:边框图片:border-image: url(border.png) 30 30 round
  • box-shadow:盒阴影:box-shadow: 10px 10px 5px #888888
  • 媒体查询:定义两套 CSS,当浏览器的尺寸变化时会采用不同的属性

CSS3 新增伪类

  • p:first-of-type:选择属于其父元素的首个元素
  • p:last-of-type:选择属于其父元素的最后元素
  • p:only-of-type:选择属于其父元素唯一的元素
  • p:only-child:选择属于其父元素的唯一子元素
  • p:nth-child(2):选择属于其父元素的第二个子元素
  • :enabled:disabled表单控件的禁用状态
  • :checked:单选框或复选框被选中

弹性布局

CSS 样式验证

text-align 的居中特性

  • 父盒子设置text-align: center;后,盒子里面的文字内容、行内元素、行内块元素都可以水平居中对齐,而块级元素则不可以,验证示例代码如下
<style type="text/css">
  /*清除浏览器默认间距 */
  * {
    margin: 0;
    padding: 0;
  }

  .text-center{
    border:1px solid #24b3a3;
    margin: 10px 0;
    overflow: hidden;
    text-align: center;
  }
  .d-inline-block {
    /*行内块元素*/
    display: inline-block;
    width: 300px;
    height: 100px;
    background-color: green;
  }
  .b-color {
    background-color: red;
  }

  .width-height {
    width: 300px;
    height: 100px;
    background-color: pink;
  }
  .width-height-margin {
    width: 300px;
    height: 100px;
    background-color: pink;
    /*块元素居中*/
    margin: 0 auto;
  }
</style>
<body>
  <!-- 1.文字内容 -->
  <!-- 展示效果:居中 -->
  <div class="text-center">
    文本元素
  </div>
  <!-- 2.行内元素 -->
  <!-- 展示效果:居中 -->
  <div class="text-center">
    <span>行内元素</span>
  </div>
  <!-- 3.行内块元素 -->
  <!-- 3.1.行内块元素-图片 -->
  <!-- 展示效果:居中 -->
  <div class="text-center">
    <img src="https://www.most-all.com/upload/2021/01/WechatIMG1-6b3f928200074980ae6ad1a568cb091d.png" />
  </div>
  <!-- 3.2.行内块元素-行内块 -->
  <!-- 展示效果:居中 -->
  <div class="text-center">
    <span class="d-inline-block">被转成行内块元素的行内元素</span>
  </div>
  <!-- 4.块元素,没有设置宽高,可以水平居中,因为没有设置宽高,会继承父盒子的宽高;就这个示例来说,实际上就成了1的情况-->
  <!-- 展示效果:居中,因为text-align的继承特性,实质上与1的效果相同 -->
  <div class="text-center">
    <div class="b-color">块元素,未设置宽高 + 父盒子设置text-align: center;</div>
  </div>
  <!-- 5.块元素的其他情形 -->
  <!-- 5.1.块元素,设置了宽高+未设置margin:0 auto;的块级元素无法水平居中-->
  <!-- 展示效果:居左 -->
  <div class="text-center">
    <div class="width-height">块元素,设置了宽高 + 未设置margin:0 auto;</div>
  </div>
  <!-- 5.2.块元素,设置了宽高+设置margin:0 auto;的块级元素可以水平居中-->
  <!-- 以下示例中实际上使块居中的是margin属性,与text-align无关,此时的text-align实际只控制了div内部的文本的居中显示 -->
  <!-- 展示效果:居中 -->
  <div class="text-center">
    <div class="width-height-margin">块元素,设置了宽高 + 设置margin:0 auto;</div>
  </div>
</body>

移动端CSS

特殊的标签说明

  • <meta name="viewport" content="width=device-width, initial-scale=1">

这个标签用来控制 viewport。浏览器的 viewport 是指用户可以看到的 Web 内容的窗口区域

当页面在移动设备上显示时,窗口通常比屏幕要宽;如果直接显示的话,页面一定会乱掉,所以移动端浏览器会有相应的机制来防止这种情况发生。默认情况下,浏览器会采用虚拟视口来渲染页面,例如移动设备的宽度为 640px,则可能会用 980px 的虚拟视口渲染页面,然后缩小页面以适应 640px 的窗口大小

但是这种方案的体验并不好,由于页面被缩小所以页面看起来会不够清楚,用户需要用手势放大页面再移动来仔细查看页面;而且由于虚拟窗口用于都是固定大小(例如 980px),所以媒体查询不会起作用。这种方案通常只被用来渲染未针对窄屏幕做过优化的页面

其中 width=device-width 是指用来渲染页面的视口的宽度与移动设备屏幕的宽度保持一致,这样就不会出现浏览器永远都用 980px 的视口渲染页面的情况。
initial-scale=1 是指初始页面不放大也不缩小。所以,对于响应式页面来说,这个标签是不可缺少的

物理像素,逻辑像素和像素密度

以 iPhone XS 为例,当编写 CSS 代码时,针对于单位 px,其宽度为 414px & 896px,也就是说当赋予一个 div 414px,这个 div 就会填满手机的宽度

而有一把尺子来实际测量这部手机的物理像素,实际为 1242*2688 物理像素;经过计算可知,1242/414=3,也就是说,在单边上,一个逻辑像素=3个物理像素,我们就说这个屏幕的像素密度为 3,也就是常说的 3 倍屏

对于图片来说,为了保证其不失真,1 个图片像素至少要对应一个物理像素,假如原始图片是 500300 像素,那么在 3 倍屏上就要放一个 1500900 像素的图片才能保证 1 个物理像素至少对应一个图片像素,才能不失真

另外一个简单粗暴的适配方案,就是针对所有屏幕,都只提供最高清图片。虽然低密度屏幕用不到那么多图片像素,而且会因为下载多余的像素造成带宽浪费和下载延迟,但从结果上说能保证图片在所有屏幕上都不会失真

还可以使用 CSS 媒体查询来判断不同的像素密度,从而选择不同的图片

my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
  #my-image { background: (high.png); }
}

移动端适配

移动端适配主要有两个维度:

  • 适配不同像素密度。这一部分比较简单,针对不同的像素密度,使用 CSS 媒体查询,选择不同精度的图片,以保证图片不会失真

  • 适配不同屏幕大小。由于不同的屏幕有着不同的逻辑像素大小,所以如果直接使用 px 作为开发单位,会使得开发的页面在某一款手机上可以准确显示,但是在另一款手机上就会失真。为了适配不同屏幕的大小,应按照比例来还原设计稿的内容,为了能让页面的尺寸自适应,可以使用 rem,em,vw,vh 等相对单位

CSS 样式备忘

文字超出显示省略号

  • 单行文本
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
  • 多行文本
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
/* -webkit-line-clamp:把块容器中的内容限制为指定的行数 */
/* 它只有在display属性设置成-webkit-box或者-webkit-inline-box并且-webkit-box-orient(en-US)属性设置成vertical时才有效果 */

宽高等比自适应容器

  • 通过vw视口单位实现(兼容性较差)

所谓视口单位(viewport units)是相对于视口(viewport)的尺寸而言,100vw等于视口宽度的100%,即1vw等于视口宽度的1%

<div class="box">
    <img src="http://images.pingan8787.com/2019_07_12guild_page.png" />
</div>
// css
*{
    margin:0;
    padding:0
}
.box{
    width:100%;
    height:51.5vw
}
.box img{ 
    width:100%; 
}
// .box高度为51.5vw是因为图片原来的尺寸是884 * 455的宽高比例,即 455/884 = 51.5%。
// 这个方法无论图片是否加载成功,容器高度始终是计算完成,不会造成页面抖动,也不会造成页面重绘,从而提升性能
  • 通过子元素padding实现(推荐)

通过设置子元素的padding属性来实现,是比较常用,也是效果比较好的一种,这里需要理解的是:子元素的padding属性百分比的值是相对父容器的宽度而言

<div class="box">
    <div class="text">
        <img src="http://images.pingan8787.com/2019_07_12guild_page.png" />
    </div>
</div>
// css
.box{
    width: 100%;
}
.text{
    overflow: hidden;
    height: 0; /* 高度设置为0,是避免增加额外的高度,同时由于高度为0,该元素的子元素会overflow溢出到padding所在的区域*/
    padding-bottom: 51.5%;
}
.box .text img{
    width: 100%;
}

扩展

CSS 的引入方式

  • 内联:style 属性(style="color: red")
  • 内嵌:style 标签(
  • 外链:link 标签(
  • 导入:@import(@import url('index.css') 或者 @import 'index.css')
  • link 是 XHTML 标签,除了加载 CSS 外,还可以定义 RSS 等其他事务;@import 属于 CSS 范畴,只能加载 CSS。
  • link 引用 CSS 时,在页面载入时同时加载;@import 需要页面网页完全载入以后加载。
  • link 是 XHTML 标签,无兼容问题;@import 是在 CSS2.1 提出的,低版本的浏览器不支持。
  • link 支持使用 Javascript 控制 DOM 去改变样式;而 @import 不支持。

png,jpg,gif,webp

  • png:便携式网络图片,一种无损数据压缩位图文件格式,优点是压缩比高,色彩好,大多数地方可用
  • jpg:一种针对相片使用的失真压缩方法,在网络上被用来存储和传输照片的格式
  • gif:一种位图文件格式,以8位色重现真色彩的图像,可以实现动画效果
  • webp:压缩率位jpg的2/3,大小比png小45%,压缩时间久,兼容性不好

::before和::after中双冒号和单冒号的区别

  • 通常情况下,:表示伪类,::表示伪元素(文档中不存在的元素),而对于before和after而言,:before/:after是Css2的写法::before/::after是Css3的写法
  • :before/:after的兼容性要比::before/::after好,不过在H5开发中建议使用::before/::after比较好
  • 这些伪元素 要配合content属性一起使用
  • 这些伪元素不会出现在DOM中,所以不能通过js来操作,仅仅是在 CSS 渲染层加入
  • 这些伪元素的特效通常要使用:hover伪类样式来激活

行内元素和块元素

行内元素

  • 常用行内元素
    • <a>, <span>, <b>, <em>, <i>, <cite>, <mark>, <code>
  • 行内元素特性
    • inline元素中只能包含内容或其他inline元素
    • 默认情况下,多个inline元素之间不会换行
    • 忽略margin-top,margin-bottom和padding-top,padding-bottom属性,margin-left,margin-right及padding-left,padding-right属性有效
    • 忽略height与width属性
    • 设置为inline-block时,inline元素将拥有block部分属性,如margin的所有属性均有效(同时还能避免margin的折叠),height与width也有效
    • inline元素若设置float为left或right,则拥有所有block元素的特征

块元素

  • 常用块元素
    • <p>, <div>, <form>, <header>, <nav>, <ul>, <li>, <h1>
  • 块元素特性
    • block元素中可以包含block元素、inline元素等所有元素
    • 默认情况下,block元素前后会另起一行(假设子元素没有设置float及position属性)
    • margin和padding所有属性均有效
    • block元素在未设置width属性时,默认占据父元素100%的width
    • block元素在未设置height属性时,默认高度根据子元素自适应(假设子元素没有设置float及position属性)

行内块元素

  • 常见行内块元素
    • <img>、<input>、<td>
  • 行内块元素特性
    • 既具有块元素特性也具有行内元素的特性,可以设置其宽度和高度,默认大小由行内块元素的内容而定,不会占据整行。行内块元素只能容纳文本或则其他行内元素。(a标签除外,a标签内可以放块元素)

替换元素

替换元素的实际类型或者实际内容与元素属性有关,如img的实际内容由其"src"属性指定的图像替换,input的实际类型由其"type"属性决定
替换元素表现类似inline-block类型元素,其特性见行内块元素特性
<img>, <object>, <button>, <textarea>, <input>, <select>

CSS中的BFC模式

定义

BFC(Block Formatting Context)格式化上下文,是指页面上一个隔离的独立容器,容器内部的子元素不会影响到外面的元素,反之外面的元素也不会影响容器里面的元素

BFC 布局特性

  • 在 BFC 中,盒子从顶端开始垂直地一个接一个地排列
  • 盒子垂直方向的距离由 margin 决定,属于同一个 BFC 的两个相邻盒子的 margin 会发生重叠

普通文档流布局规则

  • 浮动的元素不会被父级计算高度
  • 非浮动元素会覆盖浮动元素的位置
  • margin会传递给父级元素
  • 相邻元素的上下的margin会重叠

以下代码产生的页面中,它们的边距是 200px,需要通过 BFC 解决边距问题

<div style="width:100px; height:100px; margin-bottom:100px;"></div>
<div style="width:100px; height:100px; margin-top:200px;"></div>

BFC的布局规则

  • 浮动元素会被父级计算高度(父级元素触发了 BFC)
  • 非浮动元素不会覆盖浮动元素的位置(非浮动元素触发了 BFC)
  • margin不会传递给父级(父级触发 BFC)
  • 属于同一个BFC的两个相邻元素上下margin会重叠

BFC在开发中的应用

  • 清除元素内部浮动,内部的Box会在垂直方向上一个接一个的放置
  • 解决外边距合并问题,阻止margin重叠
  • 阻止元素被浮动元素覆盖(BFC 的区域不会与float的元素区域重叠)

形成BFC的条件

  • float: left/right
  • position: absolute/fixed
  • display: inline-block/table-cell/table-caption/flex/grid
  • overflow: hidden/auto/scroll

脱离文档流

文档流

将窗体自上而下分成一行一行,并在每行中按从左至右一次排放元素,成为文档流

脱离文档流

脱离文档流的元素,将不再在文档流占据空间,而是漂浮在文档流上方

  • float: left/right:元素会脱离并且具有block或者table的特性,即可以设置宽高,但是其他盒子会环绕该元素的周围
  • position: absolute/fixed:absolute 为绝对定位,脱离文档流之后还是会相对于该元素的父类(做了 relative/absolute 定位的父类)进行偏移。而 fixed 就是完全脱离文档流,相对于 HTML (整个浏览器窗口)的形式展示

高度塌陷

当父元素没有设置高度时,其高度由子元素撑开,此时如果子元素脱离了文档流,则父元素的高度将发生塌陷,页面可能发生混乱

高度塌陷坚决方案

  • 开启bfc模式(参考前文内容)
  • 在父元素里的最末尾的位置添加一个div,然后对这个div设置清除浮动clear:both;,就解决了父元素高度塌陷。这个方法基本没有副作用(w3c推荐,全浏览器兼容)
  • 使用css中的after伪类,通过after伪类向父元素的末尾添加一个空白的块元素,然后对其清除浮动,使用它来解决父元素高度塌陷。和直接添加div原理一样,但不会添加多余的结构,非常推荐使用
/*以后这个clearfix类可以添加到任何高度塌陷的元素中解决问题*/
.clearfix:after{
    /*添加一个空元素*/
    content:"";
    /*使其变为块元素*/
    display:block;
    /*清除两侧浮动*/
    clear:both;
}
/*更加优秀的版本(即考虑了高度塌陷又考虑了父子元素垂直外边距重叠问题)*/
.clearfix:before,.clearfix:after{
    /*添加一个空元素*/
    content:"";
    /*使其变为块元素*/
    display:table;
    /*清除两侧浮动*/
    clear:both;
}

/*兼容ie6的额外样式*/
.clearfix{
    zoom:1;
}

如何解决 a 标点击后 hover 事件失效的问题

  • 改变 a 标签 CSS 属性的排列顺序

在 CSS 中,如果对于相同元素针对不同条件的定义,适宜将最一般的条件放在最上面,依次向下,保证最下面的是最特殊的条件(可以理解为样式覆盖),因此针对上述问题,应当使用如下的顺序进行样式边下:

link -> visited -> hover -> active

  • a:link:简写 a,未访问的样式
  • a:visited:已经访问的样式
  • a:hover:鼠标移上去时的样式
  • a:active:鼠标按下的样式

引用参考