CSS-Grid布局详解

news2024/9/23 10:34:22
前言

Grid 栅格布局 是 CSS 语言中非常强大的种布局,它提供了丰富的工具属性,可以轻松实现复杂且灵活的布局设计,因此想要完美使用CSS Grid 也有一定的难度和复杂性,我自己也是花了不少时间才真正掌握它的使用,在这篇教程中,我会分享在学习和使用 CSS Grid 时的一些关键体会和收获,通过这些希望能够帮助各位了解到 CSS Grid 的基础知识,并学会如何用它实现一些复杂的布局效果。

兼容性怎么样?


CSS Grid 是使用 CSS 构建布局的一种前言方式,实际上也并不完全是“前沿”的,自 2017 年以来,所有主流浏览器都支持它!据 caniuse 称,97.8% 的用户支持 CSS Grid(在新标签页中打开),这是算是非常出色的浏览器兼容率,Flexbox(弹性盒子) 的兼容率仅高出约 0.5%!

简介

 CSS是由几种不同的布局算法组成,每种算法都针对不同类型的用户界面而设计。默认布局算法 Flow 布局专为数字文档而设计,Table表格布局专为表格数据而设计,Flexbox 专为沿单个轴分布布局而设计。

  而CSS Grid 算是一种最新、最出色的布局算法,它非常强大,可以使用它来构建复杂的布局,并且可以根据许多复杂约束条件流畅地进行布局调整,在我看来CSS Grid 最不寻常的部分是网格结构、行和列完全在 CSS 中定义:

 

使用 grid布局之后,单个 DOM 节点被细分为行和列,上图用虚线突出显示行/列,但实际上,它们是不可见的,为了方便展示我加了border属性,在其他所有布局模式中,创建此类布局的唯一方法是添加更多 DOM 节点。例如,在表格布局中,每行都使用 <tr> 创建,该行中的每个单元格使用 <td> 或 <th> 创建:

 

<table>
  <tbody>
  
    <tr> 
      <td></td>
      <td></td>
      <td></td>
    </tr>
 
    <tr> 
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>

 与表格布局不同的是grid布局允许浏览器完全在 CSS 内部管理布局,能够随意分割容器,创建网格子元素可以用作锚点的隔间

.wrapper {
  display: grid;
}

默认情况下,grid布局使用单列,并根据子元素的数量根据需要创建行,这称为隐式网格,因为没有明确定义任何布局结构,工作原理如下:

隐式网格是动态的;行数将根据子项的数量添加和删除,每个子项都有自己的行,默认情况下网格父元素的高度由其子元素决定,它会动态增加和减少,有意思的是这甚至不是grid的属性,网格父元素仍然使用流布局,流布局中的块元素会垂直增长以包含其内容!只有子元素使用网格布局排列。

但是如果我们给网格一个固定的高度会怎么样?在这种情况下,整体高度将被分成大小相等的行:

使用Grid布局 

默认情况下,Grid 将创建单列布局,可以使用 grid-template-columns 属性指定列:

为了清晰起见,所以这里添加了虚线
在上面的所有内容的示例中都使用了虚线来显示列和行之间的划分,在 CSS 网格中实际是没有这些虚线的。

通过给 grid-template-columns 设置两个属性值(25% 和 75%),意思是告诉 CSS grid 算法将元素分成两列。

可以使用任何有效的 CSS <length-percentage> value(在新选项卡中打开)定义列,包括px、rem、vw单位等。此外grid还可以使用一个新单位  fr  单位:

 fr 可以理解为'份数'在此示例中,表示第一列应占用 1 份的空间,而第二列应占用 3份的空,这意味着整个元素总共被分为了 4 个份的空间把着看做分母,第一列占用了可用空间的 ¼,而第二列占用了 ¾。fr 单位为 CSS Grid 布局带来了 Flexbox 布局的灵活性,百分比和 <length> 值会创建硬约束,而 fr 列可以根据需要自由增长和收缩以完全占用父元素。

具体差异如下:

在这种情况下,左边第一列有一个固定宽度的图片,其宽度被明确指定为 55px。但是如果列太小而无法容纳它怎么办?

