CSS布局、定位和动画

479 阅读12分钟

一. CSS 布局

布局就是把页面分成一块一块,比如按左中右、上中下排列。

  • 固定宽度布局,一般宽度为960 / 1000 / 1024 px
  • 不固定宽度布局(主要在手机上用),主要靠文档流的原理来布局(文档流本来就是自适应的,不需要加额外的样式)
  • 响应式布局,在PC上固定宽度,手机上不固定宽度,即混合布局 布局的两种思路
  • 从大到小: 先定大局,再完善每个部分小布局
  • 从小到大: 先完成小布局,然后组成大布局

1. 「float布局」

兼容IE9,手机页面不用float

步骤

1). 在子元素上加 float: left; 和 width
2). 在父元素加上 .clearfix

.clearfix::after {     /* 两个冒号一个冒号都可以 */
  content: '';
  display: block;
  clear: both;
}

实践

  • 用float做两栏布局(如顶部条)
  • 用float做三栏布局(如内容区)
  • 用float做四栏布局(如导航)
  • 用float做平均布局(如产品展示区) 加上头尾,即可满足所有PC页面需求。

代码展示

<!-- 在header用float做两栏布局顶部条logo和nav -->
  <header class="clearfix">
    <div class="logo">
      <img src="https://static.xiedaimala.com/xdml/cdn/assets/black-logo-6b90d5f6165754f30be3d8469256bc824371ae8deaefc286127fb7701b7b8dc5.png" alt="">
    </div>
    <!-- 用float做四栏布局 (导航) -->
    <ul class="clearfix nav">
      <li>首页</li>
      <li>课程</li>
      <li>优惠</li>
      <li>关于</li>
    </ul>
  </header>

  <!-- 内容区  用float做三栏布局 -->
  <div class="content clearfix">
    <!-- 边栏 -->
    <aside>一行有6个字</aside>
    <!-- 主要内容 -->
    <main></main>
    <!-- 广告 -->
    <div class="ad"></div>
  </div>
  
  <!-- 用float做平均布局 如产品展示区 -->
  <div class="imageList">
    <div class="x clearfix">
      <div class="image"></div>
      <div class="image"></div>
      <div class="image"></div>
      <div class="image"></div>
    </div>
  </div>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
ul,
ol {
  /* 删除列表原点 */
  list-style: none; 
}
img {
  max-width: 100%;
}
.clearfix:after {
  content: '';
  display: block;
  clear: both;
}

.logo {
  background: white;
  display: inline-block;
  float: left;
  margin-top: 3px;
  margin-left: 10px;
}
.logo > img {
  height: 26px;
  /* 去掉图片下面多余的部分,top或middle都可以*/
  vertical-align: top;
}
.nav {
  float: right;
  margin-left: 20px;
}
ul > li {
  float: left;
  /* 先上下边距再左右边距 */
  padding: 4px 0.5em;
 /*  如果高度是基数无法对齐,可以加下面这句改变高度 */
  /* line-height: 32px; */
}
ul {
  /* inline-block尽量压窄自己,block尽量放宽自己 */
  display: inline-block;
}
header {
  background: grey;
  color: white;
}


.content {
  /* 有时候bordr会干扰宽度,用outline调试 */
  outline: 1px solid red;
  width: 800px;
  margin-top: 10px;
  /* 让内容区居中用下面两句:只对块元素有用,并且宽度是固定的 */
  margin-left: auto;
  margin-right: auto;

}
.content > aside {
  width: 200px;
  background: green;
  /* 平常不要给高度,高度应该由里面的内容撑起来 */
  height: 300px;  
  float: left;
}
.content > main {
  background: yellow;
  height: 300px;
  width: 500px;
  float: left;
}
.content > .ad {
  background: black;
  height: 300px;
  width: 100px;
  float: left;  
}


.imageList {
  outline: 1px solid green;
  width: 800px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 10px;
  
}
.imageList > .x > .image {
  width: 191px;
  height: 191px;
  background: black;
  border: 1px solid blue;
  float: left;
  margin-bottom: 10px;
  margin-right: 12px; 
}
.imageList > .x {
  margin-right: -12px
}

代码效果图

经验

i. 一般最后一个子元素不设置宽度width(或者写一个max-width ∵定宽)
ii. float布局不需要做响应式,因为手机上没有IE,而这个布局是专门为IE准备的
iii. 平均布局需要用到负margin★

float布局需要手动计算宽度,不灵活,所以可以用flex布局

2. 「flex布局」

父元素container,子元素items

重点记住这些代码

