传统布局、网格布局、flex布局解决居中问题

584 阅读7分钟

本文汇总多种方法,具体场景具体分析,注意使用的对象的分类:

  • 文本、行内元素
  • 块级元素
  • 自适应内容的块级元素

基础方法

行内元素水平居中
text-align:center;//父元素属性
行内元素垂直居中
height:100px;//父元素属性
line-height:100px;//父元素属性行高==高度即可

大小确定的块级元素
margin:auto;//自身

传统布局模式

使用position的absolute实现居中

  1. 确定包含块 使用该方法时候,一定要对父元素进行定位,因为absolute是相对与static外的第一个父元素

补充:本质上absolute相对的是层叠上下文,所以CSS 3 transform属性不为none的也可以作为绝对定位的包含块

  1. 目标元素绝对定位
  2. left、top移动50%
  3. 上一步百分比移动是相对于(0,0)点的,所以需要移动自身长度的一半来居中
  4. 大小确定者,采用margin-left:一半宽度的负值;margin-top:一半高度的负值;
  5. 长度不确定margin-left transform变形属性
#father{
    width:100px;
    height:100px;
    background-color: aqua;
    /* 父元素必须定位,即必须对position初始化,否则为默认值static */
    position: fixed;
    left:auto;
}
#son{
    width:50px;
    height:50px;
    background-color:palevioletred;
    position: absolute;
    left:50%;
    top:50%;
    /* 百分比移动是相对于(0,0)点的,所以需要移动自身长度的一半来居中 */
    margin-left:-25px;
    margin-top:-25px; 
}

在这里插入图片描述

自适应的块级元素想要用这个方法怎么办?

transform:translateX(-50%);// 注意CSS世界中没有几个属性的百分比是相对自己计算的
transform:translateY(-50%);

transform属性

  • 该属性允许我们对元素进行旋转、缩放、移动或倾斜
  • 内联元素不支持所有变换特性,无法应用transform
  • 与clip-path出现在同一选择器中时,无论书写前后,先clip-path后transform

clip-path使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏

  • 类似opacity不为1的元素,如果元素的transform不为none,就会创建一个新的层叠上下文

两张图片重叠时候,后DOM遮住前DOM,可以通过给前DOM设置transform:scale(1)调整

  • 如果父元素使用了transform变换,子元素的fixed固定效果就会失效,表现类似absolute绝对定位,所以推荐外层元素负责定位,内层元素负责动画

fixed 相对于浏览器窗口进行定位

视口居中-视口单位+transform

vw 是与视口宽度相关的,1vw 表示视口宽度的 1%

  • 1vmin=min(1vw, 1vh);
  • 1vmax=max(1vw, 1vh);
#father{
    width:100px;
    height:100px;
    background-color: aqua;
    margin:50vh auto 50vw auto;
    transform:translateY(-50%); 
    transform: translateX(-50%);
}
#son{
    width:50px;
    height:50px;
    background-color:palevioletred;
    margin:50vh auto 50vw auto;
    transform:translateY(-50%); 
    transform: translateX(-50%);
}

缩放浏览器,元素保持视口居中

flex布局

传统布局基于盒状模型,依赖 display 属性 + position属性 + float属性。09年,W3C提出Flex布局 css单词通用含义

  • justify水平方向
  • align垂直方向
  • items全体元素
  • content整体布局
  • self元素自身的样式,大部分是子元素

利用弹性盒子写一个菜单栏

首先一个简单的例子 在这里插入图片描述

在这里插入图片描述

/*外部容器设置为弹性*/
    .site-nav {
      display: flex;
      padding: .5em;
      background-color: #5f4b44;
      list-style-type: none;
      border-radius: .2em;
    }

    .site-nav > li {
      margin-top: 0;
    }

    .site-nav > li > a {
      display: block;
      padding: .5em 1em;
      background-color: #cc6b5a;
      color: white;
      text-decoration: none;
    }
    /*所有块的左部外边距*/
    .site-nav > li + li {
      margin-left: 1.5em;
    }
   /*设置最后一块的左部外边距为auto来让他填满容器,实现靠右的效果*/
    .site-nav > .nav-right {
      margin-left: auto;
    }
  • display:flex,该元素成为弹性容器,他的子元素成为弹性子元素
  • flex容器存在方向不同的两条轴,主轴和交叉轴
  • 项目主轴大小:子元素占据主轴方向上的长度。
  • 子元素的float、clear、vertical-align失效。

属性

