CSS 知识总结

446 阅读12分钟

文档流和盒模型

  • 盒模型一般分为content-box和border-box,具体结构如下图所示;

    image.png

    image.png

  • margin合并原则一般为:

    1. margin和margin之间没有border和padding才会合并;

    2. 子和父,子和子(兄弟),上下合并,左右不合并;

    3. inline-block元素的外边距不重叠,margin不合并,可用来消除兄弟元素的margin合并;

    4. 在父元素上加上overflow:hidden;可消除父子元素的margin合并;

    5. display:flex;样式下,父子元素的margin不合并;

  • 文档流的方向为从左到右(inline),从上到下(block),inline一直挤到行末才会换行,inline-block不会跨行也是从左到右,但不会跨行;元素的height和width计算原则为:

    1. inline元素width为内部inline子元素width之和,不能用width指定;inline元素的height由line-height间接确定,与height属性无关;

    2. block元素的width默认自动计算,也可以用width属性指定;block元素的height由内部所有的文档流元素决定,可以设置height;

    3. inline-block可以用width和height确定,没有设置width和height时,width默认按照inline元素的方式计算,height默认按照block的方式计算;

  • 脱离文档流的方法

    1. float

    当一个元素设置float后,会从文档流中脱离,其他元素会环绕float的元素。

    1. position:absolute/fixed

    具体见下面“关于定位”条目

  • 关于定位

positon:staic(默认)/absolute(绝对定位)/relative(相对定位)/sticky(粘滞定位)

position:absolute 让元素绝对定位,脱离文档流,定位基准为先祖元素中最近的position值不为staic的元素,如果找不到,则最终指向html元素;可配合z-index使用

position:fixed 让元素固定定位,定位基准通常为viewpoint。但有一些例外

position:relative 元素实际占位不变,变化的只有显示位置。一般用于做位移,以及做absolute定位的父元素

position:sticky 粘滞定位,尽量避免在手机端使用,有各种复杂的bug

层叠上下文

假定用户正面向(浏览器)视窗或网页,而 HTML 元素沿着其相对于用户的一条虚构的 z 轴排开,层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。

文档中的层叠上下文由满足以下任意一个条件的元素形成:

  • 文档根元素(<html>);

  • position值为 absolute或  relative且 z-index值不为auto的元素;

  • position值为fixed或sticky的元素;

  • z-index 的值不为auto的所有元素;

  • opacity属性值小于1的元素;

  • mix-blend-mode属性值不为normal的元素;

  • 以下任意属性值不为none的元素:

    • transform
    • filter
    • perspective
    • clip-path
    • mask/mask-image/mask-border
  • isolation属性值为isolate的元素;

  • -webkit-overflow-scrolling属性值为touch的元素;

  • will-change值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素;

  • contain属性值为layout、paint或包含它们其中之一的合成值(比如contain: strict、contain: content)的元素。

子级层叠上下文的z-index值只在父级中才有意义。子级层叠上下文被自动视为父级层叠上下文的一个独立单元。

层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。层叠上下文的层级是 HTML 元素层级的一个子级,因为只有某些元素才会创建层叠上下文。可以这样说,没有创建自己的层叠上下文的元素会被父层叠上下文同化。

层叠上下文和盒模型统一考虑,由近到远排序为:z-index值为正(由大到小)的元素→ z-index=0 → 内联子元素(包括文字等)→ 浮动元素 → 块级子元素 → border → background → z-index值为负的元素 → html;z-index值相同,优先度一致时,采用后来居上的原则,后面的覆盖前面的;

  • z-index的数值应注意管理,避免使用z-index=9999这种情况
  • z-index的值默认为auto,auto和0不同;

CSS布局

  • 布局原则
graph LR
    start[布局选择] --> conditionA{是否兼容IE9?}
    conditionA -- YES -->使用float布局
    conditionA -- NO --> conditionB{只兼容最新浏览器吗?}
    conditionB -- YES -->使用grid布局
    conditionB -- NO -->使用flex布局

float布局

在子元素上加上float和width,在父元素上加上.clearfix,即可实现float布局;

.clearfix的代码为:.clearfix ::{content:'';display:block;clear:both;}

子元素加上float后脱离文档流,不能被父元素包裹,加上.clearfix后,父元素可以重新包裹住子元素

