CSS中auto值你知多少
试问一下,你可知道CSS中有多少个属性呢?说实在的还真答不上来。根据 CSS Reference 统计来看,差不多有200个属性(不包括浏览器自带的私有属性)。在这些CSS属性中,很多属性的值是关键词 auto
,比如我们熟悉的margin
、padding
和overflow
等。虽然他们的值都可以取值auto
,但是差别却很大。CSS就是这么的神奇,充满魔性,如果不了解的话,会无声无息地将你带入坑中。另外一点,搞懂CSS中会让你很兴奋,至少我是这样的。今天就和大家一起来聊聊auto
。
为什么要聊auto
事实上,我无法准确无误地回答出,CSS中有多少属性的值可以取值为
auto
!
简单地数了一下浏览器自带的属性,可设置值为auto
的,大约有70
个左右,不同的浏览器、不同的元素标签都会有所差异:
如果你有足够的精力和时间,不仿查阅一下W3C规范中各大模块的属性,并且列出能取值为auto
的属性。
话说回来,今天我们要聊的并不是CSS中有多个属性可取值是auto
,而是要和大家一起探讨的是 auto
在CSS是如何工作的,使用auto
的细节是什么,以及我们如何最大限度地利用好auto
。简单地说吧,CSS中不同属性取值为auto
时起的作用不同,只有知道其相关的细节,才能用好!比如说:width
和margin
都可以取值为auto
,但它们是如何计算的?在不同的环境中会有何差异?如果你不能很清楚的说清楚的话,那么接下来的内容就非常值得你花时间去阅读。
初始值auto
在CSS中基本上每个属性都会有一个初始值(**initial**
),在W3C规范中,介绍每个属性的语法规则时,不难发现其初始值是什么。随便拿个属性来举例,比如我们熟悉的width
属性:
CSS中属性的初始值也被称为默认值。简单地说,如果在CSS中没有显式的给属性设置值,那么浏览器客户端将会取该属性的初始值进行渲染。比如下面这个示例:
<!-- HTML -->
<div></div>
比如上面的<div>
元素,我们并不有显式的给它添加width
的值。那么这个时候,width
的取值会是auto
。
CSS属性的初始值还有另一个作用,就是覆盖已设置的样式值。比如这样的一个场景,你显式的给div
设置了width
的值为50vw
,但在另一个场景中,你需要的宽度不是50vw
,而是希望能通过客户端自己行计算,那么这个时候,采用width
的初始值来覆盖是一个比较好的选择:
<!-- HTML -->
<div></div>
<div class="box"></div>
// CSS
div {
width: 50vw;
}
.box {
width: auto;
}
这是一个很简单的示例:
这个示例涉及到了CSS最基础的一个概念,也是一个很重要的概念,即 CSS的层叠,感兴趣的话可以阅读《CSS层叠和继承》一文进行了解。
前面提到过,CSS有很多属性的初始值是关键词 auto
。从字面上来解释的话就是自动。比如上面的示例中,当div
的width
未显式或显式设置值为auto
时,该元素的width
将会根据它的容器元素的width
来做计算。
在上例中,尝试着水平拖动右下角的滑块,你会发现div.box
的width
会自动计算,注意,在div.box
中并未显式设置width
的值(默认取值为auto
)。从表现行为上来看,他似乎和div.box
的width
设置了100%
并没差异:
这里要特别提出的是,上面示例演示的只是最基本的效果(仅仅是众多结果之一)。你可以尝试着对div.wrapper
做个调整,比如将其display
设置为flex
或grid
,你会发现同样width
为auto
的div.box
会有所差异:
当设置为display: grid
,对应的grid-template-columns
未显式设置值的话,那么取值同样会是auto
,这个时候div.box
的width
值相当于容器的宽度。发果你显式地设置了grid-template-columns
的值,那么取值为width:auto
的div.box
对应的宽度就是grid-template-colummns
中设置的值,比如:
当display
设置的值不同的时,元素自身的格式化上下文就会发生变化,也同样的会影响到其子元素。具体有关于这方面的介绍可以阅读:
- 视觉格式化模型
- 如何理解CSS的
display
属性 - What Happens When You Create A Flexbox Flex Container?
- Understanding CSS Grid: Creating A Grid Container
上面我们看到的仅是CSS中width
取值为auto
的示例,这个示例再次告诉我们看上去非常的简单的auto
属性值在CSS的世界中并不简单。而是极其的复杂,除了不同属性取值为auto
表现不一样之外,即使同一个属性取值为auto
,在不同的上下文表现也会不一样。
在一篇文章中我们无法把所有取值为
auto
的属性聊清楚,接下来只会以一些比较经典的属性来举例。
盒模型属性中的auto
CSS盒模型主要用来设置元素框的尺寸,每个元素框的尺寸大小直接会影响到Web布局效果。虽然CSS盒模型中的每个属性对盒子尺寸有着决定性的作用,但是能取值为auto
的属性主要有width
、height
和margin
。
随着CSS逻辑属性模块的到来,CSS的盒模型也将有着明显的变革:
可以用张图来描述,更具对比性:
就上图而言,不管是以前的物理属性还是现在的逻辑属性,可以取值为auto
的主要有:
物理属性 | 逻辑属性(horizontal-tab ) |
逻辑属性(vertical-lr ) |
逻辑属性(vertical-rl ) |
备注 |
---|---|---|---|---|
width |
inline-size |
block-size |
block-size |
初始值为auto |
height |
block-size |
inline-size |
inline-size |
初始值为auto |
margin-top |
margin-block-start |
margin-inline-start |
margin-inline-start |
可以取值为auto |
margin-right |
margin-inline-end |
margin-block-end |
margin-block-start |
可以取值为auto |
margin-bottom |
margin-block-end |
margin-inline-end |
margin-inline-end |
可以取值为auto |
margin-left |
margin-inline-start |
margin-block-start |
margin-block-end |
可以取值为auto |
top |
inset-block-start |
inset-inline-start |
inset-inline-start |
初始值为auto |
right |
inset-inline-end |
inset-block-end |
inset-block-start |
初始值为auto |
bottom |
inset-block-end |
inset-inline-end |
inset-inline-end |
初始值为auto |
left |
inset-inline-start |
inset-block-start |
inset-block-end |
初始值为auto |
其中top
、right
、bottom
和left
以及它们所对应的逻辑属性是隶属于 **CSS Positioned Layout Module Level 3**模块,主要用来给定位元素设置位置的。而width
和height
以及它们所对应的逻辑属性主要是用来设置元素尺寸大小。设置元素尺寸大小除了width
、height
之外,它还有min-width/height
和max-width/height
以及相应的逻辑属性:
物理属性 | 逻辑属性(horizontal-tab ) |
逻辑属性(vertical-lr ) |
逻辑属性(vertical-rl ) |
备注 |
---|---|---|---|---|
min-width |
min-inline-size |
min-block-size |
min-block-size |
初始值为auto |
min-height |
min-block-size |
min-inline-size |
min-inline-size |
初始值为auto |
max-width |
max-inline-size |
max-block-size |
max-block-size |
初始值为none ,不可取值为auto |
max-height |
max-block-size |
max-inline-size |
max-inline-size |
初始值为none ,不可取值为auto |
另外有一点要特别的提出,CSS的逻辑属性和CSS的书写模式有着紧密的关系,具体的可以阅读《Web中向左向右》一文。
先来看第一部分,设置元素尺寸相关的属性。
取值为auto
时对元素尺寸大小的影响
特别声明:接下来的内容还是以物理属性为主。
在CSS中,CSS的width
、height
、min-width
、min-height
、max-width
和max-height
都可以用来决定元素尺寸大小。其中除了max-width
和max-height
两个属性不能取值为auto
之外,其他都可以。
width
取值为auto
width
取值为auto
时,其计算和布局模块(即CSS视觉格式化模型)有关系。
为了不让事情变得复杂化,我们先来看大家最熟悉的块元素,比如使用最多的div
。它的初始宽度是auto
(在未显式设置width
情况下),那么它的宽度会占据整个容器的水平空间。
根据CSS的规范我们可以得知:
块元素框宽度 = margin-left + border-left + padding-left + width(内容宽度) + padding-right + border-right + margin-right
我们来看一个简单的示例:
正如上面的示例所示,当一个块元素的width
取值为auto
时,即使显式设置了margin
、border
和padding
值,元素也不会溢出其父容器。此时元素内容所占的宽度超越元素自身的宽度(大于元素内容自身的宽度)时,内容将会断行,比如:
就此例来说,命名为div.width
的元素,其width
取值为初始值,即auto
。其最终的width
计算出来的值大约是330px
:
我们来看一下div.width
元素的width
是怎么来的:
❯ div.width元素的父容器div.box,其宽度是492px,去除border的值,可用空间是490px
❯ div.width元素显式的设置了margin-left、margin-right、border-left、border-right、padding-left和padding-right
❯ margin-left = margin-right = 30px
❯ border-left = border-right = 20px
❯ padding-left = padding-right = 30px
❯ div.width的可用空间 = 490 - 60 - 40 - 60 = 330px
如果你熟悉CSS的话,应该知道CSS的box-sizing
对元素尺寸大小是有一定影响的,比如:
用个简单的示例来演示:
我们在上面的示例上稍作调整:
正如上面所说,box-sizing
将会改变元素的width
,也将会影响width:auto
的计算结果:
上面我们看到的是块元素width
取值为auto
的计算方式。接下来,我们来看看元素是内联或内联块元素width
取值为auto
的计算方式。在HTML中,行内元素有很多,比如span
、strong
等,另外还可以在元素上显式设置display
来改变元素的上下文格式。同样在上面的示例基础上,显式的设置div.width
元素的display
来将块元素改成行内或内联元素:
不难发现,内联元素width
取值为auto
的时候和块元素的计算方式是不一样的。
❯ border-left + padding-left + 内联元素文本内容所撑开的宽度 + padding-right + border-right
浏览器计算出来的结果如下:
前面提到过,CSS布局模块对width
取值为auto
的元素有很大的影响,除了上例中所演示的效果之外,其父容器的上下文格式化也会对其有影响。简单地说,父容器的display
的取值会对width
取值为auto
时有一定的影响。我们在上面的示例基础上稍做处理,将display
的设置移到其父元素上:
你可以尝试着在上例上改变display
下拉选项的值浏览示例的效果,将不难发现,当display
取值为flex
或inline-flex
的时,div.width
的表现行为和内联元素width
为auto
相似。至于为什么会如此,那就需要对Flexbox有所了解了,后面的内容中,将会和大家一起聊聊这方面的内容。
你可能已经发现了,对于块元素上width
取值为auto
时,看上去和width: 100%
有点类似,但其中还是有很大的不同:
- 不会包含
margin-left
和margin-right
- 即使有足够的内容,也不会撑破容器
如果显式在元素上设置了width: 100%
,其计算方式是有所不同的,而且很容易撑破父容器,影响整个布局,比如下面这个示例:
尝试着调整示例中的各个参数,你会发现width:auto
和width: 100%
的差异的:
从《CSS 的值和单位》一文中我们可以获知,width: 100%
是相对于其父容器的width
来计算的。不过有一点需要注意,如果容器是一个Flex容器,即使元素显式设置了width: 100%
,也有差异的。它将会是这样的一个过程:元素先根据容器的宽度计算出自身的宽度,但Flex项目总宽度超过Flex容器宽度时,那么Flex项目会进行收缩,不让元素溢出容器:
这个计算是个复杂的过程,涉及到的知识点较多,如果你对这方面感兴趣的话,可以阅读:
另外,Grid容器和Flex容器有点类似,当将元素的容器显式的设置成Grid容器,并且显式的通过grid-template-columns
指定列的宽度,比如:
.box {
grid-tempate-columns: repeat(2, 1fr)
}
这个时候,即使元素显式设置为width: 100%
其实际宽度还是会做出调整:
上面示例中使用的是 CSS Grid带来的新单位,即分数单位fr
,具体怎么使用这里不做阐述,感兴趣的可以自己去做相关的了解。我们再来调整一下示例的代码,将上面的1fr
换成具体的长度单位值,比如:
.box {
grid-tempate-columns: 1fr 200px;
}
这个时候div.percentage
(显式设置了width: 100%
),其实际计算出来的宽度是200px
(在box-sizing: border-box
)下:
CSS中Flexbox和Grid布局中,有关于Flex项目或Grid项目的计算是件复杂的事情,这里不想用过多的篇幅来阐述这方面的知识,如果你对这方面感兴趣的话,建议你持续关注 Flexbox vs Grid 这个话题的相关更新。
height
取值为auto
元素的height
到值为auto
表现行为和width
取值为auto
有所差异。不管是块元素还是行内元素,元素设置height
为auto
的时候,首先height
(内容高度)将会根据内容所占的高度来计算,而元素的盒子高度是:
块元素框高度 = margin-top + border-top + padding-top + height(内容高度) + padding-bottom + border-bottom + margin-bottom
比如下面这个示例:
可以尝试着在上面的示例中添加内容,你会发现div.element
元素的高度也会随着内容增加而改变:
这里需要特别的注意,文本相关的属性设置,比如font-family
、font-size
和line-height
会对auto
计算出来的值有所影响。
有关于line-height
相关的介绍,可以阅读《深入了解CSS字体度量,行高和vertical-align
》一文。
对于行内元素(或display: inline
的元素),元素的height
(内容区域高度)会是auto
,表现行为和块元素有点类似,都是依赖元素的内容来撑开。
你会发现,inline
的元素和inline-block
、inline-flex
以及inline-grid
还是有所差异的:
注意,
inline
元素的渲染行为并不是一个Bug,它的特性就是如此。
同样的,容器上下文格式对于元素取值height: auto
的计算也会有影响,我们主要来看Flexbox和Grid上下文环境:
正如上面示例所示,在Flex容器或Grid容器中的元素会被拉伸填充整个容器,看上去有点类似于元素设置了height: 100%
。但两都还是有所差异的,比如下图所示的测试结果:
在Flex容器(或Grid容器)中的Flex项目(Grid项目),margin-top
和margin-bottom
的值对于height: auto
的计算是有影响的:
除此之外,在Grid上下文中,Grid容器的grid-template-rows
设定的值对于Grid项目height: auto
的计算也一定的影响。
min-width/height
取值为auto
在CSS中,除了width
和height
之外,还可以使用min-width
和min-height
来设置元素框的尺寸。从前面的内容我们可以获知,min-width
和min-height
的初始值也是auto
。换句话说,也可以给这两个属性显式的设置值为auto
。但不同的时,如果不受布局模块影响的话,min-width
和min-height
的auto
计算出来的值是0
。有关于这一点,W3C规范中有一段这样的描述:
For
min-width/min-height
, specifies an automatic minimum size. Unless otherwise defined by the relevant layout module, however, it resolves to a used value of 0. For backwards-compatibility, the resolved value of this keyword is zero for boxes of all [CSS2] [display types]//www.w3.org/TR/css-display-3/#display-type): block and inline boxes, inline blocks, and all the table layout boxes. It also resolves to zero when no box is generated.
flex-basis
取值为auto
flex-basis
是Flexbox中的一个属性,主要用来指定Flex项目在主轴方向的初始大小。如果不使用box-sizing
改变盒模型的话,这个属性就决定了Flex项目的框大小。
在Flexbox中flex-basis
指定的是主轴方向的初始值。简单地说,除了auto
和content
,它都以与水平书写模式中width
相同的方式解析(除了width
值设置为auto
,flex-basis
设置为content
)。当然,Flexbox是纵向布局(即flex-direction
取值为column
时),flex-basis
对应的值就是height
。而且当书写模式改变时,相应的取值也会有所改变:
从上图可以获取到下面相关的信息:
- 当
flex-direction
取值为row
时,flex-basis
相当于width
- 当
flex-direction
取值为column
时,flex-basis
相当于height
在Flexbox布局中,flex-basis
属性在任何空间分配发生之前初始化Flex项目的尺寸。其初始值为auto
。如果flex-basis
的值设置为auto
,浏览器将先检查Flex项目的主尺寸是否设置了绝对值再计算Flex项目的初始值。比如说,你给Flex项目显式设置width: 200px
,那么200px
就是Flex项目的flex-basis
值。
如果Flex项目可以自动调整大小,则auto
会解析为其内容的大小,这个时候min-content
和max-content
就会起作用。此时将会把Flex项目的max-content
作为flex-basis
值。
在Flexbox布局中设置Flex项目尺寸大小时有一个隐式的公式存在:
content
➜width
➜flex-basis
简单地说,如果未显式指定flex-basis
的值,那么flex-basis
将回退到width
属性;如果未显式指定width
,那么flex-basis
将回到基于Flex项目内容的计算宽度。不过,决定Flex项目尺寸方面,还受flex
的其他两个属性flex-grow
和flex-shrink
以及Flex项目容器大小的影响。而且Flex项目最终尺寸会受min-width
和max-width
属性限制。这一点必须得注意。
上面的示例中,我们未显式给Flex项目设置width
、min-width
和flex-basis
的值,因此它们都将会以auto
值根据内容来自动计算。这里需要特别提出的是,flex-basis
是flex
其中一个属性。换句话说,如果未做任何显式设置,就相当于:flex: 0 1 auto
,即:
.item {
flex: 0 1 auto
}
// 等效于
.item {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
这里面要再次着重的提一次,Flexbox中的flex
的计算是件复杂的事情,它所涉及到的知识点和相关联的功能模块特别的多。这里不再做任何的阐述,感兴趣的话可以阅读:
在CSS中给元素框设置尺寸本来就不是件简单地事情,除了涉及到视觉格式化模型,盒模型,display
(布局模块)和逻辑属性之外,还将涉及CSS单位值,以及如何设置等知识。而且这些功能模块所牵涉的内容你应该也体会到了,就比如上面介绍的,取值为auto
对元素框大小有着什么样的影响,又是如何来选择。不容易吧。
定位模块中的auto
这里所说的定位模块主要指的是CSS的定位(position
)和层叠控制(z-index
),对应的是 **CSS Positioned Layout Module Level 3**模块。有关于这方面的基础知识和相关的细节这里不再花篇幅来阐述,如果你感兴趣的话,可以阅读下面的文章:
在这里我们主要来聊聊定位模块中相关属性取值为auto
相关的事情。比如top
、right
、bottom
和left
的初始值为auto
。接下来我要解释的事情相对来说都是定位中的一些细节,掌握这些细节让你能彻底的搞清楚定位模块。
在这一节中如何你看到
TRLB
的简写,其代表的就是定位模块中的top
(T
)、right
(R
)、bottom
(B
)和left
(L
)
在W3C规范中对TLBL
取值为auto
有过详细的阐述,这里就不累述了,感兴趣的可以查阅规范中的第八小节(Sizing and positioning details)。
CSS中position
取值为非static
时,可以对元素进行定位,其中TRBL
可以用来设置元素的偏移量:
在上例的基础上调整一下,把能取值为auto
的相关参数配置上去。示例的默认状态width
和height
值都是auto
,除此之外,在定位环境下TRBL
和margin
都可以取值为auto
:
基于该示例,按照规范中的第八小节(Sizing and positioning details)调整参数,就可以看到具体的效果。这里就不再将演示的结果贴出来了。
对齐中的auto
Web中让元素实现水平或垂直居中,我们都可以使用margin:auto
来实现,比如水平居中:
.element {
width: 30vw;
margin-left: auto;
margin-right: auto;
}
如果我们使用margin-left
、margin-right
取值auto
实现水平居中,有一个必要条件,那就是元素自身需要显式设置width
或max-width
的值。其实现过程如下:
相当于:容器剩余空间 = 容器宽度 - 元素宽度
。然后将剩余空间分成两等份,如果margin-left
和margin-right
都显式设置了auto
,那么浏览器会根据容器剩余空间进行计算,分别分给这两个属性。
在定位中,margin
取值为auto
时,同样可以让元素居中:
.parent {
position: relative;
}
.children {
position: absolute;
margin: auto
}
在绝对定位中使用margin: auto
让元素实现水平垂直居中,它有一个前提条件,那就是RTBL
的值需要显式的设置为0
,同时元素自身需要显式的设置width
和height
的值。如果未显式设置具体的值,元素将会填满整个容器。
在Flexbox中,margin: auto
同样很实用,有点类似于绝对定位。如果我们在Flex容器中,显式的给设置Flex项目设置margin
设置值auto
,它将会根据容器可用空间进行计算。将上面的示例修改成Flexbox的布局:
.parent {
display: flex;
}
.children {
margin: auto
}
margin
取值为auto
在Flexbox布局特别的实用,比如下面这样的案例:
接下来,我们再来看看margin: auto
在CSS Grid中的运用,它所起的作用和在Flexbox上的基本相似。将上例中的Flexbox布局换成Grid布局:
.parent {
display: grid;
grid-template-columns: auto;
}
.children {
margin: auto;
}
时至今日,CSS中使用Flexbox和Grid布局越来越广泛,其中最为强大的是在Flexbox或Grid布局中,我们可以使用CSS Box Alignment Module Level 3来控制Flex项目或Grid项目的对齐方式。共中align-self
和justify-self
(它们的简写属性place-self
)也可以取值为auto
。当place-self
取值为auto
时,Flex项目和Grid项目的对齐方式将会按照它的父容器设置的对齐方式来处理。我们来看看下面的示例:
background-size
和mask-size
中的auto
在CSS中,可以使用background-size
来指定背景图像的大小,使用mask-size
来指定遮罩图像的大小。这两个属性的计算原理都是相似的,而且它们都可以取值为auto
。使用auto
关键词时,要相应方向缩放图像,这样保持其固有的比例。
- 如果图像有两个固有的尺寸 (高度和宽度),它将呈现它本身的大小。
- 如果背景图像没有固有的比例和维度,然后它将以背景指定区域的大小呈现。
- 如果图像没有比例,但是存在维度,它的呈现好像
contain
就被指定一样。 - 如果有一个固有的尺寸和一个比例,他将按照其尺寸和比例呈现。
- 如果图像有一个固有的维度,但没有比例,它将按照其固有维度和对应背景指定区域的维度呈现。
如果background-size
(或mask-size
)属性的值是对值,其中一个值是auto
,另一个值是<length>
或<percentage>
则:
- 如果图像具有固有比例: 使用
length/percentage
值在相应的维度中指定呈现图像的大小,然后使用图像的比例来计算其他维度的值。所以,例如,第一个值是length
,第二值为auto
,然后图像呈现的的宽度将按照其指定的length
,图像的高度将基于图像的比例。 - 如果图像没有固有的比例: 使用
length/percentage
值在相应的维度中指定呈现图像的大小。对于另一个方向 (其中值为auto
),浏览器将使用图像的尺寸,当然前提是,存在的情况下。例如,一个 JPEG 图像有两个固有维度 (高度和宽度),所以如果高度设置为一个length
值,宽度设置为auto
,浏览器将从图像中提取的宽度,并使用它,因为它有一个这个值。但是如果图像不具有固有的宽度 (例如渐变),浏览器也将呈现同一维度作为背景指定区域。
来看一个background-size
示例:
有关于这方面的介绍,可以阅读:
overflow
取值为auto
在CSS中,当我们有一个元素时,我们应该考虑它应该包含的最小和最大内容。如果内容超过了最大值,那么就需要显示一个滚动条。在CSS实现这样的效果可以使用overflow
来控制。比如:
.box {
overflow: auto
}
当内容超过容器最大值就会出现滚动条,如果未超出就不会。比如下面这个示例:
有关于overflow
更详细的介绍还可以阅读《你所不知道的CSS Overflow Module》一文。
小结
在CSS中初始值或能取值为auto
的属性很多,在这篇文章主要和大家聊了一下常见的几个属性中auto
的具体使用。auto
值在不同的属性中所起的作用有所不同,只有了解这其中的细节都能更好的用好。如果你在这方面有更好的建议或经验,欢迎在评论中与我们一起共享。