【前端基础】 CSS

661 阅读11分钟

盒模型

首先我们可以把每个 dom 元素都理解成为一个盒子,而每个盒子都有一些组成元素,这个就叫做盒模型

我们知道盒子有这几个要素:margin / border / padding / content

盒模型可以分为两类:IE 盒模型和 W3C 标准盒模型

  • W3C 盒模型 —— 盒子的 width/height 只包括 content 部分,不包括 border 和 padding
  • IE 盒模型 —— 盒子的 width/height 包含 content+border+padding

在 ie8+ 的浏览器上是用什么盒模型可以用 box-sizing 属性控制,默认值是 content-box,即为标准盒模型, 如果把 box-sizing 设置为 border-box 则使用的是 IE 盒子模型。

在 iE6/7/8 的版本中如果缺失 DOCTYPE 就会触发 IE 盒子模型。其他情况我们可以使用 box-sizing 来指定盒子模型自由切换。

1px 问题产生的原因

设计稿给出的像素是物理像素,手机设备的像素是虚拟CSS像素,而每个设备都有它的 drp(物理像素比)

DRP:物理像素比,描述的是网页未缩放状态下,物理像素与 CSS 像素的初始比例关系,换算关系如下所示:

DPR = 设备像素 / CSS 像素

所以,不同的设备有不同的 dpr,我们可以得出如下的结论:

  • DPR=1 时,我们设 1dpi 在 1 倍屏中真实展示 x 个 pt,根据刚刚的公式,我们可以得出,1dpi = 1px = x/1 即 x = 1。
  • DPR=2 时,我们设 1dpi 在 2 倍屏中真实展示 x 个 pt,我们可以得出,1dpi = 1px = x/2 即 x = 2,所以 1dip 显示 2个pt。这样造成的问题是我们实际制作出的页面会比设计稿大一倍。

1px 问题解决方式

解决方式有如下几种:

background-image && boder-image

.background-image-1px {
  background: url(...) no-repeat left bottom;
  -webkit-background-size: 100% 1px;
  background-size: 100% 1px;
}

.border-bottom-1px {
  border-width: 0 0 1px 0;
  -webkit-border-image: url(...) 0 0 2 0 stretch;
  border-image: url(...) 0 0 2 0 stretch;
}

缺点:如果需要更改边框的颜色,那就要重新切图,并且可能会出现圆角模糊锯齿化的情况。

border-shadow

通过 css 对 border-shadow 的处理来模拟 0.5px

.box-shadow-1px {
  box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}

优点:代码少,还能换颜色 缺点:阴影会导致颜色变浅,而且仔细看很明显能看出是阴影 不是边框。

伪元素 + scale 缩放

这是对比前面的两种方式后的一种比较好的方式,并且 ant-design-mobile 也是使用的这种方式

我们可以先在 less 的变量控制文件中写好方法,然后在具体的页面中调用 less 方法:

@border-color-base : #EBEDF0;
// 伪元素的位置控制
.scale-hairline-common(@color, @top, @right, @bottom, @left) {
  content: '';
  position: absolute;
  background-color: @color;
  display: block;
  z-index: 1;
  top: @top;
  right: @right;
  bottom: @bottom;
  left: @left;
}

//上边框
.hairline(@direction, @color: @border-color-base) when (@direction = 'top') {
  border-top: 1PX solid @color;

    @media (min-resolution: 2dppx) {
      border-top: none;

      &::before {
        .scale-hairline-common(@color, 0, auto, auto, 0);
        width: 100%;
        height: 1PX;
        transform-origin: 50% 50%;
        transform: scaleY(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleY(0.33);
        }
      }
    }
}

// 右边框
.hairline(@direction, @color: @border-color-base) when (@direction = 'right') {
  border-right: 1PX solid @color;

    @media (min-resolution: 2dppx) {
      border-right: none;

      &::after {
        .scale-hairline-common(@color, 0, 0, auto, auto);
        width: 1PX;
        height: 100%;
        background: @color;
        transform-origin: 100% 50%;
        transform: scaleX(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleX(0.33);
        }
      }
    }
}

// 下边框
.hairline(@direction, @color: @border-color-base) when (@direction = 'bottom') {
  border-bottom: 1PX solid @color;

    @media (min-resolution: 2dppx) {
      border-bottom: none;
      &::after {
        .scale-hairline-common(@color, auto, auto, 0, 0);
        width: 100%;
        height: 1PX;
        transform-origin: 50% 100%;
        transform: scaleY(0.5);
        @media (min-resolution: 3dppx) {
          transform: scaleY(0.33);
        }
      }
    }
}