容器属性

flex-flow属性:flex-direction + flex-wrap

默认值为row、nowrap

在垂直的弹性盒子里,flex的收缩属性不会起作用

flex-direction主轴的方向即项目的排列方向
flex-direction:row;//默认控制子元素从左到右
column、row-reverse、column-reverse

flex-wrap默认项目都排列在轴线上,如果超出一行,该属性定义如何换行
nowrap不换行
wrap换行,下一行在下方
wrap-reverse换行,下一行在上方
启用之后,flex-shrink无效,元素不再收缩,直接折行

对齐:justify-content、align-content、align-items

justify-content 水平间距也可以理解为主轴上对齐方式 在这里插入图片描述 align-content属性值同justify-content,定义多根交叉轴线的对齐方式,即多行的间距 在这里插入图片描述 align-item属性定义flex子项在flex容器的当前行的侧轴(纵轴)方向上的对齐方式 在这里插入图片描述 子元素提供了align-self属性来覆盖align-item属性

常用来实现居中

子元素属性

  • 子元素的float、clear、vertical-align失效
  • 控制副轴上的属性align-items、align-content的初始值是stretch
  • 弹性子元素像块级元素一样填充可用宽度,但是弹性子元素不一定填满其弹性容器的宽度
  • 弹性子元素高度相等,高度由他们的内容决定。(换一个主轴方向就是等宽列)
  • 将弹性子元素的margin设置为auto后,就可以实现子元素相对弹性容器居中。

order属性

定义项目排列顺序:值越小越前,默认值为0

flex属性

flex属性是简写属性

flex-grow
非负整数,子元素的盒模型占据之后的容器宽度可能会有留白
留白会将增长因子视作权重来分给子元素
0代表不增长

flex-shrink
子元素的盒模型占据之后的容器宽度可能不足
0代表不缩水

flex-basis
元素大小的基准值,作用于宽度还是高度取决于flex-direction
px、em、百分比

缩略特殊值:

flex:initial 默认值 
flex:0 1 auto

flex: 0 等同于
flex: 0 1 0% 文字会显示为一柱擎天

flex: 1 等同于文字会显示为一柱擎天

flex: none 等同于
flex: 0 0 auto

flex:auto 等同于
flex:1 1 auto

grid布局

和弹性盒子类似,网格布局也是作用于两级DOM结构。

  • display:grid,该元素成为一个网格容器,它的子元素成为网格元素。
  • 网格语法有一个限制,所有网格元素必须是网格容器的直接子节点

定义网格轨道

  • 新增属性定义网格轨道
  • fr每一列的分数单位,权重
  • 函数repeat
grid-template-rows: 1fr 1fr;
//等同于
grid-template-rows:repeat(2,1fr );

grid-template-columns: 2fr 1fr 1fr 3fr;
//等同于
grid-template-columns: 2fr repeat(2,1fr ) 3fr;

在这里插入图片描述

实现代码

<!doctype html>
<head>
  <style>
  :root {
    box-sizing: border-box;
  }

  *,
  ::before,
  ::after {
    box-sizing: inherit;
  }

  .grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    grid-template-rows: 1fr 1fr;
    grid-gap: 0.5em;
  }

  .grid > * {
    background-color: darkgray;
    color: white;
    padding: 2em;
    border-radius: 0.5em;
  }
  </style>
</head>
<body>
  <div class="grid">
    <div class="a">a</div>
    <div class="b">b</div>
    <div class="c">c</div>
    <div class="d">d</div>
    <div class="e">e</div>
    <div class="f">f</div>
  </div>
</body>

隐式网格

隐式网格:上面显式定义了一个网格,在实际DOM中如果元素多于网格数会自动扩充网格

隐式网络设置一个默认大小值

grid-auto-rows: 1fr;
grid-auto-colums: 1fr;

指定元素所占位置

grid-column: 起始网格线 / 终止网格线、或者span 网格数

 .a{
    grid-column: 1 / 3;
  }

页面变化为 在这里插入图片描述

命名网格线

.container {
    display: grid;
    grid-template-columns: [left-start] 2fr
                           [left-end right-start] 1fr
                           [right-end];
    grid-template-rows: repeat(4, [row] auto);
    grid-gap: 1.5em;
    max-width: 1080px;
    margin: 0 auto;
  }

  header,
  nav {
    grid-column: left-start / right-end;
    grid-row: span 1;
  }

  .main {
    grid-column: left;
    grid-row: row 3 / span 2;
  }

  .sidebar-top {
    grid-column: right;
    grid-row: 3 / 4;
  }