布局要点:
    1. 留一些空间,或最后一个子元素不设置width,可以设置max-width
    1. 不需要做响应式,手机上基本没有IE,此布局为IE准备
    1. IE6/7存在双倍margin的bug,可将margin减半或加一条margin语句,例如margin-left:10px;margin-left:5px;其他浏览器会忽略后面的语句,IE6/7会用后面的语句覆盖前面的语句
    1. 如果图片下面有多余的线框,加上vertical-align:top/middle;
    1. 像素为最小单位,所以奇数和偶数像素无法设置完美对齐
    1. margin:0 auto;相比于margin-left:auto;margin-right:auto;可能会覆盖上下的margin,故后者更佳;
    1. block元素,如果拥有一个固定的width,那么可以通过margin-left:auto;margin-right:auto;设置居中;
    1. 做平均布局时,子元素往往不能和父元素理想嵌套,一般来说,最后一个子元素的margin会影响视觉效果,可以在子元素和父元素之间加一层div,为此div设置负margin,可以消除最后子元素的margin效果,同时又不影响外层父元素的宽度;
    1. 做布局时,通常在pc上选择定宽布局,在手机端选择不定宽布局

flex布局

.container+items,即可实现flex布局。.container的语句为.container { display:flex/inline-flex};,父元素加上container语句,即可成为flex容器。flex将对象作为弹性伸缩盒显示;inline-flex:将对象作为内联块级弹性伸缩盒显示;当Flex Box 容器没有设置宽度大小限制时,当display 指定为 flex 时,FlexBox 的宽度会填充父容器,当display指定为 inline-flex 时,FlexBox的宽度会包裹子Item;

container的属性:
  1. flex-direction,为flex内items的流动排列方式,默认值为row;可以取值:row/column/row-reverse/column-reverse;flexflow为弹性盒模型文档流,不同于normal-flow,通过flex-direction和flex-wrap设置流动方向;默认主轴为x轴,改变flex-direction后,会改变主轴方向;
  2. flex-wrap:wrap/nowrap,默认值为nowrap;
  3. justify-content,当弹性盒空间未完全利用时,设置主轴方向的空间分配方式。可以取值flex-start/flex-end/center/space-between/space-around/space-evenly;默认值为flex-start,item往start的方向挤;space-between为平均分配空间,item顶住盒子两边;space-around为空间平均分配给items,每个item左右两侧分配到相等的空间(不互相重叠);space-evenly为各个item之间的空间相等,但item不顶住盒子两边;
  4. align-items设置次轴对齐方式,可以取值flex-start/flex-end/center/strech/baseline;默认值为strech,未设置height时,向盒子次轴两端顶齐(items可能会被拉长);
  5. 当存在多行item,且container空间的height较高时,需要设置align-content属性,可以取值:flex-start/flex-end/center/strech/space-between/space-around/normal等;
item的属性:
  1. order,可改变item的次序,默认为0,从小到大排列,取值可以为负整数。
  2. flex-grow,不设置item的width时,item较多时,默认会尽量变窄。设置flex-grow属性,可以控制item的空间分配,取值为数值,负值无效,负值被当做0处理。在某些页面的header部分,可将logo:导航栏:用户头像设置为0:1:0,避免logo和用户头像缩放。
  3. flex-shrink,当盒子的空间变小,空间不足时,item会被挤窄,取值范围和flex-grow相同,默认值为1,数值越大,变窄时缩放越快;一般设置logo和用户头像的flex-shrink为0,防止被缩小。
  4. flex,以上几个item属性,可以用flex属性囊括,语句为flex:flex-grow的值 空格 flex-shrink的值 空格 flex-basis;设置flex-shrink时,需要同时设置flex-basis。
  5. align-self,会对齐当前 grid 或 flex 行中的元素,并覆盖已有的 lign-items的值。可以取值center/flex-start/flex-end;可用于为item单独设置位置。

布局要点: 一般不把flex的width和height固定,而是用max-width/min-width/max-height/min-height来确定;flex和margin-xxx:auto;结合使用;flex基本可以满足所有布局。

Grid布局

Grid类似于表格,相比于flex布局,Grid更适合于二维布局。让一个元素成为container的语句为.container{display:grid|inline-grid;}。可以将container划分为行和列,语句示例.container{display:grid;grid-template-column:40px 50px auto 50px 40px;grid-template-rows:25% 100% auto;}可将container分成三行五列;

item可设置范围,例如.item-a{grid-column-start:2;grid-column-end:5;grid-row-start:1;grid-row-end:3;}数值代表相应序号的划分线所在位置。

也可以通过fr划分container的空间,示例container{grid-template:1fr,50px,2fr,3fr;}

也可以直接把空间分割并命名,例如

{
 grid-template-areas:"header header header header"
                     "main mian . siderbar"
                     "footer footer footer footer"
}
/* 其中,'.' 代表空*/

grid-gap属性可以控制item之间的间隙。