.container {
  display: flex;    /* 让一个元素变成flex容器 */
  flex-direction: row/column; /* 改变items流动方向 */
  flex-wrap: wrap;            /* 改变折行 */
                              /* flex-flow: row wrap; 二者可以缩写*/
  justify-content: center/space-between;    /* 控制x轴对齐方式(当默认主轴是横轴时) */
  align-items: center;                      /* 控制y轴对齐方式(当默认主轴是横轴时) */
}  

实践

  • 用flex做两栏布局(如顶部条)
  • 用flex做三栏布局(如内容区)
  • 用flex做四栏布局(如导航)
  • 用flex做平均布局(如产品展示区) 和float同样的效果代码会少很多,预览地址js.jirengu.com/sufip/2/edi…

经验

i. 想让导航栏去到右边有两种写法: 在父元素上设置justify-content: space-between;或者在导航栏上写margin-left: auto;
ii. 和float一样,平均布局需要用到负margin★,使用justify-content:space-between无法满足要求
iii. 永远不要把width和height写死,除非特殊说明;用min-width/max-width/min-height/max-height
iv. flex和margin-xxx: auto; 配合有意外效果;flex基本可以满足所有需求

3. 「grid布局」

兼容最新浏览器,手机页面用
也分container和item

步骤

  1. 用grid-template-areas 设计大致的布局
  2. 用grid-template-rows和grid-template-columns指定每一行每一列的高度和宽度
<div class="container">
  <header>header</header>
  <aside>aside</aside>
  <main>main</main>
  <div class="ad">ad</div>
  <footer>footer</footer>
</div>
.container {
  min-height: 100vh;
  display: grid;
  grid-template-rows: 60px auto 60px;
  grid-template-columns: 100px auto 100px;
  /* grid-gap: 10px; 左右上下都有空隙*/
  grid-row-gap: 10px;
  grid-template-areas:
    "header header header"
    "aside main ad"
    "footer footer footer";
}
  1. 对于每一个小块,用grid-area和grid-template-areas 里布局的字符串对应
.container > header{
  grid-area: header;
}
.container > aside{
  grid-area: aside;
}
.container > main{
  grid-area: main;
}
.container > .ad{
  grid-area: ad;
}
.container > footer{
  grid-area: footer;
}

效果图

grid尤其适合不规则布局

示例代码地址

二. CSS 定位

CSS 有两个最重要的基本属性:display 和 position。
display属性指定网页的布局。position属性指定网页的定位。
布局是屏幕平面的,定位是垂直于屏幕的。

1. position属性

static

static 是 position 属性的默认值。如果省略 position 属性,浏览器就认为该元素是 static 定位。 该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。

relative

relative 表示,相对于默认位置(即 static 时的位置)进行偏移,即定位基点是元素的默认位置。 升起来,但不脱离文档流。它必须搭配 top、bottom、left、right 这四个属性一起使用,用来指定偏移的方向和距离 (很少用)。给absolute元素做父元素 (常用)

配合z-index创建层叠上下文(不为auto)

位移示例(很少用)

<div class="container">
    <div class="demo"></div>
    <div class="demo2"></div>
  </div>
.container {
  border: 1px solid red;
  height: 300px;
}
.demo {
  border: 1px solid green;
  width: 50px;
  height: 50px;
  position: relative;
  top: 10px;
  left: 20px;
}
.demo2 {
  background: black;
  width: 50px;
  height: 50px;
}
你站的位置不变,只是显示和原来有一些偏移

和absolute结合使用(常用)(示例在下方)

absolute

absolute 表示,相对于祖先元素中最近的一个定位元素(非static)进行偏移,否则定位基点就会变成整个网页的根元素html。要写上top 、left属性值。 某些浏览器不写top/left会位置错乱。

  • 使用场景:脱离原来的位置,另起一层,如对话框的关闭按钮;鼠标提示
  • 配合z-index
  • 善用left:100%;
  • 善用left:50%;加负margin(居中)

关闭按钮示例

<div class="container">
    <span class="close">X</span>
</div>
* {box-sizing: border-box;}
/* 父元素 加relative配合使用 */
.container {
  border: 1px solid red;
  height: 300px;
  position: relative;
}
/* 子元素 加absolute*/
.close {
  border: 1px solid black;
  position: absolute;
  top: 0;
  right: 0;
  padding: 0 8px;
  background: blue;
  color: white;  
}

鼠标提示示例

<button>点击
    <span class="tips">提示内容</span>