基于百分比的列是固定的,因此会出现图像溢出。
基于 fr 的列是灵活的,就算破坏了预先规定的宽度比例也不会缩小到图片内容大小以下,
更准确地说:fr 单位分配额外的空间。首先列宽将根据其内容计算,如果有剩余空间,它将根据 fr 值进行分配,这与 flex-grow 非常相似,这种灵活性在实际使用场景中是一种更好更方便的选择。

我们可以通过 gap 看到一个完美的例子。gap 是一个神奇的 CSS 属性,它在我们的网格中的所有列和行之间添加了固定量的空间。

看看在百分比和fr之间切换时会发生什么:

注意使用基于百分比的列时内容会溢出网格的父级,发生这种情况是因为百分比是使用总网格面积计算的,两列占用了父级内容区域的 100%,并且不允许缩小,当添加 16px 的间隙时列别无选择只能溢出容器。

相比之下,fr 单位是根据额外空间计算的。在这种情况下,额外空间已减少了 16px间隙,grid算法将剩余空间分配到两个网格列之间。

gapVS grid-gap

grid 首次推出时,grid-gap 属性用于在列和行之间添加空间。然而大家很快意识到,如果 Flexbox 也拥有此功能那效果将会更好,因此该属性被赋予了一个更通用的名称 gap。

如今,grid-gap 已被标记为弃用,浏览器已将其更改为 gap,这两个属性的作用完全相同,而且它们浏览器兼容率都为96%,因此无论使用的是 Flexbox 还是 CSS Grid,我都建议使用 gap 而不是 grid-gap!

 隐式和显式行

如果在两列网格中添加两个以上的子元素,会发生什么情况?上面网格增加了第二行,网格算法确保每个子元素都有自己的网格单元,它会根据需要生成新行来实现此目标,这在元素数量可变(例如照片网格)并且希望网格自动扩展的情况下非常方便,

但是,在其他情况下希望明确定义行,以创建特定的布局,就可以使用 grid-template-rows 属性来实现这一点:

 通过定义 grid-template-rows 和 grid-template-columns,可以创建一个显式网格。

实用案例

使用grid布局构建一个日历:

CSS Grid 是处理此类问题的绝佳工具。我们可以将其构造为 7 列网格,每列占用 1 个单位:

