# 居中 Center

在我浅薄的前端经历中,常遇到两种居中的场景。一种是在一个 div 中放一个 div,让内层的 div (水平,或垂直,或两者都要)居中;另一种是让一个 div 里的文字(水平,或垂直,或两者都要)居中。

让 div 居中时,我个人不太喜欢使用 margin: auto 或者 top: 50%; left: 50%,平时都是无脑上 flex,即给外层 div 加上 display: flex; justify-content: center; align-items: center;,非常方便。

<div style="background-color: blue; width: 400px; height: 200px; display: flex; justify-content: center; align-items: center">
  <div style="background-color: red; width: 100px; height: 100px"></div>
</div>
  • 如果修改不了外层元素,就在中间加一层 div,给这层 div 加上 display: flex; justify-content: center; align-items: center;。这样的缺点就是会多一层 div,不过我平时用着没啥问题。

让文字居中时,其实也可以使用 flex 布局,相当省事。

<div style="background-color: grey; width: 400px; height: 200px; display: flex; justify-content: center; align-items: center">
  content
</div>
content

# 覆盖 Overlay

我们需要把两个元素叠在一起,例如将红色元素叠在蓝色元素之上。一种常见的实现是,把两个元素放在一个父 div 下,给红色元素加上 position: absolute; top: xxx; left: xxx; z-index: 1;

<div style="position: relative; background-color: grey">
  <div style="background-color: blue; width: 400px; height: 200px"></div>
  <div style="background-color: red; width: 100px; height: 100px; top: 0; left: 0; position: absolute; z-index: 1"></div>
</div>
  • 不要忘了给父 div 设置 position: relative,否则上层元素会基于整个页面进行定位。
  • 如果上层元素想基于 position: relative 进行布局,可以给上层元素加 position: absolute; top: 0; left: 0; width: 100%; height: 100%,里面套一个 relative 元素,里面的元素就可以使用相对布局了。

# 父元素宽度自适应

Stack Overflow (opens new window)

一般子元素自适应宽度很好做,用 width: 100% 就可以以父元素宽度基准进行设定。

如果想要反过来,以子元素的宽度作为基准,设定父元素的宽度,可以使用 width: fit-content; 或者 display: inline-xxx

<div style="width: 200px; height: 200px; background: gray">
  <div style="display:flex; width: fit-content; height: 150px; background: red;">
    <div style="width: 100px; height: 100px; background: blue;"></div>
    <div style="width: 50px; height: 50px; background: green;"></div>
  </div>
</div>
<div style="width: 200px; height: 200px; background: gray">
  <div style="display:inline-flex; height: 150px; background: red;">
    <div style="width: 100px; height: 100px; background: blue;"></div>
    <div style="width: 50px; height: 50px; background: green;"></div>
  </div>
</div>
  • 这里使用 flexinline-flex 是为了把红、绿两个元素放在一行。

# Layout 页面

一个 Web App 的 Layout 页面一般包含顶栏、底栏、侧边栏和放路由页面的部分。这四个部分会占据整个页面。

为了“占据整个页面”,顶栏和底栏是固定高度,中间部分的高度则需要根据页面高度和顶栏高度确定。一种方法是使用 flex 布局:配置好顶栏和底栏的高度后,中间的部分使用 flex-grow: 1 撑起整个页面;另一种方法是使用 calc() 属性:提前计算好顶栏和底栏的高度后,中间的部分指定为 height: calc(100vh - ?px),也能达到一样的效果。

不过使用 flex-grow: 1 的方案时需要注意,一是需要给其它元素设置 flex-shrink: 0,防止该元素超高导致其它元素变矮;二是如果不设置定长,同时这个元素正好被设置了 display: flex 导致 min-content: auto,这个元素的 children 变高会导致元素本身变高,进而导致整个页面变高,需要在元素上设置 min-content: 0 阻止。读者可以尝试在开发者工具中修改去掉下面例子的这两条属性,然后观察会发生什么。这么对比下来,提前计算好高度的方案反而简单多了

路由页面里的内容会根据业务需要和路由来确定,而 Layout 一般会为这个部分创建一个 container,配置一些默认属性(如宽、高、overflow),路由页面中的业务就不用再配置 container 的属性,而是专注于自己的业务 UI。一般来说,为 container 设置好宽、高和 overflow: auto 就足够了,这样 children 不够高时 container 也会撑起整个页面;chilren 太高、太宽时,container 也会显示滚动条。

<div class="code-example">
  <div style="width: 600px; height: 400px; background: gray; display: flex; flex-direction: column">
    <div style="flex-shrink: 0; height: 50px; width: 100%; background: red;">顶栏</div>
    <div style="flex-grow: 1; display: flex; min-height: 0;">
      <div style="flex-shrink: 0; width: 100px; height: 100%; background: yellow;">侧边栏</div>
      <div style="flex-grow: 1; height: 100%; background: green; overflow: auto;">
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
        <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
      </div>
    </div>
    <div style="flex-shrink: 0; height: 50px; width: 100%; background: orange;">底栏</div>
  </div>
</div>
顶栏
侧边栏
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
底栏
顶栏
侧边栏
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
底栏

# 滚动条 Scroll

# 一个固定宽、单行、可横向滚动的 div;调整 scrollbar 的高度

使用 width: xxx; white-space: nowrap; overflow-x: auto; 可以创造一个固定宽度的 div,内容只有一行,内容超出 div 宽度时可以横向滚动。这样能保证 div 的宽高不会随内容的宽度变化而变化,同时如果内容太长太长,用户可以使用滚动条查看剩余内容。

使用 ::-webkit-scrollbar 伪类可以调整 scrollbar 的样式,例如高度、颜色等。还可以调整其它伪类来定制化 scrollbar,具体可以看 MDN Docs (opens new window)。不过需要注意的是,inline CSS 和 CSS In JS 不支持伪类,只能老老实实写 class,然后定义 CSS 文件。

<div class="scrollbar-h6" style="width: 600px; white-space: nowrap; overflow-x: auto; background: yellow">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

<style lang="css">
.scrollbar-h6::-webkit-scrollbar {
  height: 6px;
}
</style>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

# 始终为 scrollbar 保留空间

在某些场景下 scrollbar 会频繁出现、消失(如表格数据不多的时候不显示滚动条,加载所有数据后显示滚动条;又比如页面上有滚动条,但页面失去焦点后滚动条消失),导致页面的宽度频繁变化,影响用户体验。

可以使用 scrollbar-gutter: stable 来始终为 scrollbar 保留空间,这样即使 scrollbar 不显示,页面的宽度也不会变化。