浏览器渲染原理

  • 浏览器渲染页面的过程为:
    1. 根据HTML构造HTML树,即DOM
    2. 根据CSS构建CSS树,即CSSOM
    3. 将两者合并为一个渲染树,即render-tree
    4. Layout布局(根据文档流,盒模型等,计算大小,位置等)
    5. compose合成(根据层叠关系展示画面)
    6. paint绘制(把边框颜色,文字颜色,阴影等画出来)
  • 更新样式一般使用JS语句(例如div.style.background='red';div.style.diplay='none'div.classList.add('red'),div.remove()等),浏览器有三种实现途径:
    1. JS/CSS-->style-->layout-->paint-->compose 例如div.remove();
    2. JS/CSS-->style-->paint-->compose
    3. JS/CSS-->style-->compose

动画效果实现

transform实现动画

transform有四个常用功能:translate位移/scale缩放/rotate旋转/skew倾斜,一般都需要transition过渡;inline元素不支持transform;语法格式为:

  1. tansform:translateX|Y(<length-percentage>)
  2. tansform:tanslate(<length-percentage>,<length-percentage>?)两个维度X/Y,tanslate(-50%,50%)可用于做绝对定位元素的居中
  3. tansform:translateZ(<length>)且父容器perspective;两者搭配使用,父容器通过perspective设置“视点”
  4. tansform:translate3d(X,Y,Z)
  5. tansform:scale(1.6)缩放1.6倍,缩放时,对应的border也会变粗变细;transform:scale(X,Y?)可以缩放X,Y两个方向;
  6. rotate默认绕Z轴旋转,即rotateZ(),同时,可以设置rotateX(),rotateY()等;语句为:transform:rotate([<angle>|<zero>]);,tansform:rotateX|Y|Z([<angle>|<zero]);tansform:rotate3d();可用于制作loading的加载动画
  7. tansform:skewX|Y(±15deg)倾斜
  8. tansform:scale(1.3) rotate(45deg);可加多个效果 9.tansform:none;取消所有效果

transition用于过渡,补充中间帧。示例语句:transition:left(属性名) 150ms(时长) liner(过渡方式) 110ms(延迟);,可以用逗号分隔不同属性transition:left 200ms,top 220ms;,可以用all代表所有属性transition:all 440ms;。不是所有的属性都能过渡,比如display:none-->block无法过渡,一般用visiility:hidden-->visible实现;背景色background也可以过渡;一般transition配合setTimeout()+div.remove()使用。

如果要实现中间过渡动画效果,有两种方式:

  1. 使用两次tansform,用setTimeout()或监听transitioned事件,确认是否到达中间状态。 2.使用animation

animation实现动画

animation:时长|过渡方式|延迟|次数|方向|填充样式|是否暂停|动画名

使用示例如下

在html构造一个<div id="demo"></div><button id="button">开始</button>

在JS添加一个动作button.onclick=()=>{demo.classList.add('start')};

在CSS添加动画

#demo.start{animation:xxx 1.5s};

@keyframes xxx{
0% {transform:none;}
35% {transform:tanslateX(200px);}
100% {transform:tanslateX(200px) tanslateY(200px);}
};

points & skills

  • caniuse.com可用来查看浏览器对css样式的支持

  • css的注释只有一种,即/* */

  • css的所有字符和语言都是英文字符

  • w3c css验证器可检验css代码错误

  • border调试法可用来检查并定位css语句的错误、

  • css的常见语法错误,基本都是低级错误,有:

    1. 拼写错误

    2. 符号错误(没加花括号)

    3. 没写分号

    4. 使用中文符号(冒号)

    5. 没加单位

  • CSS的资料查阅:

    1. 关键词+MDN,google

    2. CSS tricks

    3. 张鑫旭的博客

  • 在支持emmet的编辑器中,输入.xxx 按下tab或者回车,会自动转化为<div class="xxx"><div>;同时写n个元素的快捷输入方式: span {第$个元素}*n 然后按下tab或回车;

  • 元素不必区分block元素或者inline元素,不同浏览器的支持效果不同,通过设置display:block/inline 可以决定元素为block或inline

  • block元素默认宽度为auto而非100%

  • 不要在inline元素中包含block元素,样式问题很大

  • 一些布局中,border的宽度可能会干扰布局的宽度,可以将border换成outline,outline不占宽度

  • 写css样式前,应手动清除浏览器的默认样式,避免浏览器默认样式对布局样式的干扰。常用语句有:*{margin:0;padding:0;box-sizing:border-box;}ul,ol{list-style:none;}

  • 调试属性的数值时,可以按住ALT+↑/↓

  • CSS性能分析的一个工具,在chrome开发者工具的任意一个页面,按下ESC,在弹出窗口点击┆,然后进入RENDING,勾选paint flashing即可

  • 调试CSS动画时,选中元素,按↑/↓或shift + ↑/↓,可查看动画效果

  • 通过设置border-radius:50;可以画圆

  • 为body元素设置背景色后,body元素以外的部分颜色也会改变,此为浏览器自动填充背景色

  • 文字不准换行 white-space:nowrap;