.calendar {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

虽然上述方案也可行,但必须计算每个 1fr,这有点烦人。想象一下,如果我们有 50 列该怎么办呢?有一种更好的方法可以解决这个问题:

<style>
  .calendar {
    display: grid;
    grid-template-columns:
      repeat(7, 1fr);
    gap: 4px;
  }
</style>

<ol class="calendar">
  <li class="day">1</li>
  <li class="day">2</li>
  <li class="day">3</li>
  <li class="day">4</li>
  <li class="day">5</li>
  <li class="day">6</li>
  <li class="day">7</li>
  <li class="day">8</li>
  <li class="day">9</li>
  <li class="day">10</li>
  <li class="day">11</li>
  <li class="day">12</li>
  <li class="day">13</li>
  <li class="day">14</li>
  <li class="day">15</li>
  <li class="day">16</li>
  <li class="day">17</li>
  <li class="day">18</li>
  <li class="day">19</li>
  <li class="day">20</li>
  <li class="day">21</li>
  <li class="day">22</li>
  <li class="day">23</li>
  <li class="day">24</li>
  <li class="day">25</li>
  <li class="day">26</li>
  <li class="day">27</li>
  <li class="day">28</li>
  <li class="day">29</li>
  <li class="day">30</li>
  <li class="day">31</li>
</ol>

此日历是如何使用 CSS Grid 创建特定布局的简单示例,它并不适用于生产环境。 

分配子元素

默认情况下,grid算法会将每个子元素分配到第一个未占用的网格单元,可以将子元素分配到想要的任何单元!子元素甚至可以跨越多行/列:

grid-row 和 grid-column 属性允许指定网格子元素应占据哪些位置,如果希望子元素占据一行或一列,可以通过其编号指定,grid-column: 3 将设置子项位于第三列。

网格子项还可以跨越多行/列,此语法使用斜线来划分开始和结束:

.child {
  grid-column: 1 / 4;
}

乍一看,这看起来像一个分数¼。但在 CSS 中,斜线字符不用于除法,而是用于分隔值组。在本例中,它允许我们在单个声明中设置起始列和结束列,它本质上是以下代码的简写:

.child {
  grid-column-start: 1;
  grid-column-end: 4;
}

这里有一个小小的陷阱:提供的数字是基于列数量,而不是列索引,为了方便理解,这里用一张图来解释这个更容易:

 让人不解的是,虽然说是4列的网格布局,但实际上包含了5条分隔列的线。在分配子元素到网格中时,会依据这些线来确定它们的位置,如果想让一个子元素占据前3列的空间,那么它的起始位置应是第1条列线,而结束位置则需延伸到第4条列线之后。

 负数行号

 在左到右的语言中,习惯从左到右计数列,但是使用负数行号,实际上也可以按相反方向计数,即从右到左。

.child { 
  grid-column: -2;
}

更有意思的是实际上你可以正数负数一起使用!!!

 

即使没有特别指定子元素应占据的列数,它有时也会自动跨越整个网格的宽度,这确实是一个值得注意的现象。在这种情况下,如果想要子元素从第一列线开始,并一直延伸到最后一列线,可以采用一种简便的声明方式来实现  Full-Bleed 布局

网格区域

如何使用grid布局实现如下页面结构呢?

.grid {
  display: grid;
  grid-template-columns: 2fr 5fr;
  grid-template-rows: 50px 1fr;
}

.sidebar {
  grid-column: 1;
  grid-row: 1 / 3;
}
.header {
  grid-column: 2;
  grid-row: 1;
}
.main {
  grid-column: 2;
  grid-row: 2;
}

 

和之前一样,使用 grid-template-columns 和 grid-template-rows 定义网格结构。但是这里有个奇怪的声明: 

.parent {
  grid-template-areas:
    'sidebar header'
    'sidebar main';
}

它的工作原理确实非常直观还很有创意,通过一种类似于制作ASCII艺术的方式来规划网格布局。每一行代表网格中的一行,而每个“单词”或标识符则是为网格中特定区域所指定的名称。这样,整个布局在视觉上就能清晰地呈现出网格的结构。

在分配子元素到网格时,采用grid-area属性,而不是单独使用grid-columngrid-row。这种方式使得布局更加灵活和易于理解,因为可以通过区域名称来指定子元素的位置和大小,而无需关心具体的行列号。

当某个区域需要跨越多行或多列时,只需在网格模板中重复该区域的名称即可。例如,在示例中,“侧边栏”区域跨越了两行,因此在第一列中连续为两个单元格指定了“侧边栏”作为它们的名称。

至于应该使用区域还是行/列来构建布局,这主要取决于具体的需求和场景。在构建具有明确语义含义和显式布局的网格时,使用区域(如通过grid-template-areasgrid-area)通常是一个更好的选择。它不仅能够使布局更加清晰易懂,还能为网格的不同部分赋予有意义的名称,从而提高代码的可维护性和可读性。

然而,当网格的行数和列数可能发生变化,或者需要更灵活地控制子元素的具体位置时,使用grid-columngrid-row等属性可能更为合适。这些属性允许直接指定子元素应该占据哪些行和列,从而提供了更高的灵活性和控制力。

总的来说,无论是使用区域还是行/列来构建网格布局,关键在于根据具体需求和场景选择最合适的方法。

用户体验


在网格分配方面有一个很大的问题:选项卡顺序仍然基于 DOM 位置,而不是网格位置。当使用CSS Grid布局时,一个容易被忽视但非常重要的问题,特别是关于Tab键的导航顺序。在CSS Grid中,虽然可以自由地排列元素以实现视觉上的布局效果,但Tab键的导航顺序仍然是基于DOM中的元素顺序,而不是它们在网格中的视觉位置。

假设有一个包含多个按钮的网页,使用CSS Grid来布局这些按钮,使它们在视觉上呈现出一种特定的排列方式。然而,当使用键盘上的Tab键来导航这些按钮时,会发现它们并不是按照在网格中看到的顺序来被选中的。相反,它们会按照它们在HTML文档(即DOM)中出现的顺序被依次选中

为了解决这个问题,应该重新排列 DOM 中的网格子元素,使它们与视觉顺序相匹配,这样我就可以从左到右、从上到下进行切换。

CSS 开发人员也意识到这是 网格布局的一个缺陷。必须将 DOM 顺序与视觉顺序相匹配,这有点违背了将子元素分配给特定网格单元的目的!

据说是正在修复中。将来阅读顺序 CSS 属性应该允许指示浏览器忽略 DOM 顺序,并按照元素在屏幕上出现的顺序聚焦元素。

截至 2024 年 9 月,任何浏览器都尚未实现此属性

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件造价咨询】工程活动工作量分布占比的统计分析

在软件项目管理中&#xff0c;准确估算工程活动的工作量是确保项目按时、按预算完成的关键。工程活动工作量分布基准数据明细提供了一种量化工作量的方法&#xff0c;可以帮助团队成员更好地预测和把控不同工程活动所需的工作量。本文将探讨工程活动工作量分布基准数据明细的意…

offsetX、offsetY...

文章目录 offsetX & offsetYclientX & clientYpageX & pageYscreenX & screenYinnerHeight & innerWidthoffsetHeight & offsetWidthoffsetTop & offsetLeftscrollHeight & scrollWidthscrollTop & scrollLeft:与scrollHeight和scrollWidt…

图为科技大模型一体机,智领未来社区服务

当AI与边缘计算相遇&#xff0c;一幅关于智慧生活的宏伟蓝图正缓缓展开。 今天&#xff0c;让我们一同探索&#xff0c;如何通过图为大模型一体机&#xff0c;为物业服务插上智能的翅膀。 通过整合采集物业数据&#xff0c;大模型一体机可全方位为物业行业赋能&#xff0c;实…

Vue3实现类ChatGPT聊天式流式输出(vue-sse实现)

1. 效果展示 流式输出 直接输出 2. 核心代码 找了一些示例与AI生成的代码&#xff0c;或多或少有些问题&#xff0c;搞了好久&#xff0c;郁闷~&#xff0c;在此记录下 2.1 依赖安装 npm install vue-sse2.2 改写main.ts import VueSSE from vue-sseconst app Vue.cre…

ubuntu+MobaXterm+ssh+运行Qt(成功版)

点击上方"蓝字"关注我们 01、ubuntu连接SSH >>> 通过串口工具连接ubuntu 登录 解决连接不上的问题 检查 SSH 服务:确保目标机器上 SSH 服务已启动。你可以在目标机器上运行以下命令: sudo systemctl status ssh 如果没有运行,可以使用以下命令启动 SSH …

解锁2024年翻译在线Top4,让每一次交流都精准无误

现在世界就像个大家庭&#xff0c;交流多了&#xff0c;语言不通就成了问题。有道翻译在线就像桥梁&#xff0c;帮我们和全世界的朋友沟通。对企业来说&#xff0c;翻译准确太重要了&#xff0c;一句话翻错可能损失巨大。有道翻译在线技术强&#xff0c;各种语言都能搞定&#…

简述混沌神经网络

混沌神经网络是一种结合了神经网络与混沌理论的新型智能信息处理系统。以下是对混沌神经网络的详细解析&#xff1a; 一、定义与背景 混沌神经网络是由于神经网络具有高度非线性动力学系统的特性&#xff0c;而混沌又具有无规则性、遍历性、随机性等特点&#xff0c;因此神经网…

快递物流查询-快递查询-快递单号查询-快递物流单号查询-快递物流轨迹查询-快递物流查询接口

快递物流查询接口&#xff08;API&#xff09;是一种允许开发者通过编程方式实时查询快递物流信息的服务。这些接口通常集成了多家快递公司的物流数据&#xff0c;为电商平台、物流管理系统、个人用户等提供便捷的物流查询服务。以下是关于快递物流查询接口的一些详细介绍&…

【通讯协议】S32K142芯片——LIN通信的学习和配置

文章目录 前言1.LIN是什么&#xff1f;2. LIN连接结构及节点构成3. 帧的组成3.1 帧头3.1.1 同步间隔场&#xff08;Break&#xff09;3.1.2 同步场&#xff08;Synch&#xff09;3.1.3 标识符场&#xff08;PID&#xff09; 3.2 帧响应3.2.1 数据场3.2.2 校验和场 3. 代码配置总…

「C++系列」动态内存

【人工智能教程】&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站&#xff1a;【人工智能教程】 文章目录 一、动态内存1. 使用new和delete①分配单个对象②分配对象数组 2. …

深入理解MySQL InnoDB中的B+索引机制

目录 一、InnoDB中的B 树索引介绍 二、聚簇索引 &#xff08;一&#xff09;使用记录主键值的大小进行排序 页内记录排序 页之间的排序 目录项页的排序 &#xff08;二&#xff09;叶子节点存储完整的用户记录 数据即索引 自动创建 &#xff08;三&#xff09;聚簇索引…

[数据结构与算法·C++] 笔记 1.5 流

流 标准输入输出流 标准输入流 cin>>x 读入整型数时以第一个非数字为终结读入字符串时以第一个空格、tab 或换行符为终结 其它方法 标准输出流 cout<<y cout 输出到标准设备cerr 输出错误信息clog 输出错误日志 输出不同进制 hex -> 16 进制dec -> 10 …

windows cuda12.1 pytorch gpu环境配置

安装cuda12.1 nvcc -V conda创建pythong3.10环境 conda create -n llama3_env python3.10 conda activate llama3_env 安装pytorch conda install pytorch torchvision torchaudio pytorch-cuda11.8 -c pytorch -c nvidia gpu - Pytorch version for cuda 12.2 - Stack Ov…

Stable Diffusion WebUI Forge 支持 Flux 了!

大家好&#xff0c;我是每天分享AI应用的萤火君&#xff01; Flux横空出世有段时间了&#xff0c;模型效果也得到了广泛的认可&#xff0c;但是 Stable Diffusion WebUI 官方迟迟没有跟进&#xff0c;据说是因为要修改很多底层的处理机制&#xff0c;加之ComfyUI如火如荼&…

鸿蒙OpenHarmony【轻量系统内核扩展组件(CPU占用率)】子系统开发

基本概念 CPU&#xff08;中央处理器&#xff0c;Central Processing Unit&#xff09;占用率分为系统CPU占用率和任务CPU占用率。 系统CPU占用率&#xff1a;是指周期时间内系统的CPU占用率&#xff0c;用于表示系统一段时间内的闲忙程度&#xff0c;也表示CPU的负载情况。系…

iOS 中 KVC 与 KVO 底层原理

KVC 本质&#xff1a; [object setValue: forKey:];即使没有在.h 文件中有property 的属性声明&#xff0c;setValue:forKey依然会按照上图流程执行代码 KVC 如果成功改变了成员变量&#xff0c;是一定可以被 KVO 监听到成员变量的前后改变的 KVO runtime会生成中间类&…

EmguCV学习笔记 C# 12.3 OCR

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

ActiveMQ 的消息持久化策略

ActiveMQ 的消息持久化策略 消息持久化对于可靠消息传递来说是一种比较好的方法&#xff0c;即使发送者和接受者不是同时在线&#xff0c;或者消息中心在发送者发送消息后宕机了&#xff0c;消息中心重启后仍然可以将消息发送出去。 消息持久性的原理很简单&#xff0c;就是在发…

[Linux] 通透讲解 什么是进程

标题&#xff1a;[Linux] 通透讲解 什么是进程 个人主页&#xff1a;水墨不写bug &#xff08;图片来自网络&#xff09; 目录 一.深入进程基本概念 二.管理好进程 1.管理好进程的方法 2.描述进程-PCB 3.组织进程 正文开始&#xff1a; 本文按照对进程的先描述再组织进行…

C++之模版的进阶

1.非类型模版参数 模版参数分类类型与非类型形形参 类型形参&#xff1a;出现在模版参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff1a;用一个常亮作为类&#xff08;函数&#xff09;模版的一个参数&#xff0c;在类&#xff08;函数…