博客列表 >Flex布局知识及实战案例演示

Flex布局知识及实战案例演示

Dong.
Dong.原创
2020年06月24日 16:58:04692浏览

基于浮动,绝对定位方式的二列布局

1.基于浮动的二列布局

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>基于浮动的二列布局</title>
  7. </head>
  8. <style>
  9. /* 给予背景 */
  10. header,
  11. footer ,
  12. aside,
  13. main {
  14. background-color: rgb(207, 255, 205);
  15. }
  16. /* 设置主体内容区最小高度 */
  17. aside,
  18. main {
  19. min-height: 700px;
  20. }
  21. /* 设置侧边宽度,向左浮动 */
  22. aside {
  23. width: 200px;
  24. float: left;
  25. }
  26. /* 设置内容区宽度,向右浮动 */
  27. main {
  28. width: 790px;
  29. float: right;
  30. }
  31. /* 设置页脚页眉宽度 */
  32. header,
  33. footer {
  34. height: 50px;
  35. }
  36. /* 浮动布局,宽度设置1000 */
  37. .wrap {
  38. width: 1000px;
  39. /* 设置1像素边框及边框颜色 */
  40. border: 1px solid #000;
  41. /*设置overflow属性 解决高度塌陷 */
  42. overflow: hidden;
  43. /* 上下10像素,左右居中 */
  44. margin: 10px auto;
  45. </style>
  46. <body>
  47. <header>页眉</header>
  48. <div class="wrap">
  49. <aside>侧边</aside>
  50. <main>主体</main>
  51. </div>
  52. <footer>慧城科技 | 备案号:*********</footer>
  53. </body>
  54. </html>

浏览器显示效果:

2.基于绝对定位的二列布局

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>基于绝对定位实现二列布局</title>
  7. </head>
  8. <style>
  9. /* 设置块级元素的背景色 */
  10. header,aside,main,footer {
  11. background-color: aliceblue;
  12. }
  13. /* 设置页眉页脚的高度 */
  14. header,footer {
  15. height: 50px;;
  16. }
  17. /* text-align水平对齐居中方式 */
  18. footer {
  19. text-align: center;
  20. line-height:50px;
  21. }
  22. /* 设置主题区的最小高度 */
  23. aside,main {
  24. min-height: 700px;
  25. }
  26. .wrap {
  27. width: 1000px;
  28. border: 1px solid black;
  29. min-height: 700px;
  30. margin: 10px auto;
  31. /* 转为父级元素(定位父级) */
  32. position: relative;
  33. }
  34. aside {
  35. width: 200px;
  36. min-height: inherit;
  37. /* 绝对定位 */
  38. position: absolute;
  39. /* 可以省略 */
  40. top: 0;
  41. left: 0;
  42. }
  43. main {
  44. width: 790px;
  45. min-height: inherit;
  46. /* 绝对定位 */
  47. position: absolute;
  48. /* 可以省略 只留right就好*/
  49. bottom: 0;
  50. right: 0;
  51. }
  52. </style>
  53. <body>
  54. <header>页眉</header>
  55. <div class="wrap">
  56. <aside>侧边栏</aside>
  57. <main>主体内容区:绝对定位</main>
  58. </div>
  59. <footer>页脚|慧城科技©|备案号********</footer>
  60. </body>
  61. </html>

浏览器显示效果:


3.内容的多栏显示

示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>内容的多栏显示</title>
  7. </head>
  8. <style>
  9. /* 初始化 */
  10. * {
  11. padding: 0;
  12. margin: 0;
  13. /* 重新计算盒子的大小 */
  14. box-sizing: content-box;
  15. }
  16. /* 设置字体大小以及字体颜色 */
  17. :root {
  18. font-size: 18px;
  19. color: rgb(221, 217, 217);
  20. }
  21. /* 多栏布局 */
  22. div {
  23. /* 给文本添加一个1像素的边框 */
  24. border: 1px solid red;
  25. /* rem相对单位,相对于html文档中的字体大小 */
  26. padding: 1rem;
  27. /* 宽度:60个字体大小 */
  28. width: 60rem;
  29. /* 上下30px,左右自动居中 */
  30. margin: 30px auto;
  31. }
  32. div {
  33. /* 分列显示 */
  34. column-count: 3;
  35. /* column-rule-style: solid;(设置中间的分割线)
  36. column-rule-width: 1px;(分割线宽度为1px)
  37. column-rule-color: red; (分割线的颜色)*/
  38. /* 简写 */
  39. column-rule: solid 1px red;
  40. }
  41. </style>
  42. <body>
  43. <div>
  44. 新华社北京6月22日电
  45. 中国-阿拉伯国家政党对话会特别会议22日以视频会议方式召开。中共中央总书记、国家主席习近平向会议致贺信。
  46. 习近平表示,值此中国-阿拉伯国家政党对话会特别会议开幕之际,我代表中国共产党,并以我个人的名义,向会议的召开表示热烈的祝贺,向出席会议的阿拉伯国家政党领导人表示诚挚的问候。
  47. 习近平指出,中阿友谊源远流长,历久弥新。中阿两大民族在古丝绸之路上出入相友,在共建“一带一路”中携手相伴,共同致力于实现国家富强、民族复兴梦想。面对突如其来的新冠肺炎疫情,中阿守望相助、共克时艰,谱写了共建中阿命运共同体的新篇章。患难见真情。经过携手抗疫的洗礼,中阿战略伙伴关系基础更加牢固,人民友谊更加深厚,合作前景更加光明。
  48. 习近平强调,此次疫情再次表明,人类是休戚与共的命运共同体。中国共产党和中国政府始终坚持人民至上、生命至上,全力以赴救治生命,疫情防控取得重大战略成果;始终本着公开、透明、负责任态度,积极参与和推动国际抗疫合作,始终力所能及支持和帮助国际社会抗疫斗争。中方愿同包括广大阿拉伯国家在内的国际社会加强团结合作,支持世界卫生组织发挥领导作用,共同推动构建人类卫生健康共同体。
  49. 习近平表示,中阿政党对话会是中国共产党与阿拉伯国家政党交流合作的重要平台。面对疫情带来的新形势新挑战,中国共产党愿同阿拉伯各国政党一道,发挥好中阿政党对话会的平台作用,继续加强战略沟通,深化疫情防控常态化形势下治国理政经验交流,相互尊重,互学互鉴,为构建新时代中阿命运共同体、实现中阿两大民族伟大复兴而不懈努力。预祝会议取得圆满成功。
  50. 中国-阿拉伯国家政党对话会特别会议由中共中央对外联络部主办。会议为期3天,主题为“携手共建新时代中阿命运共同体”。毛里塔尼亚总统加祖瓦尼,巴勒斯坦法塔赫主席、总统阿巴斯,叙利亚复兴党总书记、总统巴沙尔,摩洛哥公正与发展党总书记、首相奥斯曼尼等6位阿拉伯国家领导人向会议致辞,阿拉伯国家60余位主要政党领导人参加。阿方领导人表示,完全赞同习近平总书记对阿中战略伙伴关系的积极评价;
  51. 高度赞赏中国党和政府在抗疫斗争中始终坚持“人民至上”的执政理念,并秉持人类命运共同体理念,积极参与和推动国际抗疫合作;感谢中方一贯支持阿拉伯国家捍卫主权和独立,认为香港、新疆等事务是中国内政,反对外部势力干涉中国内政;愿同中国共产党一道,加强战略沟通和理念互鉴,携手共建新时代阿中命运共同体。
  52. </div>
  53. </body>
  54. </html>

浏览器显示效果:

4.多栏多列布局页面

代码示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>多栏显示布局</title>
  7. </head>
  8. <style>
  9. /* 初始化 */
  10. *{
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. }
  15. /* 给予页眉页脚部分设置高度以及背景颜色 */
  16. header,footer {
  17. height: 50px;
  18. background-color: rgb(210, 250, 228);
  19. }
  20. .container {
  21. /* 设置中间区域父容器的宽度, */
  22. width: 1000px;
  23. /* 上下外边距为10px,留点间隙,水平居中, */
  24. margin: 10px auto;
  25. /* 设置边框属性 */
  26. border: 1px solid red;
  27. /* 分列显示 */
  28. column-count: 3 ;
  29. }
  30. /* 给予边栏设置高度及背景颜色 */
  31. aside {
  32. height: 700px;
  33. background-color: royalblue;
  34. }
  35. /* 给予主体内容设置高度以及背景色 */
  36. main {
  37. height: 700px;
  38. background-color: seagreen;
  39. }
  40. </style>
  41. <body>
  42. <header>页眉(可以用来布局,但是有局限性,只能用在等宽基础上)</header>
  43. <div class="container">
  44. <aside>左侧边栏</aside>
  45. <main>主体内容区</main>
  46. <aside>右侧边栏</aside>
  47. </div>
  48. <footer><footer>页脚|慧城科技&copy;|备案号********</footer></footer>
  49. </body>
  50. </html>

注意:可以利用多栏显示来布局,但是拥有局限性,只能用在等宽的基础上

浏览器显示效果:


5.FlexBox弹性盒子布局快速预览

基本常识:

  1. - 所有的弹性元素必须沿着主轴排列
  2. - 与主轴垂直交叉的轴被称为交叉轴或侧轴、列轴、辅助轴

如下图所示:

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>FlexBox弹性盒子布局快速预览</title>
  7. </head>
  8. <style>
  9. *{
  10. margin: 0;
  11. padding: 0;
  12. box-sizing: border-box;
  13. }
  14. .container {
  15. width: 300px;
  16. /* 转为弹性盒子 */
  17. display: flex;
  18. }
  19. .container > .item{
  20. /* 一旦将父元素转为弹性容器,内部的“子元素”就会自动成为: 弹性项目 */
  21. /* 不管这个项目标签之前是什么类型,统统转为“行内块” */
  22. /* 行内:全部在一排显示 */
  23. /* 块: 可以设置宽和高 */
  24. /* 沾满整个弹性容器空间 */
  25. flex: auto;
  26. }
  27. </style>
  28. <body>
  29. <div class="container">
  30. <div class="item">1</div>
  31. <div class="item">2</div>
  32. <div class="item">3</div>
  33. </div>
  34. </body>
  35. </html>

注意:如果这个容器中的内容要使用flexBox布局,第一步就是必须将这个容器转为弹性盒子: display:flex

浏览器显示样式:

flex: auto;前浏览器样式:


6.FlexBox弹性盒多行容器

示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>FlexBox弹性盒子多行容器</title>
  7. </head>
  8. <style>
  9. /* 初始化 */
  10. *{
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. }
  15. .container {
  16. width: 300px;
  17. /* 转为弹性盒子 */
  18. display: flex;
  19. }
  20. .container > .item{
  21. /* 项目宽度为60px */
  22. width: 60px;
  23. width: 100px;
  24. }
  25. /* 当前弹性盒里面有6个弹性项目
  26. 当他们的宽度之和小于弹性盒总宽度时,会有剩余空间
  27. 当他们的宽度之和等于弹性盒总宽度时,刚好填满
  28. 当他们的宽度之和大于弹性盒总宽度时,将不能完全显示,因为弹性盒默认不换行 */
  29. .container {
  30. /* 换行显示 默认不换行nowrap为默认值*/
  31. flex-wrap: wrap;
  32. }
  33. </style>
  34. <body>
  35. <div class="container">
  36. <div class="item">1</div>
  37. <div class="item">2</div>
  38. <div class="item">3</div>
  39. <div class="item">4</div>
  40. <div class="item">5</div>
  41. <div class="item">6</div>
  42. </div>
  43. </body>
  44. </html>

浏览器显示效果:

7.单行容器中的项目对齐方式

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>单行容器中的项目对齐方式</title>
  7. </head>
  8. <style>
  9. /* 初始化 */
  10. *{
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. }
  15. .container {
  16. /* 设置宽度为400像素 */
  17. width: 400px;
  18. /* 转为弹性盒子 */
  19. display: flex;
  20. /* justify-content: 控制所有项目在主轴上的对齐方式;
  21. 本质是:设置容器中的剩余空间在所有 “项目之间”的分配方案 */
  22. /* 1. 容器剩余空间在所有项目“二边”的进行分配 ,匠所有项目视为一个整体*/
  23. /* 左对齐 */
  24. justify-content: flex-start;
  25. /* 右对齐 */
  26. justify-content: flex-end;
  27. /* 居中对齐 */
  28. justify-content: center;
  29. /* 2.容器剩余空间在所有项目之间进行分配 ,将项目视为一个个独立的个体*/
  30. justify-content: space-between;
  31. /* 将剩余空间在项目中平均分配 */
  32. justify-content: space-around;
  33. justify-content: space-evenly;
  34. }
  35. .container > .item {
  36. width: 50px;
  37. }
  38. </style>
  39. <body>
  40. <div class="container">
  41. <div class="item">1</div>
  42. <div class="item">2</div>
  43. <div class="item">3</div>
  44. <div class="item">4</div>
  45. </div>
  46. </body>
  47. </html>

效果展示:

  • justify-content: flex-start; :左对齐效果

  • justify-content: flex-end; :右对齐效果

  • justify-content: center; :居中对齐效果

  • justify-content: space-between; : 平均对齐

  • justify-content: space-around; :分散分布

  • justify-content: space-evenly; :平均分配


8.多行容器中的项目对齐方式

代码示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>多行容器中的项目对齐方式</title>
  7. </head>
  8. <style>
  9. /* 初始化 */
  10. *{
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. }
  15. .container {
  16. /* 设置宽度为400像素 */
  17. width: 400px;
  18. /* 转为弹性盒子 */
  19. display: flex;
  20. /* 多行容器 */
  21. flex-wrap: wrap;
  22. /* 设置行高 */
  23. height: 100px;
  24. /* align-content: 设置多行容器中的项目排列; */
  25. /* 1. 容器剩余空间在所有项目“二边”的如何分配 ,将全部项目视为一个整体*/
  26. align-content: stretch;
  27. align-content: flex-start;
  28. align-content: flex-end;
  29. align-content: center;
  30. /* 2. 容器剩余空间在所有项目“之间”的如何分配 ,将项目视为一个个独立的个体*/
  31. align-content: space-between;
  32. align-content: space-around;
  33. align-content: space-evenly;
  34. }
  35. .container > .item {
  36. width: 60px;
  37. }
  38. </style>
  39. <body>
  40. <div class="container">
  41. <div class="item">1</div>
  42. <div class="item">2</div>
  43. <div class="item">3</div>
  44. <div class="item">4</div>
  45. <div class="item">5</div>
  46. <div class="item">6</div>
  47. <div class="item">7</div>
  48. <div class="item">8</div>
  49. </div>
  50. </body>
  51. </html>

大概思路与单行对齐大同小异

浏览器样式:


9.主轴为垂直方向时的项目排列

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>主轴为垂直方向时的项目排列</title>
  7. </head>
  8. <style>
  9. .container {
  10. width: 300px;
  11. height: 100px;
  12. /* 转为弹性盒子 */
  13. display: flex;
  14. /* 主轴方向:row 默认为行 */
  15. flex-direction: row;
  16. /* column 将主轴设置为列 */
  17. flex-direction: column;
  18. /* 项目二边分配 */
  19. justify-content: flex-start;
  20. justify-content: flex-end;
  21. justify-content: center;
  22. /* 项目之间分配 */
  23. justify-content: space-between;
  24. justify-content: space-around;
  25. justify-content: space-evenly;
  26. }
  27. </style>
  28. <body>
  29. <div class="container">
  30. <div class="item">1</div>
  31. <div class="item">2</div>
  32. <div class="item">3</div>
  33. <div class="item">4</div>
  34. </div>
  35. </body>
  36. </html>

浏览器显示效果:

这里只展示了 space-evenly 平均分配的效果图,其余效果可自行根据代码去查看


10.项目在交叉轴上的排列

备注:默认项目在交叉轴上是自动伸缩的

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>项目在交叉轴上的排列</title>
  7. </head>
  8. <style>
  9. .container {
  10. width: 300px;
  11. height: 100px;
  12. /* 弹性盒子 */
  13. display: flex;
  14. /* 项目在交叉轴上默认是自动伸缩的 */
  15. align-items: stretch;
  16. /* 上对齐 */
  17. align-items: flex-start;
  18. /* 下对齐 */
  19. align-items: flex-end;
  20. /* 居中 */
  21. align-items: center;
  22. }
  23. .container > .item {
  24. width: 60px;
  25. }
  26. </style>
  27. <body>
  28. <div class="container">
  29. <div class="item">1</div>
  30. <div class="item">2</div>
  31. <div class="item">3</div>
  32. </div>
  33. </body>
  34. </html>

浏览器效果显示:


11.主轴方向与项目排列的简写

代码演示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>主轴方向与项目排列的简写</title>
  7. </head>
  8. <style>
  9. .container {
  10. width: 600px;
  11. height: 200px;
  12. display: flex;
  13. /* 以下是默认值可以不用写出来 */
  14. /* flex-direction: row;*/
  15. /*flex-wrap: nowrap; */
  16. /* flex-flow: row nowrap; */
  17. /* 可以直接简写成: */
  18. flex-flow: column wrap;
  19. }
  20. .container > .item {
  21. width: 60px;
  22. height: 100px;
  23. }
  24. </style>
  25. <body>
  26. <div class="container">
  27. <div class="item">1</div>
  28. <div class="item">2</div>
  29. <div class="item">3</div>
  30. <div class="item">4</div>
  31. <div class="item">5</div>
  32. </div>
  33. </body>
  34. </html>

浏览器显示效果:

12.flex容器属性实战: 快速制作一个主导航

代码示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>flex容器属性实战: 快速制作一个主导航</title>
  7. </head>
  8. <style>
  9. /* 初式化 */
  10. *{
  11. padding: 0;
  12. margin: 0;
  13. box-sizing: border-box;
  14. }
  15. a {
  16. /* 取消字体下面的下划线 */
  17. text-decoration: none;
  18. /* 设置字体颜色 */
  19. color: rgb(243, 241, 240);
  20. }
  21. nav{
  22. height: 40px;
  23. /* 设置背景色 */
  24. background-color: black;
  25. padding: 0 20px;
  26. /* 转为弹性盒子 */
  27. display: flex;
  28. }
  29. nav a {
  30. height: inherit;
  31. line-height: 40px;
  32. padding: 0 15px;
  33. }
  34. /* 添加鼠标移入样式,变亮 */
  35. nav a:hover {
  36. background-color: seagreen;
  37. color: white;
  38. }
  39. /* 将登录/注册放到最右边 */
  40. nav a:last-of-type {
  41. margin-left: auto;
  42. }
  43. </style>
  44. <body>
  45. <header>
  46. <nav>
  47. <a href="">首页</a>
  48. <a href="">公司简介</a>
  49. <a href="">项目名称</a>
  50. <a href="">公司荣誉</a>
  51. <a href="">视频下载</a>
  52. <a href="">联系我们</a>
  53. <a href="">登录/注册</a>
  54. </nav>
  55. </header>
  56. </body>
  57. </html>

浏览器效果图:


13.项目属性: order控制项目顺序

代码示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>项目属性: order控制项目顺序</title>
  7. </head>
  8. <style>
  9. .container {
  10. width: 300px;
  11. display: flex;
  12. }
  13. .container > .item {
  14. width: 60px;
  15. }
  16. .container > .item:first-of-type {
  17. /* order: 默认是顺序为0 */
  18. /* 给的值越大越往后排 */
  19. order: 3;
  20. }
  21. .container > .item:last-of-type {
  22. /* order: 默认是0 */
  23. order: 5;
  24. }
  25. </style>
  26. <body>
  27. <div class="container">
  28. <div class="item">1</div>
  29. <div class="item">2</div>
  30. <div class="item">3</div>
  31. </div>
  32. </body>
  33. </html>

浏览器显示效果:


14.order小案例,调整元素顺序,比如小相册

代码示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>order小案例,调整元素顺序,比如小相册</title>
  7. <style>
  8. .container {
  9. width: 300px;
  10. display: flex;
  11. flex-direction: column;
  12. }
  13. .container > .item {
  14. border: 1px solid #000;
  15. padding: 10px;
  16. display: flex;
  17. position: relative;
  18. }
  19. .container > .item > div {
  20. display: flex;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div class="container">
  26. <div class="item">
  27. images-1.jpg
  28. <div>
  29. <button onclick="up(this)">Up</button
  30. ><button onclick="down(this)">Down</button>
  31. </div>
  32. </div>
  33. <div class="item">
  34. images-2.jpg
  35. <div>
  36. <button onclick="up(this)">Up</button
  37. ><button onclick="down(this)">Down</button>
  38. </div>
  39. </div>
  40. <div class="item">
  41. images-3.jpg
  42. <div>
  43. <button onclick="up(this)">Up</button
  44. ><button onclick="down(this)">Down</button>
  45. </div>
  46. </div>
  47. </div>
  48. <script>
  49. let up = (ele) => (ele.offsetParent.style.order -= 1);
  50. let down = (ele) => (ele.offsetParent.style.order += 1);
  51. </script>
  52. </body>
  53. </html>

浏览器样式:


内容总结

  • flexBox弹性盒子单行、多行的对齐以及分配方式只是代码不同,但是概念都基本一样
  • 使用flexbox之前必须得将这个容器转为弹性盒子
  • flexbox内的属性都比较类似容易混乱,已经做好笔记方便课下复习记忆
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议