CSS中auto值你知多少

发布于 大漠

试问一下,你可知道CSS中有多少个属性呢?说实在的还真答不上来。根据 CSS Reference 统计来看,差不多有200个属性(不包括浏览器自带的私有属性)。在这些CSS属性中,很多属性的值是关键词 auto,比如我们熟悉的marginpaddingoverflow等。虽然他们的值都可以取值auto,但是差别却很大。CSS就是这么的神奇,充满魔性,如果不了解的话,会无声无息地将你带入坑中。另外一点,搞懂CSS中会让你很兴奋,至少我是这样的。今天就和大家一起来聊聊auto

为什么要聊auto

事实上,我无法准确无误地回答出,CSS中有多少属性的值可以取值为auto!

简单地数了一下浏览器自带的属性,可设置值为auto的,大约有70个左右,不同的浏览器、不同的元素标签都会有所差异:

如果你有足够的精力和时间,不仿查阅一下W3C规范中各大模块的属性,并且列出能取值为auto的属性。

话说回来,今天我们要聊的并不是CSS中有多个属性可取值是auto,而是要和大家一起探讨的是 auto 在CSS是如何工作的,使用auto的细节是什么,以及我们如何最大限度地利用好auto。简单地说吧,CSS中不同属性取值为auto时起的作用不同,只有知道其相关的细节,才能用好!比如说:widthmargin都可以取值为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。从字面上来解释的话就是自动。比如上面的示例中,当divwidth未显式或显式设置值为auto时,该元素的width将会根据它的容器元素的width来做计算。

