聊一聊flex布局

845 阅读5分钟

站内或者其他网站里都有很多flex布局相关的内容, 本文旨在记录一些偏向于需求的内容, 一些应用层面的内容, 语法方面的内容可查看阮一峰老师的博文, 个人觉得讲得挺详细的:

参考文章:

Flex 布局教程:语法篇

Flex 布局示例

同时如果你对flex布局并不了解, 那么推荐你先去看上面的两篇参考文章, 然后再来针对某些需求或者细节来查阅本文, 那么我们现在开始

flex-basis

这个属性我们需要记住的有两点

  1. 它的优先级会高于widthheight
  2. 具体最后渲染的结果是width还是height取决于我们的flex-direction, 当flex-direction值为row的时候它渲染的结果是width, 反之为column的时候是height 下面我们可以通过一个例子在看一下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex-basis</title>
  <style>
    .container{
      width: 800px;
      height: 800px;
      display: flex;
    }
    .box1{
      width: 200px;
      height: 200px;
      background: #f00;
    }
    .box2{
      flex-basis: 400px;
      width: 200px;
      height: 200px;
      background: #0f0;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="box1"></div>
    <div class="box2"></div>
  </div>
</body>
</html>

image.png

image.png

image.png

此时如果设置flex-direction: column;则结果为:

image.png

此时flex-basis设置的值渲染为height

元素被拉长(自我调节属性)

看了winter老师极客时间的课之后了解到, 这是一种"根据外部环境调节自身"的一种行为, 这就是为何flex布局更只能的原因所在了

还是以上面的代码来举例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>元素被拉长</title>
  <style>
    .container{
      width: 800px;
      height: 800px;
      display: flex;
    }
    .box1{
      width: 200px;
      height: 200px;
      background: #f00;
    }
    .box2{
      width: 200px;
      background: #0f0;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="box1"></div>
    <div class="box2"></div>
  </div>
</body>
</html>

image.png

.box1的尺寸渲染结果为200x200, 而.box2没有设置height, 它最终被渲染的结果是200x800, 此时修改样式为:

  <style>
    .container{
      width: 800px;
      height: 800px;
      display: flex;
      flex-direction: column;
    }
    .box1{
      width: 200px;
      height: 200px;
      background: #f00;
    }
    .box2{
      height: 200px;
      background: #0f0;
    }
  </style>

则渲染结果变为:

image.png 可以看到, 根据外部环境调节自身的这个特性不止使用与拥有flex这个display上下文的父容器, 在父容器的子元素中同样适用, 这是这里的被改变的属性是交叉轴方向上的属性, 比如

  • 第一个例子flex-direction没有显式设置, 那么它的默认值为row, 此时能被调节被改变的是height
  • 反之第二例flex-direction: column;, 此时被调节的则是width

自我调节属性的应用

这里也可以直接给a标签的父级div设置一个高, flex之后a标签就能撑住父亲, 与父亲一样高了

父亲display:flex, 儿子有图片, 给图片设置好高度例如30px:

image.png

image.png

儿子此时的高便能和他的兄弟中最高的那个一致了:

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

此时p没高, 那么就是最高那个元素的高, 这里最高的元素是父元素div, 54px, 因此p元素的高就是 54px, 另外的input button的高都是各自自己设置的高, 而且此时pmargin是均分的

解决方案一

此时可以给蓝盒子设置height: xx%来解决, 如果遇到移动端的话, 也可以用vw来搞定

解决方案二

既然子元素会被拉到和父盒子一样高,那就给父盒子一个高度,如果子元素有很多margin的情况 可以给个margin 0来解决:

image.png

image.png

image.png 给个margin 0之后就好了:

image.png

image.png

text-align属性失效

flex布局会影响text-align:

image.png

image.png

image.png

image.png 这个时候如果将display:flex;去掉之后text-align:right;就能正常生效了:

image.png

父元素设置了display:flex之后, 子元素的float clear vertical-align同时还有这里的text-align属性都将失效

两个元素一个居中一个居右

image.png

css使用了ootstrap 2.x栅格系统, 同时辅以媒体查询外加百分比作单位, 适配效果良好, 大盒子和两个子盒子都用flex布局, 两个子盒子的元素排列方式都用flex-end, 宽度设置不同的百分比, 然后微调即可

image.png

image.png

image.png

image.png

换行效果: flex-wrap:wrap;

默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行:

  • nowrap(默认):不换行
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方

image.png

image.png

image.png

子元素宽了,父元素装不下了,所以就在某个位置换行了, 如果子元素不设置宽度的话就默认到父元素的结束位置再换行, 也就是说调整的宽度越大, 那么就越提前换行

两个元素一个居左一个居右

当时开发的时候由于对flex的理解还不深, 因此有了这个记录, 最后发现设置justify-content: space-between;即可

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style type="text/css">
        .box{
            display: flex;
            flex-basis: 100vw;
            justify-content: space-between;
        }
    </style>
</head>
<body>
    <div class="box">
        <div class="item">1</div>
        <div class="item">2</div>
    </div>
</body>
</html>

image.png

flex-basis定义了在分配多余空间之前,项目占据的主轴空间main size。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小, 这个地方如果设置的值小,那么二者的距离就相应的变小了:

image.png

元素宽缩为一半

父元素:

image.png

image.png

子元素:

image.png

image.png

此时子元素的宽是屏幕宽 - 两边留白, 没问题, 当父元素设置了display:flex;之后:

image.png

子元素的宽变成了刚才父元素没加display:flex;之后的宽的一半

超出内容省略号

PC端

DOM结构

image.png

父元素

image.png

左侧图片, 固定宽高和右边距

image.png

右侧盒子应该用百分比固定宽度, 而不是flex属性类似0 0 auto什么的, 不然就有弹性了, 没法实现需求

image.png

这里看到昵称和右侧盒子之间又有一个盒子是遗留问题, 因为之前昵称右边有个盒子, 所以是这样的

手机端

手机端的布局和PC端一样,但是用百分比的时候怎么都会超出去一些

image.png

修改宽度之后就好了

image.png

而且如果是width:calc(100% - 50px);图片的尺寸就会被压缩, 所以还是绝对的宽度好: 屏幕宽减去图片的宽和右边距以及屏幕两边的留白

关于flex: 1;和flex: auto;

例如前面有个元素需要自动填充, 后面有一行文字的效果:

flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;

image.png

flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

image.png

此时flex: 1;能完成需求, 但是flex: auto;不行, flex-basis: auto;表示项目占据的空间为项目本身的空间, 而这里是需要缩小的, 要变化的

如果你觉得这篇文章对你有用的话记得给我点个赞, 点个收藏, 众人拾柴, 愿没有难写的代码, 没有难实现的需求