</button>
button {
  position: relative;
}
button span {
  position: absolute;
  border: 1px solid red;
  /* 文字内容不准换行 */
  white-space: nowrap;
  /* 放在最上面要反向思考 */
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%)
}
/* 提示内容默认看不见,悬浮时出现 */
button span {
  display: none;
}
button:hover span {
  display: inline-block;
}

fixed

fixed 表示,相对于视口(viewport,浏览器窗口)进行偏移,即定位基点是浏览器窗口。这会导致元素的位置不随页面滚动而变化,好像固定在网页上一样。元素的位置通过 left、top、right、bottom属性进行规定。

  • 使用场景:烦人的广告;回到顶部按钮
  • 配合z-index
  • 当祖先元素具有transform属性且不为none时,就会相对于祖先元素指定坐标,而不是适口。(失效)
  • 手机上不要使用这个属性(坑多)

示例

<div class="fixed"></div>
    <p>1</p>
    <p>2</p>
    <p>3</p>
    <p>4</p>
    <p>5</p>
    <p>6</p>     <!-- 有100个p,未全部显示 -->
.fixed {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 100px;
  border: 1px solid green;
  width: 100px;
  height: 100px;
}
.fixed {
  position: fixed;
  left: 10px;
  bottom: 10px;
  background: green;
}
无论怎么滚动页面,三角标志始终在左下方位置固定

sticky

能够形成"动态固定"的效果,比如表格滚动的时候,表头始终固定。(兼容性很差)

  <div class="container">
    <div class="sticky"></div>
    <p>1</p>
    <p>2</p>
    <p>3</p> <!-- 有100个p,未全部显示 -->
.sticky {
  border: 1px solid green;
  background: green;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

滚动的时候表头始终固定

2. z-index

取值

z-index的默认值是auto, 不建立新的层叠上下文

z-index取整数(正、负、0)时,有两个作用:
① 在当前元素建立一个层叠上下文,即告诉浏览器这里出现了堆叠,需要考虑分层了。
② 告诉浏览器当前元素在这个层叠上下文中所占的位置

使用

只有position为relative/absolute/fixed的元素,z-index属性才起作用。注意,是该元素本身。 z-index遵循从父原则,即如果父元素和子元素同时设置了z-index,以父元素的z-index为准。
-1,0,1,2足够
负z-index逃不出层叠上下文

3. 层叠上下文

不同的 DOM 元素组合在一起发生重叠的时候,它们的的显示顺序会遵循层叠水平的规则,而 z-index 是用来调整某个元素显示顺序,使该元素能够上浮下沉。

规则

当两个元素层叠水平相同的时候,这时候就要遵循下面两个准则:

  1. 后来居上原则
  2. 谁 z-index 大,谁在上的准则(同一个层叠上下文中)

当两个元素在不同的层叠上下文中时候:

  1. 先找到共同的祖先层叠上下文,然后比较共同层叠上下文下这个两个元素所在的局部层叠上下文的层叠水平
  2. 处在层叠上下文中的元素和处在这个上下文外的元素无关(z-index无法比较)
  3. 处在同一个层叠上下文中的元素的z-index才能比较

可以创建层叠上下文的属性

  1. z-index值不为auto的绝对/相对定位
  2. position: fixed;
  3. flex
  4. opacity
  5. transfrom 详见MDN文档

三. CSS 动画

每个静止的画面都称作帧,将这些帧以一定的速度进行播放,我们的肉眼因视觉残象产生错觉而误以为是活动的画面,形成动画效果。一般影视播放需要24帧/s,游戏需要60帧/s。

1. 浏览器渲染原理

浏览器渲染过程

① 根据 HTML 构建 HTML 树 (DOM)
② 根据 CSS 构建 CSS 树 (CSSOM)
③ 将两棵树合并成一颗渲染树 (Render Tree)
④ Layout布局 (文档流、盒模型、计算大小和位置)
⑤ Paint绘制 (把边框颜色、文字颜色、阴影等画出来)
⑥ Composite合成 (根据层叠关系展示画面)

如何更新样式

一般用JS更新样式

  • 比如div.style.background='red'
  • 比如div.style.dispaly='none'
  • 比如div.classList.add('red')
  • 比如div.remove()直接删掉节点 这些方法不同处见下方

三种不同的渲染方式

  • 第一种,全走,如:div.remove() 会触发当前消失,其他元素全部重新渲染
  • 第二种,跳过layout,如:改变背景颜色,直接 repaint 和 composite
  • 第三种,跳过layout和paint,如:改变transform ,只需 composite (布局颜色都没变) 可以通过CSS Triggers网站,查看每个属性触发哪一种流程

CSS 动画优化

答案都在Google写的文章里,背下来,比如
① 不要用left 用 transform
② JS优化: 使用 repuestAnimationFrame 代替 setTimeout 或 setlnterval
③ css 优化: 使用 will-change 或 translate

2. transform 全解

属性值(四个常用功能)注释
transformtranslate位移,tanslateX(50%)表示回x方向自身宽度的50%
同上scale缩放,用得少,因为会变形变模糊
同上rotate旋转,默认以z轴(垂直于屏幕的轴)转动,一般用于制作loading
同上skew倾斜,用得少

上述功能可以组合使用

注意: 这些功能一般需要配合 transition 过渡;inline 元素不支持 transform,需要先变成 block

/* 以下三行表示绝对居中 */
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

第一个跳动的心示例

  <div id="heart">
    <div class="left"></div>
    <div class="right"></div>
    <div class="bottom"></div>
  </div>
#heart {
  margin: 200px;
  position: relative;
  display: inline-block;
  /* 过渡时长为0.5s */
  transition: all .5s;
}
#heart:hover {
  /* 悬浮时扩大1.5倍 */
  transform: scale(1.5);
} 
#heart > .left {
  background: red;
  width: 50px;
  height: 50px;
  position: absolute;
  bottom: 100%;
  right: 100%;
  /* 旋转45度 X轴方向移动36像素 */
  transform: rotate(45deg) translateX(36px);
  /* 将正方形变成圆形 */
  border-radius: 50% 0 0 50%;
}
#heart > .right {
  background: red;
  width: 50px;
  height: 50px;
  position: absolute;
  bottom: 100%;
  left: 100%;
  transform: rotate(45deg) translateY(36px);
  border-radius: 50% 50% 0 0;
}
#heart > .bottom {
  background: red;
  width: 50px;
  height: 50px;
  transform: rotate(45deg);
}