// 左边框
.hairline(@direction, @color: @border-color-base) when (@direction = 'left') {
  border-left: 1PX solid @color;

    @media (min-resolution: 2dppx) {
      border-left: none;

      &::before {
        .scale-hairline-common(@color, 0, auto, auto, 0);
        width: 1PX;
        height: 100%;
        transform-origin: 100% 50%;
        transform: scaleX(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleX(0.33);
        }
      }
    }
}

// 全边框
.hairline(@direction, @color: @border-color-base, @radius: 0) when (@direction = 'all') {
  border: 1PX solid @color;
  border-radius: @radius;

    @media (min-resolution: 2dppx) {
      position: relative;
      border: none;

      &::before {
        content: '';
        position: absolute;
        left: 0;
        top: 0;
        width: 200%;
        height: 200%;
        border: 1PX solid @color;
        border-radius: @radius * 2;
        transform-origin: 0 0;
        transform: scale(0.5);
        box-sizing: border-box;
        pointer-events: none;
      }
    }
}

在具体的页面中调用:

.div1{
    .hairline('top',#eeeeee)
    .hairline('right')
    .hairline('left',#cccccc)
}
.div2{
    .hairline('all',#bbbbbb,3px)
}

优点:使用 less 将 css 接口化,功能灵活,复用性和兼容性较好,通过媒体查询适配了 2 倍屏和 3 倍屏。该代码写在公共 css 样式中即可。 缺点:代码仍然有继续抽象的空间,并且此方案是使用 positon:absolute 进行定位,所以父元素也必须满足绝对定位的触发条件。

viewport + rem

通过设置对应 viewport 的 rem 基准值:

在设备的 dpr=2 时,设置 meta:

<meta name="viewport" content="width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

在设备的 dpr=3 时,设置 meta:

<meta name="viewport" content="width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">

块级元素 / 内联元素 / 替换元素 / 非替换元素

  • 块级元素 —— 在浏览器显示时独占一行,默认情况下其宽度自动填满其父元素宽度,可设置 width/height/margin/padding 等属性,对应 display:block。
  • 行内元素 —— 也称内联元素,相邻的行内元素会排列在同一行里,直到一行排不下,才会换行,其宽度随元素的内容而变化,设置 width/height 属性无效,边距属性的只有margin-left、margin-right、padding-left、padding-right,其它属性不会起边距效果。对应 display:inline。
  • 替换元素 —— 浏览器根据元素的标签和属性,来决定元素的具体显示内容。替换元素一般有内在尺寸,所以具有 width/height 属性。常见的替换元素有 html 中的 <img> <input> <textarea> <select> <object>。比如:<input> 标签是根据type属性来决定是显示输入框,还是提交按钮等等。
  • 非替换元素 —— html 的大多数元素是不可替换元素,即其内容直接表现给用户端。

inline-block、inline 和 block 的区别

block

block 元素独占一行,多个 block 元素会各自新起一行。默认情况下,block 元素宽度自动填满其父元素宽度。
block 元素可以设置 width/height 属性。块级元素即使设置了宽度,仍然是独占一行。
block 元素可以设置 margin/padding 属性。

inline

inline 元素不会独占一行,多个相邻的行内元素会排列在同一行里,直到一行排列不下,才会新换一行,其宽度随元素的内容而变化。
inline 元素设置 width/height 属性无效。
inline 元素的 margin/padding 属性,水平方向的 padding-left, padding-right, margin-left, margin-right 都产生边距效果;但竖直方向的 padding-top, padding-bottom, margin-top, margin-bottom 不会产生边距效果。

inline-block

简单来说就是将对象呈现为 inline 对象,但是对象的内容作为 block 对象呈现。
之后的内联对象会被排列在同一行内。
比如我们可以给一个 link(a元素)inline-block 属性值,使其既具有 block 的宽度高度特性又具有 inline 的同行特性。

rem 和 em 和 vw 的区别

首先我们知道 px 是物理屏幕上最小的能显示出来的一个点

rem —— 元素相对于 html 根元素的字体大小

em —— 元素相对于父元素的字体大小

vw/vh —— 相对于屏幕的视图的高度和宽度,比如1vh 等于 100% 的视口高度

BFC

定义:块级格式化上下文,它是一个独立的渲染区域,规定了内部 Block-level Box 如何布局,并且与这个区域的外部毫不相关

创建了 BFC的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素(里面怎么布局都不会影响外部),BFC仍属于文档中的普通流

如何产生 BFC:display 属性为 block, list-item ,table 的元素,会产生 BFC。

作用

  • 防止外边距重叠 - 在普通文档流中,元素(非BFC元素)的外边距margin会自动折叠,产生如下现象。

这个是 html 的特性不算 bug,但是我们更希望 margin 不产生折叠效果,通过利用 BFC 元素之间的外边距不会折叠的特性来实现。

  • 清除浮动的影响 - BFC会包含创建它的元素内部的所有内容(包含浮动元素)
  • 防止文字环绕(实现左图右文布局) - 利用浮动元产生BFC以及BFC之间不会互相覆盖实现左图右文布局

如何产生 BFC

这里可以总结称一句话:凡脱离文档流都可以产生 BFC

IFC / FFC / GFC

IFC

Inline Formatting Contexts - 内联格式化上下文

表现形式是:行级盒子在包含块里是从左到右水平排列的,上下文不单会决定盒子内的规则 也会决定自身的特性

FFC

Flex formatting contexts - 弹性盒模型

GFC

GrideLayout formatting contexts - 网格布局格式化上下文

Sass / Less / Stylus

层叠上下文 / z-index

层叠上下文

HTML 中三维的概念,每个盒模型中的位置是三维的,分别是平面画布上的 X 轴,Y 轴以及代表层叠的 Z 轴,通常元素都是沿着 X Y 轴平铺,一旦元素发生堆叠,就会发生某个元素盖着另外一个元素或者被覆盖。

层叠顺序

为什么定位元素会层叠在普通元素的上面

元素一旦成为定位元素,其 z-index 就会自动生效,此时 z-index: auto 也就是0级别, 根据上面的层叠顺序表,就会覆盖 inline 或 block 或 float 元素。 而不支持 z-index 的层叠上下文元素天然 z-index:auto 级别,层叠上下文元素和定位元素是一个层叠顺序的,于是当他们发生层叠的时候,遵循的是“后来居上”准则

position

基础

| 属性 | 解析 | 相对元素 | z-index 是否生效 | |------|------------|------------| | static | 默认值,遵循标准文档流中,top/right/bottom/left 等属性失效。 | - | 无效 | | absolute | 绝对定位,对象脱离标准文档流,依赖 top/right/bottom/left 等属性 | 相对于static 定位以外的第一个父元素进行绝对定位,如果采用absolute的元素直接父容器position值为static,那么则会查询更上一层的父容器的position值,直到<body>标签。 |有效 | | relative | 相对定位,对象遵循标准文档流中,依赖 top/right/bottom/left 等属性,但是这些属性并不会改变该对象原本在文档流中的占位空间 |相对于该对象在标准文档流中的位置进行偏移 | 有效 | | fixed | 固定定位,对象脱离标准文档流,依赖 top/right/bottom/left 等属性 | 相对于浏览器窗口进行绝对定位 | 有效 | | sticky | 粘性定位,可以简单理解为 relative 和 fixed 布局的混合。 | - |

sticky

粘性定位,可以简单理解为 relative 和 fixed 布局的混合。

在了解粘性定位之前,我们需要知道以下的两个概念:

  • 流盒 - 指的是粘性定位元素最近的可滚动元素(overflow 属性值不是 visible 的元素)的尺寸盒子,如果没有可滚动元素,则表示浏览器视窗盒子。
  • 粘性约束矩形 - 即粘性布局元素的父级元素矩形

特点:

  • 当粘性约束矩形在可视范围内为 relative,反之,则为 fixed
  • 粘性定位元素如果和它的父元素一样高,则垂直滚动的时候,粘性定位效果是不会出现的
  • 它的定位效果完全受限于父级元素们。如果父元素的 overflow 属性设置了 scroll,auto,overlay 值,那么,粘性定位将会失效
  • 同一容器中多个粘贴定位元素独立偏移,因此可能重叠;位置上下靠在一起的不同容器中的粘贴定位元素则会鸠占鹊巢,挤开原来的元素,形成依次占位的效果。

float 原理

浮动出现的意义其实只是用来让文字环绕图片而已,仅此而已

float 的本质是带有方位的 display:inline-block 属性,display:inline-block 某种意义上的作用就是包裹 (wrap),float 无法等同于 display:inline-block,其中原因之一就是浮动 的方向 性,display:inline-block 仅仅一个水平排列方向,就是从左往右,而 float 可以从右往左排列, 这就是两者的差异。

清除浮动

  1. 给需要清除浮动的元素增加 clear 属性
  2. 浮动元素的父级增加 :after 伪元素
  3. 父元素增加 overflow 属性(BFC)