命名网格区域

  • 网格区域必须组成一个矩形
  • . 作为名称 代表空出一个网格
.container {
    display: grid;
    grid-template-areas: "title title"
                         "nav   ."
                         "main  aside1"
                         "main  aside2";
    grid-template-columns: 2fr 1fr;
    grid-template-rows: repeat(4, auto);
    grid-gap: 1.5em;
    max-width: 1080px;
    margin: 0 auto;
  }

特性查询

CSS查看浏览器支持特性与否 回退样式在特性查询之外

 @supports (display: grid) {
      .portfolio {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        grid-auto-rows: 1fr;
        grid-gap: 1em;
        grid-auto-flow: dense;
      }
    }
    //抑或是
     @supports not(display: grid){}
     @supports (display: grid) or (display: table){} 
     @supports (display: grid) and (display: table){} 

设置不同的大小

给部分元素占多个网格区域

.portfolio .featured {
      grid-row: span 3;
      grid-column: span 3;
    }

在这里插入图片描述在这里插入图片描述

所示变化发生在默认 grid-auto-flow:row;

例子

flex实现网页布局

在这里插入图片描述

<!doctype html>
<head>
  <style>
    :root {
      box-sizing: border-box;
    }

    *,
    ::before,
    ::after {
      box-sizing: inherit;
    }

    body {
      background-color: #709b90;
      font-family: Helvetica, Arial, sans-serif;
    }

    body * + * {
      margin-top: 1.5em;
    }

    .container {
      max-width: 1080px;
      margin: 0 auto;
    }

    .site-nav {
      display: flex;
      padding: .5em;
      background-color: #5f4b44;
      list-style-type: none;
      border-radius: .2em;
    }

    .site-nav > li {
      margin-top: 0;
    }

    .site-nav > li > a {
      display: block;
      padding: .5em 1em;
      background-color: #cc6b5a;
      color: white;
      text-decoration: none;
    }

    .site-nav > li + li {
      margin-left: 1.5em;
    }

    .site-nav > .nav-right {
      margin-left: auto;
    }

    .tile {
      padding: 1.5em;
      background-color: #fff;
    }

    .flex {
      display: flex;
    }

    .flex > * + * {
      margin-top: 0;
      margin-left: 1.5em;
    }

    .column-main {
      flex: 2;
    }

    .column-sidebar {
      flex: 1;
      display: flex;
      flex-direction: column;
    }

    .column-sidebar > .tile {
      flex: 1;
    }

  
    .login-form h3 {
      margin: 0;
      font-size: .9em;
      font-weight: bold;
      text-align: right;
      text-transform: uppercase;
    }

    .login-form input:not([type=checkbox]):not([type=radio]) {
      display: block;
      margin-top: 0;
      width: 100%;
    }

    .login-form button {
      margin-top: 1em;
      border: 1px solid #cc6b5a;
      background-color: white;
      padding: .5em 1em;
      cursor: pointer;
    }

  </style>
</head>

<body>
  <div class="container">
    <header>
      <h1>Ink</h1>
    </header>
    <nav>
      <ul class="site-nav">
        <li><a href="/">Home</a></li>
        <li><a href="/features">Features</a></li>
        <li><a href="/pricing">Pricing</a></li>
        <li><a href="/support">Support</a></li>
        <li class="nav-right">
          <a href="/about">About</a>
        </li>
      </ul>
    </nav>
    <main class="flex">
      <div class="column-main tile">
        <h1>Team collaboration done right</h1>
        <p>Thousands of teams from all over the
          world turn to <b>Ink</b> to communicate
          and get things done.</p>
      </div>
     
      <div class="column-sidebar">
        <div class="tile">
        
        <form class="login-form">
            <h3>Login</h3>
            <p>
              <label for="username">Username</label>
              <input id="username" type="text"
                name="username"/>
            </p>
            <p>
              <label for="password">Password</label>
              <input id="password" type="password"
                name="password"/>
            </p>
            <button type="submit">Login</button>
          </form>

        </div>
        <div class="tile centered">
          <small>Starting at</small>
          <div class="cost">
            <span class="cost-currency">$</span>
            <span class="cost-dollars">20</span>
            <span class="cost-cents">.00</span>
          </div>
          <a class="cta-button" href="/pricing">
            Sign up
          </a>
        </div>
      </div>
    </main>
  </div>
</body>