Grid layout + 媒体查询轻易实现常用的响应式布局

2023-11-28 20:01:45 浏览数 (1)

最近在整理前端知识体系,怎么可以少了布局这一环呢?先问大家一个问题,如果让css只保留一种布局,留下来解决前端布局问题?你会选择那个布局呢?如果问我,我会选择 网格布局,根据二八原则,网格布局基本上可以帮助我解决 80% 的布局场景,颇有一套布局打遍天下布局的气势,因此非常值得一探究竟。

学习本文,你将会学会:

  • 网格布局的基本使用方式,如果已经有基本了解,建议略过
  • 网格布局 媒体查询 来解决响应式问题

对于一名前端研发来讲,如果说不会做布局,那可能由于一个画家不会构图,这是非常致命的,但是布局的方式多种多样,只说最为常见的几种,这个是在mdn文档上的排头部的一些。

代码语言:javascript复制
display: block;
display: inline;
display: inline-block;
display: flex;
display: inline-flex;
display: grid;
display: inline-grid;
display: flow-root;

布局模式

使用场景

擅长解决的布局问题

不擅长解决的布局问题

优势

劣势

block

段落、容器、导航栏

垂直布局、容器尺寸控制

水平布局复杂性、内联元素布局

易于理解和使用、强大的宽高控制

布局较为僵硬、不适合复杂布局

inline

文本、图像

水平布局、内联元素间的排列

垂直边距不生效、大小控制

与文本流自然融合

无法设置宽高、边距和填充有限制

inline-block

按钮、小部件

内联元素的宽高控制

大型布局、自动布局

结合了inline和block的特点

对齐问题、间隙问题

flex

导航栏、卡片布局、复杂的一维布局

一维布局、对齐、分布空间

二维布局的复杂场景

强大的对齐能力、灵活的空间分配

学习曲线相对较高

inline-flex

小型的、内联的复杂布局

内联元素的复杂布局

大型的二维布局

flex的优点,但适用于内联环境

与flex相同,不适合大型的二维布局

grid

复杂的页面布局、表格布局

二维布局、对齐、模板区域

旧浏览器不兼容

强大的二维布局能力、精确布局控制

学习曲线高、兼容性问题

inline-grid

内联的复杂布局

内联元素的二维布局

与grid相同

grid的优点,但适用于内联环境

与grid相同,不适合大型的二维布局

flow-root

清除浮动、局部BFC

创建新的块格式化上下文

复杂布局

清除内部浮动不影响外部布局

相对较新,可能有兼容性问题

这里面的布局的示例就不一样去些demo围观了,,简单的demo可以在 官方网站上https://developer.mozilla.org/en-US/docs/Web/CSS/display 进行查看。

网格布局的基本使用

创建一个简单的网格容器

代码语言:javascript复制
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px; // 这里也可以写成gap
}

这里,.container 是一个包含三个等宽列的网格容器,grid-gap 设置了网格线之间的间隙,1fr表示一个份(份子),所以这个表达的意思就是将一行分为3份,每块占1份,repeat(3,1rf)===1fr 1fr 1fr

使用行和列来布局项目

代码语言:javascript复制
.item {
  grid-column: 1 / 3;
  grid-row: 1;
}

.item 将占据从第一列到第三列之前的空间(即两列宽),并位于第一行。

创建具有不同大小列的网格

代码语言:javascript复制
.container {
  display: grid;
  grid-template-columns: auto 1fr 2fr;
}

第一列根据内容自动调整大小,第二列占据剩余空间的1份,第三列占据剩余空间的2份。

使用minmax来设置灵活的网格尺寸

代码语言:javascript复制
.container {
  display: grid;
  grid-template-columns: repeat(3, minmax(100px, 1fr));
}

每列至少100px宽,但可以伸展以占据更多的空间,也就是最大就是1份,。

创建一个自适应数量的列

代码语言:javascript复制
.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

这将创建尽可能多的列,每列至少150px宽,但不会超过可用空间。

对齐网格项

代码语言:javascript复制
.item {
  justify-self: start;/* 水平对齐到网格区域的起始边缘 */
  align-self: end;/* 垂直对齐到网格区域的末端边缘 */
}

可以控制单个网格项在其网格区域内的对齐方式。

使用命名网格线

代码语言:javascript复制
.container {
  display: grid;
  grid-template-columns: [start] 1fr [middle] 2fr [end];
}
.item {
  grid-column: start / middle;
}

这里,网格线被命名startmiddleend.itemstart延伸到middle

