CSS Layout Notes
Box Pattern
Box Sizing
box-sizing
:
content-box
(initial
value).padding-box
.border-box
.
:root {
box-sizing: border-box;
}
*,
::before,
::after {
box-sizing: inherit;
}
Box sizing:
Intrinsic Sizing
(内在尺寸): 表示元素最终的尺寸表现是由内容决定的, e.gfit-content
/min-content
/max-content
.Extrinsic Sizing
(外在尺寸): 表示元素最终的尺寸表现是由上下文决定的, e.gstretch
/-moz-available
/-webkit-fill-available
.
Box Width
Width Formal Syntax
width
:
auto
: initial value.<length>
.<percentage>
.min-content | max-content | fit-content | fit-content(<length-percentage>)
.
Percentage Width
%
width calculate by containing box
width:
- 普通元素的百分比宽度是相对于父元素
content box
宽度计算. - 绝对定位元素的百分比宽度是相对于第一个
position
不为static
的祖先元素padding box
宽度计算.
Auto Flow Width
Auto flow with css-sizing
,
fit-content
/min-content
/max-content
/stretch
for width
/min-width
/max-width
/height
/min-height
/max-height
/
grid-template-rows
/grid-template-columns
/flex-basis
:
fit-content
: grow but not overflow.
.content {
width: fit-content;
margin: auto;
}
.button {
box-sizing: border-box;
width: calc(100% - 30px);
width: stretch;
height: 40px;
margin-right: 15px;
margin-left: 15px;
}
.table {
box-sizing: border-box;
width: 100%;
width: stretch;
table-layout: fixed;
}
Min and Max Width
min-width
> max-width
> width !important
:
/* 480px */
.box-1 {
min-width: 480px;
max-width: 256px;
}
/* 256px */
.box-2 {
width: 480px !important;
max-width: 256px;
}
Box Height
Flow Height
普通文档流是为限定的宽度和无限的高度设计的 (网页元素的默认布局行为):
- 行内元素跟随文字的方向从左到右排列, 当到达容器边缘时会换行.
- 块级元素会占据完整的一行, 前后都有换行.
这导致处理元素高度的方式跟处理宽度不一样:
box-sizing
仍然会影响高度, 但最好避免给元素指定明确的高度.
容器的高度由内容 (子元素) 天然地决定, 而不是容器自己决定.
Percentage Height
%
height calculate by containing box
height:
- 容器高度为
auto
(initial
value) 时, 其高度通常由子元素高度决定: 浏览器为避免高度计算死循环, 会忽略子元素百分比高度声明. - 容器高度为一个明确值时, 子元素百分比高度才会生效.
Viewport Height
.my-element {
height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
}
window.addEventListener('resize', () => {
// Get viewport height and multiple it by 1% to get a value for a vh unit
const vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
Box Aspect Ratio
Things can break aspect-ratio
:
- Setting both dimensions: setting
inline-size
andblock-size
simultaneously. - Stretching element:
align-items: stretch
. - Content that forces height: inner elements may force the height of the parent.
Box Margin
Auto Margin
CSS2 visual formatting model:
- If both margin-left and margin-right are auto, their used values are equal.
- If margin-top, or margin-bottom are auto, their used value is 0.
Negative Margin
Negative margin
change layout flow:
- Negative
margin-top
/margin-left
: pull self up/left. - Negative
margin-bottom
/margin-right
: pull sibling up/left, overlapping self. - Negative
margin
alongfloat
direction: pull self. - Negative
margin
oppositefloat
direction: pull sibling.
.content {
float: left;
width: 100%;
margin-right: -200px;
}
.sidebar {
float: left;
width: 200px;
}
Negative horizontal margin
on initial
width element make width
stretch
(just like positive padding
):
/* ul width = 100% + 20px */
ul {
margin-right: -20px;
}
ul > li {
float: left;
width: 100px;
margin-right: 20px;
}
.blockquote {
margin: 2rem -2rem;
}
Percentage Margin
Percentage margin
calculate by containing block
inline size (width
),
include margin-top
and margin-bottom
.
Collapse Margin
- Adjacent siblings: 1's
margin-bottom
with 2'smargin-top
. - No content separating parent and descendants:
- No
border
/padding
/inline part
/BFC created
/clear
: can't separate parentsmargin-top
from its descendant blocksmargin-top
. - No
border
/padding
/inline content
/height
/min-height
: can't separate parentsmargin-bottom
from its descendant blocksmargin-bottom
. - Collapsed
margin
ends up outside the parent.
- No
- Empty blocks:
no
border
/padding
/inline content
/height
/min-height
to separate block'smargin-top
from itsmargin-bottom
.
margin
collapsing calculation:
- 正正取大值.
- 正负值相加.
- 负负最负值.
margin
collapsing prevention:
- BFC creation: add
overflow: auto
to container. - Add
padding
. - Add
border
.
Margin collapsing only happen to normal block box vertical direction:
- Line box margin never collapse.
float
box margin never collapse.absolute
/fixed
positioned box margin never collapse.flex
children.grid
children.
Invalid Margin
display: inline
非替换元素 verticalmargin
无效.display: table-cell
/display: table-row
元素margin
无效: e.g<tr>
,<td>
.position: absolute
绝对定位元素未定位方向 (auto
)margin
:.absolute { top: 10%; left: 30%; }
margin-right
与margin-bottom
改变了外部尺寸, 但无法影响兄弟元素布局.- 定高容器子元素的
margin-bottom
或者定宽容器子元素的margin-right
的定位作用失效.
Box Padding
Percentage Padding
Percentage padding
calculate by containing block
inline size (width
),
include padding-top
and padding-bottom
:
.box {
position: relative;
padding: 10% 50%;
}
.box > img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Box Overflow
visible
.hidden
: 溢出隐藏基于padding box
.clip
.scroll
.auto
.
Box Line Height
Inline Element Line Height
行间距:
- 半行间距 =
(line-height * font-size - font-size) / 2
. - 行间距 = 第一行下半行间距 + 第二行上半行间距.
Box Line Height Inheritance
line-height
继承:
%
与em
继承计算值,number
继承数值.line-height
最好使用number
, 使得子代继承line-height
时文字正常排版, 不会出现line-height
<
font-size
导致文字重叠的现象.- Inline level element:
由于
line-height
可继承, 一般给父元素设置line-height
即可, 会自动作用至容器内所有内联元素. - Block level element:
由于行框盒子幽灵空白节点的存在,
line-height * font-size
会决定 block level element 内部元素的最小高度, e.g<div><span></span></div>
高度不为0
.
Box Vertical Align
Box Vertical Align Values
vertical-align
有效值:
- 线类:
baseline
,top
,middle
,bottom
. - 文本类:
text-top
,text-bottom
. - 上标下标类:
sub
,super
. - 数值: 基于
baseline
上移 (正数) / 下移 (负数). - 百分比: calculate by
line-height
.
Box Vertical Align Applies
vertical-align
作用元素:
- Inline level element:
<span>
/<strong>
/<em>
.<img>
/<button>
/<input>
.::before
/::after
.
display: table-cell
元素.- 用
display: inline-*
或display: table-cell
以外的方式 创建Box Formatting Context
后,vertical-align
不再起作用. - 当
line-height
过小时,vertical-align
在视觉上失效, 调整line-height
至足够大时,vertical-align
正常起作用.
Box Model
- Inline-level box:
display
属性为inline
,inline-block
,inline-table
的元素, 会生成 inline-level box, 并且参与Inline Formatting Context
(IFC). - Block-level box:
display
属性为block
,list-item
,table
的元素, 会生成 block-level box, 并且参与Block Formatting Context
(BFC). Flex Formatting Context
(FFC).Grid Formatting Context
(GFC).
Inline Box Model
- Not break onto a new line.
width
andheight
properties will not apply.- Vertical
padding
,border
andmargin
will not push away other inline boxes. - Horizontal
padding
,border
andmargin
will push away other inline boxes.
- Not break onto a new line.
width
andheight
properties are respected.padding
,border
andmargin
will push away other elements.
Content Area
Character box/em-box/selection box:
一种围绕文字看不见的盒子, 其大小仅受字符本身特性控制, 一般将选中区域等价于此盒子.
Inline Box
- 内联元素形成外部内联盒子, 让元素不成块显示, 而是排成一行.
- 水平间距可通过
padding-inline
/border-inline
/margin-inline
调整, 垂直间距可通过line-height
/vertical-align
调整, 垂直间距不受padding-block
/border-block
/margin-block
影响. <span>
/<a>
/<em>
tag 会产生一般内联盒子.- Bare text 会产生匿名内联盒子.
::first-line {
color: white;
background: red;
}
Line Box
- 每一行会形成一个行框盒子.
- 每个行框盒子的前面有一个幽灵空白节点
(zero-width inline box with the element's
font
andline height
properties). 父元素的line-height
会幽灵空白节点产生作用. - 将内联元素设置为
display: inline-block
可以消除幽灵空白节点.
Lines containing Box
<p>
tag 会形成一个包含盒子, 此盒子由一行一行的行框盒子组成.
在很多情况下, 容器高度莫名奇妙变大,
都是行框盒子幽灵空白节点 (Strut
), line-height
, vertical-align
共同作用的结果:
- 容器内部除了显式的内联元素外, 每行还存在幽灵空白节点 (
Strut
). line-height
可继承, 且基于font-size
进行计算.vertical-align
默认对齐方式为基线对齐 (baseline
).
常见例子有:
<div><span></span></div>
高度不为0
:Strut
撑高容器.<div class="leading-8"><span class="text-2xl">文字</span></div>
高度不为32px
(leading-8
): 当Struct
font-size
与内联元素font-size
差距过大时, 进行文字对齐时会撑高容器.<div><img src="1.jpg"></div>
下边缘存在空隙:Strut
默认基于基线对齐.
Block Box Model
- Break onto a new line.
- Extend in inline direction to fill space available in its container.
width
andheight
properties are respected.padding
,border
andmargin
will push away other elements.
Block Formatting Context Features
BFC 包含创建该上下文元素的所有子元素 (包含性):
- 包含内部所有元素的上下外边距: 它们不会跟 BFC 外部的元素产生外边距折叠 (avoid margin collapse).
- 包含内部所有的浮动元素: 计算 BFC 的高度时, 浮动元素也参与计算 (avoid height collapse).
- 不包含创建了新 BFC 的子元素的内部元素.
BFC 是页面上的一个隔离的独立容器 (隔离性):
- BFC 不会跟外部的浮动元素 (
float box
) 重叠: 可用于实现自适应布局. - BFC 内部的元素与外部的元素相互隔离, 无法相互影响.
- 一个元素不能同时存在于两个 BFC 中.
- 内部的 Box 会在垂直方向, 一个接一个地放置.
- 每个元素的
margin box
的左边, 与包含块border box
的左边相接触. - 某些情况下,BFC 中的内容可能会与其他 BFC 中的内容重叠:
- 内容太宽, 溢出了容器.
- 设置负外边距, 导致内容被拉到容器外部.
Block Formatting Context Creation
- 根元素或其它包含它的元素.
overflow
: notvisible
(e.ghidden
).position
: notstatic
/relative
(e.gabsolute
/fixed
).float
elements.display
:inline-block
.display
:table-cell
/table-caption
/table-*h
.display
:flow-root
.- Flex items: direct children of
flex
/inline-flex
box. - Grid items: direct children of
grid
/inline-grid
box.
.bfc-1 {
overflow: hidden;
}
.bfc-2 {
display: table-cell;
*display: inline-block; /* For IE7 */
width: 9999px;
*width: auto; /* For IE7 */
}
Box Stacking
Stacking Level
Positioned element (non-static
position
), flex
box, grid
box
can use the z-index
property to adjust its stacking level:
数值越大, 处于可视的优先级越大.
Stacking Context
- The root element
<html>
forms theroot stacking context
. absolute
/relative
element with non-auto
z-index
.fixed
/sticky
element.flex
children with non-auto
z-index
.grid
children with non-auto
z-index
.opacity
<
element.- non-
normal
mix-blend-mode
element. transform
element.perspective
element.clip-path
element.mask
/mask-image
/mask-border
element.filter
element.backdrop-filter
element.isolation: isolate
element.will-change
above properties element.contain
strict
/content
/layout
/paint
element.
The z-index
of elements inside of a stacking context
are always relative to parent current order in its own stacking context
.
<!-- .bottom > .inner is on top -->
<div class="top">
<div class="inner"></div>
</div>
<div class="bottom">
<div class="inner"></div>
</div>
<style>
.top,
.bottom {
position: relative;
width: 250px;
padding: 80px 20px;
}
.top {
z-index: 1;
}
.bottom {
z-index: 2;
}
.top > .inner {
z-index: 999;
}
.bottom > .inner {
z-index: 2;
}
</style>
Stacking Order
- The background and borders of the root element.
- Descendant non-positioned blocks, in order of appearance in the HTML.
- Descendant positioned elements, in order of appearance in the HTML.
.box {
/* 创建层叠上下文 */
position: relative;
z-index: 0;
background-image: url('1.png');
}
.box::before,
.box::after {
position: absolute;
z-index: -1;
content: '';
}
.box::before {
background-image: url('2.png');
}
.box::after {
background-image: url('3.png');
}
<div class="container">
<div class="page">标题和内容</div>
</div>
<style>
.container {
/* 创建层叠上下文 */
position: relative;
z-index: 0;
background-color: #666;
}
.page {
position: relative;
background-color: #f4f39e;
}
/* 边角卷边阴影 */
.page::before,
.page::after {
/* 层叠上下文(灰色背景)之上, 定位元素(黄色纸张)之下 */
position: absolute;
z-index: -1;
width: 90%;
height: 20%;
content: '';
box-shadow: 0 8px 16px rgb(0 0 0 / 30%);
}
/* 边角卷边阴影定位和角度控制 */
.page::before {
bottom: 0;
left: 0;
transform: skew(-15deg) rotate(-5deg);
transform-origin: left bottom;
}
.page::after {
right: 0;
bottom: 0;
transform: skew(15deg) rotate(5deg);
transform-origin: right bottom;
}
</style>
Inline Pattern
Inline Element Height
- 内联元素默认的高度完全受
font-size
大小控制. - 内联元素没有可视宽度和可视高度 (
clientHeight
/clientWidth
always0
), 垂直方向的行为表现完全受line-height
和vertical-align
的影响.
Inline Element Baseline
Inline Block Element Baseline
inline-block
element:
- 内部没有内联元素, 或者
overflow
not visible: 其基线为margin
底边缘. - 内部存在内联元素: 其基线为最后一行内联元素的基线.
Vertical Align Baseline
Inline element 与父元素下边缘存在空隙,
原因在于文字排版的基线 (baseline
) 对齐机制:
- 在标准模式中,
Inline Formatting Context
总是会包含类似字母 'g'/'f' 尾巴伸出部分空间 (针对下行字母). <img>
/<a>
inline element 与父元素底部若干像素间隙, 实际上是此种情况下的字母尾巴预留机制: 行框盒子存在幽灵空白节点, 默认基于baseline
对齐 (小写字母x
底部).
清除间隙的方法:
- 清除
Strut
高度: 父元素font-size: 0
/line-height: 0
, 设置Inline Formatting Context
高度为0
. - 改变对齐方式:
子元素
vertical-align
设置为top
/middle
/bottom
. - 清除
Strut
节点: 子元素display
设置为inline-block
/block
, 创建Block Formatting Context
, 直接清除幽灵空白节点.
可以用以上方法解决 <img>
image 5px problem 或相似问题.
Inline Element Padding
可以在不影响当前布局的情况下,
通过增加垂直方向的 padding
,
增加链接 (inline
) 或按钮 (inline-block
) 的点击区域大小:
article a {
padding: 0.25rem 0;
}
Inline Element Margin
非主动触发位移的内联元素是不会位移至计算容器外部,
内联元素 margin-top
设置过大时 margin-top
会直接失效,
内联元素依然会处于基线对齐位置.
Position Pattern
Static Position
- Normal flow.
top
/bottom
/left
/right
/inset
/z-index
have no effect.
Relative Position
- 使元素相对于
static
布局. - 可使用
top
/bottom
/left
/right
/inset
属性进行定位. - 相对方向 (opposite) 的定位同时设置:
top
覆盖bottom
,left
覆盖right
. - 初始位置被保留 (仍占用原始空间), 不脱离文档流.
Absolute Position
- 使元素相对于
containing block
布局:- Non-
static
position
element. transform
element.perspective
element.will-change: transform
/will-change: perspective
element.filter
element.backdrop-filter
element.contain
strict
/content
/paint
element.
- Non-
- 若祖先全为无法构成
containing block
的元素, 则使元素相对于浏览器窗口布局. - 可使用
top
/bottom
/left
/right
/inset
属性进行定位. - 相对方向 (opposite) 的定位同时设置:
若未显示设置该方向的元素大小, 则元素具有流动性, 受
containing block
影响其大小,.fluid { position: absolute; left: 0; right: 0; }
. - 初始位置不被保留, 脱离文档流.
float
computed tofloat: none
.display
:inline-table
computed totable
.inline
/inline-block
/table-*
computed toblock
.
.tooltip {
position: absolute;
}
.form-alert,
.form-warning,
.form-info {
position: absolute;
}
.overlay {
position: absolute;
top: 0;
left: 0;
z-index: -50;
width: 100%;
height: 100%;
background: rgb(0 0 0 / 50%);
}
可以利用 absolute
模拟 fixed
布局:
<html>
<body>
<div class="page">滚动内容区域</div>
<div class="fixed">固定定位元素</div>
</body>
<style>
html,
body {
height: 100%;
overflow: hidden;
}
.page {
height: 100%;
overflow: auto;
}
.fixed {
position: absolute;
}
</style>
</html>
Fixed Position
- 使元素相对于
containing block
布局:- Initial
containing block
: 浏览器窗口, 且不受滑动条影响. transform
element.perspective
element.will-change: transform
/will-change: perspective
element.filter
element.backdrop-filter
element.contain
strict
/content
/paint
element.
- Initial
- 可使用
top
/bottom
/left
/right
/inset
属性进行定位. - 初始位置不被保留, 脱离文档流.
float
computed tofloat: none
.display
:inline-table
computed totable
.inline
/inline-block
/table-*
computed toblock
.
Sticky Position
- 使元素相对于 non-
visible
overflow
祖先 (nearest scrolling ancestor) 布局: 要利用position: sticky
实现视窗定位效果, 最好保证祖先全为overflow: visible
元素, 使得视窗成为其 nearest scrolling ancestor. - 若祖先全为
overflow: visible
元素, 则使元素相对于浏览器窗口与containing block
布局:containing block
为 BFC creation element:- Block container.
- Table container.
- Flex container.
- Grid container.
- 粘性定位元素在它距离视窗顶部大于
XXX
时, 会按照默认布局, 表现为relative
position. - 一旦其距离顶部的距离等于
XXX
, 元素会固定在窗口顶部, 表现为fixed
position.
- 粘性定位元素不能超出粘性约束矩形范围的限制:
- 当
containing block
移动到窗口外时, 粘性定位元素也会跟着消失. - 黏性定位元素在同一个容器下会重叠, 在不同容器下则会依次推开: 黏性定位元素分布在一个容器时, 共用一个巨大的黏性约束矩形, 黏性定位元素分布在不同容器时, 存在多个竖直排列的黏性约束矩形.
- 若粘性定位元素父元素的高度和粘性定位元素的高度相同, 则垂直滚动时, 粘性定位效果始终不会出现.
- 可以利用这一特性, 实现层次滚动/视差滚动效果 (
Parallax
).
- 当
.sticky {
position: sticky;
top: 0;
margin-top: 50px;
}
Percentage Position
Positioned elements percentage top
/bottom
/left
/right
/inset
calculate by containing block height
:
If containing block
height
is auto
, it calculated to 0
.
Position Reference
position
property impact ondisplay
items.
Float Pattern
Float Element
- 包裹性:
- 宽度受子元素影响.
- 宽度受 containing block 影响.
- 块状化并格式化上下文.
- 没有任何
margin
合并. - 破坏文档流: 父级高度塌陷.
- 浮动元素的浮动参考 (
float reference
) 是行框盒子:- 浮动元素在当前行框盒子内定位.
float: left
box is positioned at begin of line box.float: right
box is positioned at end of line box.- Non-floaty flow (text) is laid out along edges of floating boxes.
- 浮动元素与行框盒子不可重叠: 行框盒子会缩短以容纳浮动盒子, 会形成文字环绕效果.
浮动元素与 BFC 一起布局时, BFC 会收缩以容纳浮动盒子, 此时会忽略自己的边界必须接触包含块边界的规则. 可用此特性创建自适应布局:
Float Block Formatting Context
float
make element specified value of display
:
inline-table
computed totable
.inline-flex
computed toflex
.inline-grid
computed togrid
.inline
/inline-block
/table-*
computed toblock
.
Fixed Parent
Floating won't work inside fixed
or absolute
div
unless specify width:
.parent {
position: fixed;
top: 5px;
left: 0;
width: 100%;
}
Float Clear Fix
为父容器 (.row
) 添加 .clearfix
:
clear
只能作用于 block level element:::before
/::after
默认为 inline level element,display: table
将::before
/::after
转换为 block level element.clear: both
本质是让自身不和浮动元素在同一行排列, 并没有真正意义上地清除浮动元素的float
(仍然脱离文档流):::after
伪元素不与浮动元素在同一行, 其形成的盒子自然而然地撑起了父容器的高度, 使得因浮动元素脱离文档流而塌陷的父容器恢复正常高度.
.clearfix::before,
.clearfix::after {
display: table;
content: '';
}
.clearfix::after {
clear: both;
}
.clearfix {
*zoom: 1; /* display: inline-block BFC creation for IE7 */
}
Column Pattern
Two Column Pattern
Block Two Column
inline-block
+inline-block
.
Absolute Two Column
absolute
+margin-left
: absolute element not in normal flow.- 利用父元素
relative
与子元素absolute
进行布局.
.div-1 {
position: relative;
}
.div-1a {
position: absolute;
top: 0;
right: 0;
width: 200px;
}
.div-1b {
position: absolute;
top: 0;
left: 0;
width: 200px;
}
Float Two Column
float
+float
.float
+margin-left
: block element ignore float element, inline element surround float element.float
+ BFC.
.container {
overflow: hidden; /* BFC creation */
}
.left {
float: left;
width: 60px;
height: 60px;
}
.right {
margin-left: 70px;
overflow: hidden; /* BFC creation */
}
Fifty-fifty Two Column
.fifty-fifty-flex {
display: flex;
flex-wrap: wrap;
}
.fifty-fifty-flex > * {
flex-grow: 1;
flex-basis: 250px;
}
.fifty-fifty-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
Three Column Pattern
Absolute Three Column
Position .left
and .right
with absolute
,
add margin-left
and margin-right
to .middle
:
<div class="container">
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
</div>
<style>
.container {
position: relative;
}
.left,
.right {
position: absolute;
width: 200px;
}
.middle {
margin: 0 200px;
}
.left {
left: 0;
}
.right {
right: 0;
}
</style>
Float Three Column
<div class="left"></div>
<div class="right"></div>
<div class="middle"></div>
.left {
float: left;
}
.right {
float: right;
}
.middle {
margin: 0 right-width 0 left-width;
}
For float
element:
- Negative
margin
along the float direction: pull thefloat
element in that direction. - Negative
margin
opposite the float direction decrease the float area, causing adjacent elements to overlap thefloat
element.
圣杯布局:
- HTML:
.middle
first. - Padding:
padding-left
andpadding-right
to.container
,min-width: 2 * (leftWidth + rightWidth)
to.container
. - Float:
float: left
to.left
,.middle
and.right
(Currently,.middle
in row 1,.left
and.right
in row 2). - Negative margin:
margin-left: -100%
to.left
,margin-right: -rightWidth px
to.right
(Pull them up to same row with.middle
). - Move:
right: leftWidth px
to.left
(Adjust.left
position).
<div class="container">
<div class="middle"></div>
<div class="left"></div>
<div class="right"></div>
</div>
.container {
padding: 0 200px 0 300px; /* padding-left = .left width, same to .right */
}
.container .middle {
float: left;
width: 100%;
background-color: violet;
}
.container .left {
position: relative;
right: 300px;
float: left;
width: 300px;
margin-left: -100%;
background-color: darkblue;
}
.container .right {
position: relative;
float: left;
width: 200px;
margin-right: -200px;
background-color: red;
}
Grid Three Column
Three column layout allows full-width content:
.container {
display: grid;
grid-template-columns: 1fr min(60ch, calc(100% - 64px)) 1fr;
grid-column-gap: 32px;
}
.container > * {
grid-column: 2;
}
.full-bleed {
grid-column: 1 / -1;
width: 100%;
}
Multiple Column Pattern
Multiple column
layout:
columns
:<'column-width'> || <'column-count'>
.- 分栏实际数目 = .
column-width
:auto | <length>
, 期望分栏宽度.column-count
:auto | <integer>
, 期望分栏数目.column-gap
:normal | <length-percentage>
, 分隔间隙.column-rule
:<'column-rule-width'> || <'column-rule-style'> || <'column-rule-color'>
, 分隔线.column-rule-width
(<line-width>
):medium | thin | thick | <length>
.column-rule-style
(<line-style>
):none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset
.column-rule-color
:currentcolor | <color>
.column-span
:none | all
, 子元素宽度.column-fill
:balance | balance-all | auto
, 子元素分布.break-inside
:auto
: Allows break.avoid
: Avoids break.
.three-column {
column-gap: 1em;
padding: 1em;
column-count: 3;
}
.three-column > .last-child {
column-span: all;
}
Flex Pattern
Flex Box Width
最终尺寸计算:
- 优先级: 最大最小尺寸 > 弹性增长或收缩 > 基础尺寸.
- When there is free space left: used size = .
- When there is not enough space: used size = .
flex-basis | width | 基础尺寸 |
---|---|---|
set | x | flex-basis |
auto | set | width |
auto | auto | 最大内容宽度 |
min-width | width | 最小尺寸 |
---|---|---|
set | x | min-width |
auto | set | min(width , 最小内容宽度) |
auto | auto | 最小内容宽度 |
.container {
display: flex;
}
.initial {
/* width: 100px~200px */
flex: initial;
width: 200px;
min-width: 100px;
}
.none {
/* width: 200px */
flex: none;
width: 200px;
}
.flex1 {
/* width: left width * 1/3 */
flex: 1;
}
.flex2 {
/* width: left width * 2/3 */
flex: 2;
}
Flex Shorthand Property
flex
= none | [<'flex-grow'> <'flex-shrink'>? || <'flex-basis'>]
:
flex-grow
:<number>
.flex-shrink
:<number>
.flex-basis
:content | <'width'>
.flex: initial
: 属性默认值, 元素会根据自身宽高设置尺寸. 它会缩短自身以适应容器, 但不会伸长并吸收 flex 容器中的额外自由空间来适应容器, equal toflex: 0 1 auto
.flex: none
: 元素会根据自身宽高来设置尺寸. 它是完全非弹性的: 既不会缩短, 也不会伸长来适应容器, equal toflex: 0 0 auto
.flex: auto | <'width'>
: 元素会根据自身的宽度与高度来确定尺寸, 但是会自行伸长以吸收 flex 容器中额外的自由空间, 也会缩短至自身最小尺寸以适应容器, equal toflex: 1 1 auto | 1 1 <'width'>
.flex: <number>
: 元素会被赋予一个容器中自由空间的指定占比, equal toflex: <number> 1 0%
.
flex: none
: 适合设置在内容不能换行显示的小控件元素上, e.g<button>
.flex: auto
: 适合基于内容动态适配的布局.flex: 0
: 适用场景较少, 适合设置在替换元素的父元素上.flex: 1
: 适合等分布局.
Flex Children Display
Flexbox 会改变子元素 display
属性值:
Initial Display | Flex Children Display |
---|---|
inline /inline-block /block | block |
flow-root | flow-root |
list-item | list-item |
inline-table /table | table |
table-* | block |
inline-flex /flex | flex |
inline-grid /grid | grid |
Flexbox 子元素:
- 均为块级元素:
vertical-align
无效化.- 裸文本子元素会变为匿名块级元素 (Text nodes and pseudo elements can be flex children).
float
无效化.margin
不合并.- 支持
z-index
(包括position: static
子元素):z-index
不为auto
时创建层叠上下文. absolute
定位子元素会脱离弹性布局.
Flex Flow
flex-flow
: <'flex-direction'> || <'flex-wrap'>
.
Flex Direction
flex-direction
:
row
.row-reverse
.column
.column-reverse
.
flex-direction
will change flex alignment direction and start line:
Flex Wrap
flex-wrap
:
nowrap
: 不换行.wrap
: 换行.wrap-reverse
.
Flex Alignment
Flex Parent Alignment
justify-content
, defines alignment along main axis:normal
: items packed in default position.stretch
: behaves asflex-start
(stretching in main axis controlled byflex
).space-between
/space-around
/space-evenly
.center
/start
/end
/flex-start
/flex-end
.left
/right
.
align-items
, defines alignment (align-self
) for cross axis:normal
: behaves asstretch
/start
.baseline
.stretch
.center
/start
/end
/self-start
/self-end
/flex-start
/flex-end
.
align-content
, aligns flex container's lines within when there is extra space in the cross-axis:normal
: items packed in default position.baseline
.stretch
/space-between
/space-around
/space-evenly
.center
/start
/end
/flex-start
/flex-end
.
*-content
adjust parent padding,*-items
and*-self
adjust children margin.
Flex Children Alignment
align-self
:auto
: computes to parentalign-items
value.normal
: behaves asstretch
/start
.baseline
.stretch
.center
/start
/end
/self-start
/self-end
/flex-start
/flex-end
.
order
:<number>
, 显示顺序, 初始为0
.
Flex Margin Alignment
Aligning with auto margin
:
<div class="parent">
<div class="child"></div>
</div>
<style>
.parent {
display: flex;
}
.child {
/* This will push child to the right of parent border */
margin-left: auto;
}
</style>
最后一行左对齐:
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.list {
margin: 10px;
}
.list:last-child {
margin-right: auto;
}
Flex Centering Alignment
/* 子元素全部居中对齐 */
.vertical-container {
display: flex;
align-items: center;
justify-content: center;
height: 300px;
}
.layer {
display: flex;
flex-grow: 1;
flex-direction: row;
align-items: center;
justify-content: flex-start;
margin: 5px;
background-color: #fff;
border: 1px solid #000;
}
Flexbox Pseudo Element
Set flex
to pseudo elements of flex box
will change width of pseudo elements.
.flex {
display: flex;
}
.flex::before {
position: relative; /* no need for absolute position */
display: block;
}
Fixed Sidebar Flexbox
<body>
<aside></aside>
<main></main>
</body>
body {
display: flex;
height: 100vh;
margin: 0;
}
aside {
flex: 0 0 auto; /* inflexible */
}
main {
flex: 1 1 auto; /* auto flexible */
overflow: auto;
}
Flex Reference
Grid Pattern
Grid Box Width
Grid Item Automatic Minimum Size
Grid item default min-width
is set to auto
,
grid item can't be smaller than its children:
<div class="grid">
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
<div class="item">
<p>Very very very very very long sentence.</p>
</div>
</div>
<style>
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px;
}
/**
* Grid item default `min-width` is `auto`,
* 导致 grid item 内的段落完整显示整行长句.
*/
.item {
border: 1px solid red;
}
/**
* Grid item 内的段落正常截断.
*/
.item-fixed {
/* Method 1 */
min-width: 0;
/* Method 2 */
overflow: hidden;
}
p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
Grid Property
Parent property:
grid
:grid-template
:grid-template-rows
.grid-template-columns
.grid-template-areas
.
grid-auto-rows
.grid-auto-columns
.grid-auto-flow
.
gap
:row-gap
.column-gap
.
place-content
:align-content
.justify-content
.
place-items
.align-items
.justify-items
.
Children property:
grid-area
:grid-row
:grid-row-start
.grid-row-end
.
grid-column
:grid-column-start
.grid-column-end
.
place-self
:align-self
.justify-self
.
.container {
grid-template-areas:
'header header header'
'advert content content'
'footer footer footer';
grid-template-rows: 1fr 1fr 1fr;
grid-template-rows: minmax(90px, 1fr);
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
place-items: end center;
}
.item {
grid-area: footer;
grid-row: start / end; /* 2 / -1 */
grid-column: start / end;
place-self: end center;
}
Grid Data Types
Grid Breadth Types
<track-breadth>
:
<flex>
:<number>fr
, fraction.<length-percentage>
.min-content
.max-content
.auto
.
<inflexible-breadth>
:
<length-percentage>
.min-content
.max-content
.auto
.
<fixed-breadth>
:
<length-percentage>
.
Grid Size Types
<track-size>
:
<track-breadth>
.minmax(<inflexible-breadth>, <track-breadth>)
.fit-content(<length-percentage>)
.
<fixed-size>
:
<fixed-breadth>
.minmax(<fixed-breadth>, <track-breadth>)
.minmax(<inflexible-breadth>, <fixed-breadth>)
.
Grid Repeat Types
<track-repeat>
:
repeat([<integer [1,∞]>], [<line-names>? <track-size>]+ <line-names>?)
.
<fixed-repeat>
:
repeat([<integer [1,∞]>], [<line-names>? <fixed-size>]+ <line-names>?)
.
<auto-repeat>
:
repeat([auto-fill | auto-fit], [<line-names>? <fixed-size>]+ <line-names>?)
.
<name-repeat>
:
repeat([auto-fill | <integer [1,∞]>], <line-names>+)
.
Grid Line Types
<grid-line>
:
auto
.<custom-ident>
[<integer> && <custom-ident>?]
.[span && [<integer> || <custom-ident>]]
.
Responsive Grid Layout
Explicit Responsive Grid Layout
fit-content(limit)
:clamp([min-content | min-width], limit, max-content)
.minmax([<fixed-breadth> | <inflexible-breadth>], [<track-breadth> | <fixed-breadth>])
.repeat([<integer [1,∞]> | auto-fill | auto-fit], [<track-size> | <fixed-size>]+)
.
.container {
display: grid;
grid-template-columns: fit-content(var(--sidebar-max, 20ch)) minmax(50%, 1fr);
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min, 30ch)), 1fr));
}
Implicit Responsive Grid Layout
grid-auto-rows
/grid-auto-columns
:
<track-size>+
.- Control implicitly-created grid track (row/column) size.
<div class="container">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item class="implicit">5</item>
</div>
<style>
.container {
display: grid;
grid-template: 1fr 1fr / 1fr 1fr;
/* 隐式网格高度为 60px */
grid-auto-rows: 60px;
}
</style>
<div class="container">
<item class="item-a">a</item>
<item class="item-b">b</item>
</div>
<style>
.container {
display: grid;
grid-template: 1fr 1fr / 1fr 1fr;
/* 隐式网格宽度为 60px */
grid-auto-columns: 60px;
}
.item-b {
/* 超出网格列数, 隐式网格创建 */
grid-column: 3 / 4;
background-color: rgb(255 255 0 / 50%);
}
</style>
grid-auto-flow
:
[row | column] || dense
.- Change auto-placement algorithm:
control exactly how auto-placed items get flowed into grid container,
like
flex-direction
for flex container.
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 1fr;
grid-auto-flow: dense;
grid-gap: 1em;
}
Named Grid Layout
Grid Lines
grid-row
and grid-column
change start and end of <grid-line>
will refactor grid item's size and location:
.main {
display: grid;
grid-template-rows: [header] 100px [body] auto;
grid-template-columns: [l-gutter] 1fr [sidebar] 4fr [content] 8fr [r-gutter] 1fr;
gap: 1rem 2rem;
}
.header {
grid-row: header;
grid-column: sidebar / right-gutter;
}
.sidebar {
grid-row: body;
grid-column: sidebar;
}
.content {
grid-row: body;
grid-column: content;
}
隐式网格线:
<custom-ident>
: 当<custom-ident>
不存在时, 会尝试匹配<custom-ident-start>
或者<custom-ident-end>
.<integer> && <custom-ident>
: 当第<integer>
个<custom-ident>
不存在时, 会在网格容器后方额外创建隐式网格.span && <custom-ident>
: 当<custom-ident>
不存在时, 会在网格容器前方或者后方额外创建隐式网格.
.container {
display: grid;
grid:
'. . .' 1fr
'. a .' 1fr
'. . .' 1fr / 1fr 1fr 1fr;
}
.item {
grid-area: a;
grid-area: a / a / a / a;
grid-area: a-start / a-start / a-end / a-end;
}
.container {
display: grid;
grid-template-columns: [a] 80px [b] auto [c] 100px [d];
}
.item {
/**
* .container: [a] 80px [b] auto [c] 100px [d] auto [b] auto [b] auto [b]
* .item: [c] 100px [d] auto [b] auto [b] auto [b]
*/
grid-column: b 4 / c;
}
.container {
display: grid;
grid-template-columns: [a] 80px [c] auto [c] 100px [d] auto auto;
}
.item {
/**
* .container: [b] auto [a] 80px [c] auto [c] 100px [d] auto auto
* .item: [b] auto [a] 80px [c] auto [c] 100px [d]
*/
grid-column: span b / 4;
}
Extending elements beyond the content area with named grid lines:
.content {
--gap: clamp(1rem, 6vw, 3rem);
--full: minmax(var(--gap), 1fr);
--content: min(50ch, 100% - var(--gap) * 2);
--popup: minmax(0, 2rem);
--feature: minmax(0, 5rem);
display: grid;
grid-template-columns:
[full-start] var(--full)
[feature-start] var(--feature)
[popup-start] var(--popup)
[content-start] var(--content) [content-end]
var(--popup) [popup-end]
var(--feature) [feature-end]
var(--full) [full-end];
}
.content > * {
grid-column: content;
}
.popup {
grid-column: popup;
}
.feature {
grid-column: feature;
}
.full {
grid-column: full;
}
Grid Areas
- 网格线自动命名:
areaName-start
/areaName-end
.
.container {
grid-template: 1fr 1fr 1fr 1fr / 1fr 1fr 1fr;
grid-template:
'grape grape grape' 1fr
'apple orange orange' 1fr
'apple orange orange' 1fr
'banana banana banana' 1fr
/ 1fr 1fr 1fr;
grid-template:
[row-name1-start] 'grape grape grape' 1fr [row-name1-end row-name2-start]
'apple orange orange' 1fr [row-name2-end]
'apple orange orange' 1fr [row-name3-end]
[row-name4-start] 'banana banana banana' 1fr [row-name4-end]
/ [col-name-start] 1fr [col-name-end] 1fr 1fr;
grid-template-areas:
'grape grape grape'
'apple orange orange'
'apple orange orange'
'banana banana banana';
}
.grape {
grid-area: grape;
}
.apple {
grid-area: apple;
}
.orange {
grid-area: orange;
}
.banana {
grid-area: banana;
}
Grid Gap
CSS Box Alignment Module Level 3
统一了分栏布局, 弹性布局, 网格布局的 gap
属性:
gap
:<'row-gap'> <'column-gap'>?
.row-gap
:normal | <length-percentage>
.column-gap
:normal | <length-percentage>
.
Grid Alignment
justify-content
/align-content
content within element, attach to parent css selector (effectively adjustspadding
of parent)justify-items
/align-items
align items inside box, attach to parent css selector (effectively adjustsmargin
of children)justify-self
/align-self
align element within parent, attach to children css selector (effectively adjustsmargin
of children)place-content
:<'align-content'> <'justify-content'>?
.place-items
:<'align-items'> <'justify-items'>?
.place-self
:<'align-self'> <'justify-self'>?
.
justify-items
, defines the defaultjustify-self
for all items:normal
: behaves asstretch
/start
.baseline
.stretch
.center
/start
/end
/self-start
/self-end
/flex-start
/flex-end
.left
/right
.
justify-self
:auto
: computes to parentjustify-items
value.normal
: behaves asstretch
/start
.baseline
.stretch
.center
/start
/end
/self-start
/self-end
/flex-start
/flex-end
.left
/right
.
Grid Pseudo Element
Adding background
and border
is a missing feature of
CSS Grid specification,
you can styling empty grid cells and areas with
generated pseudo elements:
.grid::after {
z-index: -1;
grid-row: 1 / 4;
grid-column: 2 / 5;
content: '';
background-color: rgb(214 232 182 / 30%);
border: 5px solid rgb(214 232 182);
}
Implement fancy <h1>
header:
h1.lines {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 1em;
text-align: center;
}
@supports (display: grid) {
h1.lines::before,
h1.lines::after {
align-self: center;
content: '';
border-top: 1px solid black;
}
}
Conditionally styling selected elements in grid container:
<main>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" checked />
<input type="checkbox" checked />
<input type="checkbox" checked />
<input type="checkbox" checked />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</main>
<style>
main {
display: grid;
grid: repeat(5, 60px) / repeat(7, 60px);
place-items: center center;
margin: 0;
}
input {
display: grid;
width: 40px;
height: 40px;
margin: 0;
appearance: none;
cursor: pointer;
background: #ddd;
border-radius: 20px;
}
input:not(:nth-of-type(7n + 1))::before,
input:nth-of-type(n + 8)::after {
z-index: -1;
grid-area: 1/1;
pointer-events: none;
content: '';
border-radius: 20px;
}
input:not(:nth-of-type(7n + 1))::before {
transform: translateX(-60px);
}
input:nth-of-type(n + 8)::after {
transform: translateY(-60px);
}
input:checked {
background: limegreen;
}
/* a box's right borders */
input:not(:nth-of-type(7n)):checked + input:checked::before {
background: limegreen;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
/* a box's bottom borders */
input:nth-last-of-type(n + 8):checked + * + * + * + * + * + * + input:checked::after {
background: limegreen;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
/* a box's adjacent (right side) box's left borders */
input:not(:nth-of-type(7n)):checked + input:checked + input::before {
background: limegreen;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* a box's adjacent (below) box's top borders */
input:not(:nth-of-type(7n)):checked + * + * + * + * + * + * + input:checked + input::before {
background: limegreen;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
/* a box's (in last column) left borders */
input:nth-of-type(7n-1):checked + input:checked {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* a box's (in last column) adjacent (below) box's top borders */
input:nth-of-type(7n):checked + * + * + * + * + * + * + input:checked {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>
Grid System
- Must have different traits at different sizes.
- Must be fluid between breakpoints.
- Must have enough control to decide which columns will transform and at which point.
- Classes should ideally still make sense at all breakpoints.
Grid Reference
- Grid complete guide.
Masonry Pattern
- Chrome debates on masonry layouts.
- Webkit invents masonry layouts for CSS grid level 3.
Alignment Pattern
Height Alignment Pattern
border
simulation.- Negative
margin
. absolute
element:.absolute { top: 0; bottom: 0; }
使所有子元素 (absolute
) 与父元素 (relative
) 等高.table
layout:display: table-cell
默认等高.flex
layout:flex
items 默认拉伸至盒子高度.grid
layout:grid
items 默认等高.
Border Simulation Height Alignment
/* 导航背景区 border 创建 */
.box {
background-color: #f0f3f9;
border-left: 150px solid #333;
}
/* 清除浮动影响 */
.box::after {
display: block;
clear: both;
content: '';
}
/* 布局主结构 */
.box > nav {
float: left;
width: 150px;
margin-left: -150px;
}
.box > section {
overflow: hidden;
}
Negative Margin Height Alignment
.column-box {
overflow: hidden; /* hidden overflow background */
}
/* 视觉等高布局 */
.column-left,
.column-right {
padding-bottom: 9999px;
margin-bottom: -9999px;
}
Layout Height Alignment
.table {
display: table;
overflow: hidden;
.left {
display: table-cell;
width: 200px;
background: #4caf50;
}
.right {
display: table-cell;
width: 800px;
background: #99afe0;
}
}
.flex {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
.left {
flex: 200px 0 0;
background: #4caf50;
}
.right {
flex: auto 1 0;
background: #99afe0;
}
}
.grid {
display: grid;
grid-template-columns: 200px auto;
align-items: stretch;
.left {
background: #4caf50;
}
.right {
background: #99afe0;
}
}
Centering Pattern
Horizontal Centering Pattern
Horizontal Centering Inline Element
text-align: center
.flex
.grid
.
.quote {
text-align: center;
}
Horizontal Centering Block Element
- Auto
margin
. flex
.grid
.
.row {
width: 100%;
max-width: --var(row-max-width);
margin: 0 auto;
}
.container {
max-width: 1024px;
margin: 0 auto;
}
父元素 float
, 父子元素 relative
:
.container {
position: relative;
left: 50%;
float: left;
}
.container ul {
position: relative;
left: -50%;
}
Vertical Centering Pattern
Vertical Centering Inline element
line-height
.vertical-align: middle
:- 作用机制: 对齐基线 (
baseline
) 往上 1/2x-height
高度 (即小写字母x
交叉点处). - 作用环境: parent element
line-height
===height
. - 作用对象: children
inline
/inline-block
/table-cell
element.
- 作用机制: 对齐基线 (
- Vertical parent
padding
. flex
.grid
.
Button label (<a>
) vertical alignment
(行内块居中法:
a.button::before {
display: inline-block;
height: 16px;
vertical-align: middle;
content: '';
}
Vertical Centering Block element
top
+translateY
.vertical-align: middle
+display: table-cell
: 表格单元居中法.- Vertical
margin
. - Vertical
padding
. flex
.grid
.
.viewport-centered-block {
width: 18em;
margin: 50vh auto 0;
transform: translateY(-50%);
}
.form-item-label {
display: flex;
flex-direction: row;
align-items: center;
}
Mixing Centering Pattern
.box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
backface-visibility: hidden; /* Remove blurry in WebKit browsers */
transform-style: preserve-3d; /* Remove blurry in WebKit browsers */
}
.dialog {
position: absolute;
inset: 0;
width: fit-content;
height: fit-content;
margin: auto;
}
Centering Pattern Reference
- Centering layout complete guide.