动态效果链接

3. CSS动画的两种做法(transition 和 animation)

transition (过渡)

作用

补充中间帧

语法

  • transition: 属性名 时长 过渡方式 延迟
  • transition: left 200ms linear
  • transition: left 200ms, top 400ms 可以用逗号分隔两个不同的属性
  • transition: all 200ms 可以用 all 代表所有属性
  • 过渡方式有:linear | ease | ease-in | ease-out | ease-in-out | cubic-bezier | step-start | step-end | steps (凭感觉选)

注意:并不是所有属性都能过渡
display: block ⟹ none 没法过渡
一般改成 visibility: visible ⟹ hidden (不要用opacity: 1 ⟹ 0
② 背景颜色background也可以过渡

过渡必须要有起始

比如 hover 和 非 hover 就是两次动画

如果有中间点,可以通过下列两种方法解决

  • 使用两次transform:.a === transform ===> .b 再从.b === transform ===> .c,用setTimeout 或者监听transitionend 事件

  • 使用animation:声明关键帧, 添加动画。

animation (更高级的过渡)

关键帧 @keyframes 语法

@keyframes xxx{
    0%{
        transform: none;
    }
    66.66%{
        transform: translateX(200px);
    }
    100%{
        transform: translateX(200px) translateY(100px);
    }
}

animation 语法

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

  • 时长:1s 或 1000ms
  • 过渡方式:同transition
  • 次数:10 / infinite(无限次)
  • 方向:reverse | alternate(交替)| alternate-reverse
  • 填充模式:none | forwards | backwards | both
  • 是否暂停:paused | running
  • 以上所有属性都有对应的单独属性

第二个跳动的心示例

  <div id="heart">
    <div class="left"></div>
    <div class="right"></div>
    <div class="bottom"></div>
  </div>
#heart {
  margin: 200px;
  position: relative;
  display: inline-block;
  animation: heart 666ms infinite alternate
}
@keyframes heart {
  0% {
    transform: scale(1.0);
  }
  100% {
    transform: scale(1.5);
  }
}
#heart > .left {
  background: red;
  width: 50px;
  height: 50px;
  position: absolute;
  bottom: 100%;
  right: 100%;
  transform: rotate(45deg) translateX(36px);
  border-radius: 50% 0 0 50%;
}
#heart > .right {
  background: red;
  width: 50px;
  height: 50px;
  position: absolute;
  bottom: 100%;
  left: 100%;
  transform: rotate(45deg) translateY(36px);
  border-radius: 50% 50% 0 0;
}
#heart > .bottom {
  background: red;
  width: 50px;
  height: 50px;
  transform: rotate(45deg);
  border-radius: 0 0 10% 0;
}

动态效果链接

其他

CSS是艺术!