创建网格模板区域

代码语言:javascript复制
.container {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar content content"
    "footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }

这样可以定义一个具有头部、侧边栏、内容和页脚区域的布局,这个也是下面的一个打的demo将会讲解的具体例子的基础,本文会基于此并结合媒体查询做一个响应式布局的案例,让你感受一下 grid 媒体查询的厉害之处。

响应式网格

代码语言:javascript复制
@media (max-width: 600px) {
  .container {
    grid-template-columns: 1fr;
  }
}

当屏幕宽度小于600px时,网格将只有一列,这里就是媒体查询结合网格的初步应用,为我们下述的demo打下基础。

网格➕媒体查询,实现响应式

假设,我们的最终实现的目标是这样的一个网页:

  • 在页面比较窄的情况下,呈现出一个flex布局的样式,directioncolumn。但实际上,我们还是使用grid layout实现哈。
  • 在页面稍微变宽点的时候,呈现中间部分显示效果。
  • 如果页面在宽到一定程度的时候就,变成右侧部分的显示效果。

怎么做到这个的呢?我给你一个初始的代码:

代码语言:javascript复制
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      .wrapper {
        display: grid;
        gap: 20px;
        grid-template-areas:
          "header"
          "nav"
          "content"
          "sidebar"
          "ad"
          "footer";
      }
      .main-head {
        grid-area: header;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;
      }
      .content {
        grid-area: content;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;
      }
      .main-nav {
        grid-area: nav;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;

      }
     .main-nav ul {
        list-style-type: none;
        margin: 0;
        padding: 0;
      }
      .side {
        grid-area: sidebar;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;
      }
      .ad {
        grid-area: ad;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;
      }
      .main-footer {
        grid-area: footer;
        background-color: bisque;
        border: 1px solid rgb(185, 107, 107);
        border-radius: 5px;
        padding: 2px 5px;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <header class="main-head">The header</header>
      <nav class="main-nav">
        <ul>
          <li><a href="">Nav 1</a></li>
          <li><a href="">Nav 2</a></li>
          <li><a href="">Nav 3</a></li>
        </ul>
      </nav>
      <article class="content">
        <h1>Main article area</h1>
        <p>
          In this layout, we display the areas in source order for any screen
          less that 500 pixels wide. We go to a two column layout, and then to a
          three column layout by redefining the grid, and the placement of items
          on the grid.
        </p>
      </article>
      <aside class="side">Sidebar</aside>
      <div class="ad">Advertising</div>
      <footer class="main-footer">The footer</footer>
    </div>
  </body>
</html>

这个呈现的效果将会是:

此时,无论如何拉伸,我们始终会看到这样的布局效果,不会改变,此时,我们加入一下媒体查询相关的代码,类似于做一些根据楼几增加样式的事情。

代码语言:javascript复制
@media (min-width: 500px) {
        .wrapper {
          grid-template-columns: 1fr 3fr;
          grid-template-areas:
            "header  header"
            "nav     nav"
            "sidebar content"
            "ad      footer";
        }
        nav ul {
          display: flex;
          justify-content: space-between;
        }
      }

此时,我们发现布局变了,这里我们做了些啥呢?

  • @media (min-width: 500px) 在500像素以上时,上下文内样式生效。
  • 通过grid-template-areas,来控制了表格中行列的摆放。
  • 通过grid-template-columns: 1**fr** 3**fr**;,控制了siderbar和 内容区域的比例。
  • 将导航栏变为了flex 布局

所以,我们看到了网页的变化成了随着宽度的变化到超过 500px时,变成这种展示效果了。继续:

代码语言:javascript复制
@media (min-width: 700px) {
  .wrapper {
    grid-template-columns: 1fr 4fr 1fr;
    grid-template-areas:
      "header header  header"
      "nav    content sidebar"
      "nav    content ad"
      "footer footer  footer";
  }
  nav ul {
    flex-direction: column;
  }
}

我们看到了上述的效果,就这样,非常轻松实现了网络的响应式布局,发现网格这种命名区域的方式,对于布局响应式来说,不是唯一的方式,但是可以说是一种比较清晰,而且有简洁的布局方式。

总结

毫不避讳的讲,网格布局有他的局限性,即兼容性

可以从mdn官网看到,grid支持2017年以后的浏览器版本,IE是肯定不支持的,因此在做选型的时候,如果产品无需支持IE,且用户群体较为时尚,可以考虑grid全量,毕竟这种方式写出的响应式布局代码,整体唯一性来看,会比较好。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