在上例中,尝试着水平拖动右下角的滑块,你会发现div.boxwidth会自动计算,注意,div.box中并未显式设置width的值(默认取值为auto。从表现行为上来看,他似乎和div.boxwidth设置了100%并没差异:

这里要特别提出的是,上面示例演示的只是最基本的效果(仅仅是众多结果之一)。你可以尝试着对div.wrapper做个调整,比如将其display设置为flexgrid,你会发现同样widthautodiv.box会有所差异:

当设置为display: grid,对应的grid-template-columns未显式设置值的话,那么取值同样会是auto,这个时候div.boxwidth值相当于容器的宽度。发果你显式地设置了grid-template-columns的值,那么取值为width:autodiv.box对应的宽度就是grid-template-colummns中设置的值,比如:

display设置的值不同的时,元素自身的格式化上下文就会发生变化,也同样的会影响到其子元素。具体有关于这方面的介绍可以阅读:

上面我们看到的仅是CSS中width取值为auto的示例,这个示例再次告诉我们看上去非常的简单的auto属性值在CSS的世界中并不简单。而是极其的复杂,除了不同属性取值为auto表现不一样之外,即使同一个属性取值为auto,在不同的上下文表现也会不一样

在一篇文章中我们无法把所有取值为auto的属性聊清楚,接下来只会以一些比较经典的属性来举例

盒模型属性中的auto

CSS盒模型主要用来设置元素框的尺寸,每个元素框的尺寸大小直接会影响到Web布局效果。虽然CSS盒模型中的每个属性对盒子尺寸有着决定性的作用,但是能取值为auto的属性主要有widthheightmargin

随着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

其中toprightbottomleft以及它们所对应的逻辑属性是隶属于 **CSS Positioned Layout Module Level 3**模块,主要用来给定位元素设置位置的。而widthheight以及它们所对应的逻辑属性主要是用来设置元素尺寸大小。设置元素尺寸大小除了widthheight之外,它还有min-width/heightmax-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的widthheightmin-widthmin-heightmax-widthmax-height都可以用来决定元素尺寸大小。其中除了max-widthmax-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时,即使显式设置了marginborderpadding值,元素也不会溢出其父容器。此时元素内容所占的宽度超越元素自身的宽度(大于元素内容自身的宽度)时,内容将会断行,比如:

就此例来说,命名为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中,行内元素有很多,比如spanstrong等,另外还可以在元素上显式设置display来改变元素的上下文格式。同样在上面的示例基础上,显式的设置div.width元素的display来将块元素改成行内或内联元素:

不难发现,内联元素width取值为auto的时候和块元素的计算方式是不一样的。

❯ border-left + padding-left + 内联元素文本内容所撑开的宽度 + padding-right + border-right

浏览器计算出来的结果如下:

前面提到过,CSS布局模块对width取值为auto的元素有很大的影响,除了上例中所演示的效果之外,其父容器的上下文格式化也会对其有影响。简单地说,父容器的display的取值会对width取值为auto时有一定的影响。我们在上面的示例基础上稍做处理,将display的设置移到其父元素上:

你可以尝试着在上例上改变display下拉选项的值浏览示例的效果,将不难发现,当display取值为flexinline-flex的时,div.width的表现行为和内联元素widthauto相似。至于为什么会如此,那就需要对Flexbox有所了解了,后面的内容中,将会和大家一起聊聊这方面的内容。

你可能已经发现了,对于块元素上width取值为auto时,看上去和width: 100%有点类似,但其中还是有很大的不同:

  • 不会包含margin-leftmargin-right
  • 即使有足够的内容,也不会撑破容器

如果显式在元素上设置了width: 100%,其计算方式是有所不同的,而且很容易撑破父容器,影响整个布局,比如下面这个示例:

尝试着调整示例中的各个参数,你会发现width:autowidth: 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有所差异。不管是块元素还是行内元素,元素设置heightauto的时候,首先height(内容高度)将会根据内容所占的高度来计算,而元素的盒子高度是:

块元素框高度 = margin-top + border-top + padding-top + height(内容高度) + padding-bottom + border-bottom + margin-bottom

比如下面这个示例:

可以尝试着在上面的示例中添加内容,你会发现div.element元素的高度也会随着内容增加而改变:

这里需要特别的注意,文本相关的属性设置,比如font-familyfont-sizeline-height会对auto计算出来的值有所影响。

有关于line-height相关的介绍,可以阅读《深入了解CSS字体度量,行高和vertical-align》一文。

对于行内元素(或display: inline的元素),元素的height(内容区域高度)会是auto,表现行为和块元素有点类似,都是依赖元素的内容来撑开。

你会发现,inline的元素和inline-blockinline-flex以及inline-grid还是有所差异的:

注意,inline元素的渲染行为并不是一个Bug,它的特性就是如此

同样的,容器上下文格式对于元素取值height: auto的计算也会有影响,我们主要来看Flexbox和Grid上下文环境:

正如上面示例所示,在Flex容器或Grid容器中的元素会被拉伸填充整个容器,看上去有点类似于元素设置了height: 100%。但两都还是有所差异的,比如下图所示的测试结果:

在Flex容器(或Grid容器)中的Flex项目(Grid项目),margin-topmargin-bottom的值对于height: auto的计算是有影响的:

除此之外,在Grid上下文中,Grid容器的grid-template-rows设定的值对于Grid项目height: auto的计算也一定的影响。

min-width/height取值为auto

在CSS中,除了widthheight之外,还可以使用min-widthmin-height来设置元素框的尺寸。从前面的内容我们可以获知,min-widthmin-height的初始值也是auto。换句话说,也可以给这两个属性显式的设置值为auto。但不同的时,如果不受布局模块影响的话,min-widthmin-heightauto计算出来的值是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指定的是主轴方向的初始值。简单地说,除了autocontent,它都以与水平书写模式中width相同的方式解析(除了width值设置为autoflex-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-contentmax-content就会起作用。此时将会把Flex项目的max-content作为flex-basis值。

在Flexbox布局中设置Flex项目尺寸大小时有一个隐式的公式存在:

contentwidthflex-basis

简单地说,如果未显式指定flex-basis的值,那么flex-basis将回退到width属性;如果未显式指定width,那么flex-basis将回到基于Flex项目内容的计算宽度。不过,决定Flex项目尺寸方面,还受flex的其他两个属性flex-growflex-shrink以及Flex项目容器大小的影响。而且Flex项目最终尺寸会受min-widthmax-width属性限制。这一点必须得注意。

上面的示例中,我们未显式给Flex项目设置widthmin-widthflex-basis的值,因此它们都将会以auto值根据内容来自动计算。这里需要特别提出的是,flex-basisflex其中一个属性。换句话说,如果未做任何显式设置,就相当于: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相关的事情。比如toprightbottomleft的初始值为auto。接下来我要解释的事情相对来说都是定位中的一些细节,掌握这些细节让你能彻底的搞清楚定位模块。

在这一节中如何你看到TRLB的简写,其代表的就是定位模块中的top(T)、right(R)、bottom(B)和left(L)

在W3C规范中对TLBL取值为auto有过详细的阐述,这里就不累述了,感兴趣的可以查阅规范中的第八小节(Sizing and positioning details)。

CSS中position取值为非static时,可以对元素进行定位,其中TRBL可以用来设置元素的偏移量:

在上例的基础上调整一下,把能取值为auto的相关参数配置上去。示例的默认状态widthheight值都是auto,除此之外,在定位环境下TRBLmargin都可以取值为auto

基于该示例,按照规范中的第八小节(Sizing and positioning details)调整参数,就可以看到具体的效果。这里就不再将演示的结果贴出来了。

对齐中的auto

Web中让元素实现水平垂直居中,我们都可以使用margin:auto来实现,比如水平居中:

.element {
    width: 30vw;
    margin-left: auto;
    margin-right: auto;
}

如果我们使用margin-leftmargin-right取值auto实现水平居中,有一个必要条件,那就是元素自身需要显式设置widthmax-width的值。其实现过程如下:

相当于:容器剩余空间 = 容器宽度 - 元素宽度。然后将剩余空间分成两等份,如果margin-leftmargin-right都显式设置了auto,那么浏览器会根据容器剩余空间进行计算,分别分给这两个属性。

在定位中,margin取值为auto时,同样可以让元素居中:

.parent {
    position: relative;
}

.children {
    position: absolute;
    margin: auto
}

在绝对定位中使用margin: auto让元素实现水平垂直居中,它有一个前提条件,那就是RTBL的值需要显式的设置为0,同时元素自身需要显式的设置widthheight的值。如果未显式设置具体的值,元素将会填满整个容器。

在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-selfjustify-self(它们的简写属性place-self)也可以取值为auto。当place-self取值为auto时,Flex项目和Grid项目的对齐方式将会按照它的父容器设置的对齐方式来处理。我们来看看下面的示例:

background-sizemask-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值在不同的属性中所起的作用有所不同,只有了解这其中的细节都能更好的用好。如果你在这方面有更好的建议或经验,欢迎在评论中与我们一起共享。