前端造地基-css-基本概念、元素、流、宽高

  这本书很细,读到第4章有点举步维艰,重新回头,将未完成的笔记做完。复习一下,重新找到书的脉络,以及读这本书更有效的方法。这本书是张鑫旭大佬 css 三部曲的第一部。

  这是本进阶的书,我没有系统学习过 css 的特性,比如菜鸟教程或其他的 css 的书,但是我有开发的经验,选择这本书是没问题的,只不过会难啃一些。

  css 不能像其他编程语言一样去学习,css 呈现的效果是多个属性共同作用造成的,不像 js 中数组的某个方法,其效果就是这个 api 单独造成的。学习 css 更看重的是特性间的相互联系和具象能力,要将所有 css 属性当作一个整体,每个 css 属性都有其存在的原因,都和其他属性有着千丝万缕的关系,背后的联系非常庞大。

概念、术语

  从整体出发构建一个 css 的世界观,让我们对 css 的认识更加立体、丰满。css 和其他的编程语言不同,更加抽象、感性,只有通过联系、具象的思考、理解,才能更好的学习。

  书中构筑了一个世界,建筑魔法世界。属性为魔法师,值为技能,选择器为法器,标签元素为魔法石,浏览器为王国,操作系统为世界。可以想象,在 windows 世界中,有着几大王国(chrome、ie、firefox、safari、opera等等),魔法师挥舞着法杖发动五花八门的技能对魔法石进行打造,使其变化多端、形状各异、多姿多彩。利用这些魔法石以及改造后的魔法石构建起了一座座美丽的建筑,伫立在王国中。

  凡事有因必有果,css 的各种奇异属性也是有原因的,和被创造时的需求不可分离。1995年,html 还是第一版,w3c 才成立,css 还没出现。后来,css 凭借“层叠”特性从几个样式语言中胜出,层叠策略可以让样式的显示十分灵活。1996年12月 css1 诞生。1998年5月 css2 诞生,推行内容与样式分离。98年是门户的时代,人们关注的是信息的获取,所以网站的需求就是信息的展示。那个时代,信息就是“图片和文字”。css2(以及,2007推出的 css2.1)都是为“图片”和“文字”服务的。

  css 凭借流击败了2003年推出的 svg。svg 的强势在于图形处理,然而 css 的图形处理能力也不差,而文字方面完全被 css 碾压。这就导致 svg 被压制这么多年。

  流就是文档流,css 中基本的定位和布局机制。这种机制是如何影响网页的呢?

  首先,html 元素是网页的基石、骨架,html 元素默认的表现就是水平流。其次,有时候需要复杂特殊的布局效果,可以破坏“流”达到。最后,流的流向是可以改变的,只是默认的流向是水平向右,垂直向下。

  除了流这种机制,还有其他机制能实现吗?比如,亲缘机制?这个听都没听说过,后续在捋

  “流式布局”就是利用元素流的特性实现的各类布局效果,“流”本身具有“自适应特性”,但是流布局并不等同于自适应布局,比如 table 布局就不是流布局。

  table 布局用的 table 元素,这个元素比 css 出现的都早,流特性虽然影响整个 css 世界,但是并不适用于 table 元素,table 有着自己的世界。

  css2.1 被 ie8 全面支持,这本书中的几乎所有 demo 都是针对 ie8 及以上浏览器的。

css3

  css3 的重点在于“布局”、“视觉表现”。布局这块和流关系还是挺多的吧。2.1 就是 3 的大基础。

术语

  属性、值、关键字、变量、长度单位、功能符、属性值、声明、声明块、规则或规则集、选择器。
   - 有很多种,整数值、小数、百分比、长度值、颜色值、字符串值、位置值、角度值、频率值、时间值。
   - 关键字有 solid、inherit,inherit 又叫泛关键字,所有的属性都能用。
   - 变量是 css3 的东西,内置的变量有 currentColor。
   - 长度单位有 px、em 等,分为绝对长度单位和相对长度单位,相对字体(em、ex、rem、ch)和相对视区(vw、vh、vmin、vmax)。
   - 功能符将值以函数的形式包裹起来,有表示颜色、背景图片地址、元素属性值、计算、过渡效果等,rgba(0,0,0,.5)、url(‘-css-world.png’)、attr(‘href’)、scale(-1)。
   - 属性值可以是单一的值,也可以是值、关键字、功能符的组合。属性名冒号到分号前的内容都是属性值。
   - 声明就是属性名加上属性值。声明块由花括号包括起来的声明序列。
   - 普通规则由选择器和声明块组成。选择器又有3种分类,简单选择器,复合选择器,复杂选择器,选择器列表。
   - @规则由@特殊字符开头,有 @media、@font-face、@page、@support 等特殊规则。

上面这些术语其实也可以叫做 css 的语法结构。 从最完整的规则,到选择器和声明块,再到声明块内的声明语句,声明又由属性名和属性值组成,属性值又有多种形式,可以是值、关键字、功能符之间的多种组合。

流、元素、基本尺寸

  流为什么能影响 css 世界呢,html 元素默认的表现就是水平流。html 元素分为两类,块级元素、内联元素。“块级元素”和“display 为 block 的元素”不是一个概念 。li 的 display 属性默认是 list-item,

默认是 table,但是他们都是块级元素,因为他们都符合块级元素的特征。

  块级元素的特征,换行特性,水平流方向上一行只能放一个块级元素,多个块级元素会换行显示。当然还有其他特征,后面再总结。

  块级元素的换行特性可以搭配 clear 属性清除浮动。实际应用中一般用 block、table 清除浮动,并不会用 list-item,原因有2个,①出现多余的项目符号;②ie 不支持伪元素 display 设置为 list-item。这两个原因背后的体系是盒模型,非常多的盒子来袭。

  最初只有块级盒子、内联盒子,块级盒子负责结构,内联盒子负责宽高、内容呈现。每个元素都有这两个盒子,又分别叫做外在盒子、内在盒子(容器盒子)。

  除了这两种盒子,还有标记盒子。list-item 元素会出现项目符号是因为生成 标记盒子(marker box),专门用来放圆点、数字这些项目符号。IE 浏览器下伪元素不支持 list-item 或许就是无法创建这个“标记盒子”导致的。

  值为 block 的元素的盒子实际由外在的“块级盒子”和内在的“块级容器盒子”组成,值为 inline-block 的元素则由外在的“内联盒子”和内在的“块级容器盒子”组成,值为 inline 的元素则内外均是“内联盒子”。

  display: inline-table 的盒子是如何组成的,外面是内联盒子,内部是table盒子。

无宽度,width: auto

  witdth / height 属性作用在元素的容器盒子。块级元素的流特性主要体现在水平方向上。width 属性的默认值是 auto,这个默认值很叼,auto 在不同的场景有4种表现,fill-available、fit-content、min-content、max-content。

  充分利用可用空间, 比方说,div、p 这些元素的宽度默认是 100%于父级容器的 ,fill-available。

  收缩与包裹,典型的代表是浮动、绝对定位、inline-block 元素或 table 元素,这些元素的宽度都由子元素决定。

  收缩到最小, table-layout 为 auto 的表格中,当每一列的空间不够时,第一列文字的每个字符就会断开换行。

  超出容器限制,内容很长的连续的英文和数字,或者内联元素被设置了 white-space:nowrap,内部元素的宽度就会超过外部元素容器的限制。

  CSS 世界中,显示也分“内部显示”和“外部显示”,尺寸也分“内部尺寸”和“外部尺寸”。内部尺寸表示尺寸由内部元素决定;外部尺寸表示宽度由外部元素决定。auto 的第一种表现就属于外部尺寸,其余都是内部尺寸,这个唯一的外部尺寸表现正是流的精髓。

  外部尺寸的流体特性,有两点,① 正常流宽度,②格式化宽度。“三无准则”,无宽度、无图片、无浮动。无宽度的原因是表现为外部尺寸的元素设置了 width 就会失去流动性。

  块级元素的流动性,是一种 content / border / padding / margin 自动分配水平空间的机制,并不是宽度 100% 这么简单。css3 中,规定这种内在盒子为 flow,也就是说 display : block 应该是 display: block flow。设置了具体的值,就没法充分利用容器空间,丢失流动性。

  格式化宽度,水就比较深了,和 position 有很大关系。position 为 absolute 或 fixed 的元素中,对于非替换元素,当 left/right 或 top/bottom 属性值同时存在时,元素的尺寸由外部元素来决定,相对于最近的具有定位特性(除了 static)的祖先元素进行计算。而默认情况下,绝对定位元素的宽度是“包裹性”,由内部元素决定。第6章有更多介绍。

  内部尺寸的流动特性,内部尺寸有3种表现形式,包裹性、首选最小宽度、最大宽度。如果一个元素没有内容,宽度为0,那么就是应用的内部尺寸。浮动、绝对定位、inline-block 元素、table 的宽度都是由子元素决定的。

  包裹性不仅能包裹,还能自适应,自适应特性就是元素宽度由内部元素决定,但元素宽度永远小于包含容器的尺寸,除了包含容器的宽度小于元素的最小宽度(min-width)。

   button 就是典型的自适应特性的 inline-block 元素,按钮文字越多,宽度就越宽,太多就会在容器的宽度处换行。input 标签默认 white-space: pre,不会自动换行,需将 pre 重置为normal。

<div class="box">
  <button>按钮</button>
</div>
<div class="box">
  <button>按钮文字越多宽度越宽(包裹,内部尺寸特性),但不会超过容器宽度(自适应性)</button>
</div>
.box {
  width: 240px;
  margin: 20px auto;
}

  包裹性在实际开发中,可以实现,某个模块内文字少的时候居中显示,文字超过一行的时候居左显示。

  最小宽度,指的是元素最合适的最小宽度。css 中图片和文字的权重要远大于布局。当外部元素设置宽度为0时,内部尺寸的元素是不为0。中文文字的最小宽度就是每个汉字的宽度,英文字符的最小宽度就是单词宽度,如果想改变为每个字符作为最小宽度,使用 word-break: break all,而图片这样的替换元素的 min-width 就是元素内容本身的宽度。理解这个知识点,就能明白css中的一些奇怪现象,没有其他实际作用。

  最大宽度,就是元素可以有的最大宽度。如果元素内部没有块级元素,或者块级元素没有设定宽度值,则“最大宽度”实际上是最大的连续内联盒子的宽度。

  连续内联盒子,指的是内联级别的一个或一堆元素,中间没有换行标签 br,或其他块级元素。

  在实际开发中,设置很大宽度一般用来保证元素在容器内不会换行,一行就显示完。很大宽度和最大宽度是有区别的。实现滚动就需要最大宽度。实现自定义滚动只有两种原理, 一种借助原生的滚动,另一种是根据内部元素的尺寸和容器的关系。iScroll 用的后一种,这时候使用最大宽度,滚动才能真的到底。

width 具体数值的表现

  100px 作用在内部盒子。如何作用的关键在于盒尺寸,内部盒子又由 margin-box(透明)、border-box、padding-box、content-box 等4个盒子构成。

  css 世界盒子实在太多了,到现在为止,已经有块级盒子、内联盒子、外在盒子、容器盒子、margin 盒子、border 盒子、padding 盒子、content 盒子。

  内部盒子的这4个盒子规范化体现在 box-sizing 这个属性上。其实并没有 marigin-box,只有 content-box、border-box、inherit。因为目前没有任何场景需要用到 margin box。有两点,第一,“margin 的背景永远是透明的”,不可能用在 backgound-clip 或 background-origin 属性值,第二,块盒规定,margin 不参与元素本身尺寸的计算。

  css2.1 规定 width 属性值是作用在 content-box 上的。这个规范也是规定的标准盒模型,所以按标准盒模型来,元素实际的尺寸比设定的尺寸要大。

  这种宽度上的设定和表现有两个不合理的地方,丢失流动性、与实际显示效果不一致。实际的显示效果是要加上 padding、border 的值,不了解标准盒模型的计算公式就可能会感到意外。而且就算考虑到,宽度边框内边距都精打细算好了,部分属性值一变化就错位。

  丢失了流动性的话,宽度的设置就非常死板,也很容易出现越界的情况。所以最好是“无宽度”,即 width: auto,充分利用容器空间。

  为了避免这种错位问题, 书写上使用“宽度分离原则”。就是 width 属性不与 padding/border(有时候包括 margin)属性共存。分离,width 独立占用一层标签,而 padding、border、margin 利用流动性在内部自适应呈现。

  分离一定是便于维护的。比如,样式与行为分离 、前后端分离、宽度分离。但是宽度分离会多使用一层标签,父元素定宽,子元素 width 默认 auto,所以内部可以像水流一样自动填满父级容器。

  然而“无宽度”的网页布局需要很深的 css 积累才能驾驭,否则,html 会多很多层。无疑增加了页面渲染和维护成本。

  还有一种方法,不需要添加外层标签,设置 box-sizing 属性。这个属性 ie8 兼容,需要加上 -ms- 前缀,虽然是 css3 属性,ie9 以上就不用加前缀了。

  box-sizing 就是盒尺寸,可以改变 width 的作用细节。通过这个属性就可以将 width 作用于其他几个盒子。

  不支持 margin-box 是因为它本身就没有价值。第一,margin 不会影响元素的尺寸;第二,规范定义 margin 的背景永远是透明的。 box-sizing 就是用来改变尺寸作用的,而 margin 只有在无宽度的时候可以改变元素尺寸,但是此时元素处于流动性状态,也不需要 box-sizing 了。规范定义的东西,很难改的吧。

  box-sizing 被发明出来最大的初衷应该是解决“替换元素宽度自适应问题”。input / textarea / img / video / object 等替换型元素的尺寸是由内部元素决定改的。修改替换元素的 display: block 是没办法使其变成外部尺寸,也就是宽度100%自适应父级容器。

  textarea 需要有 border、padding,否则输入的光标会顶着边框,体验不好。这就注定了 width/border 和 padding 得共存,同时宽度还要设置为 100%。在 box-sizing 没出来之前,嵌套一层标签来模拟边框和内边距,textarea 作为子元素,边框和内边距为0,宽度为100%。但是这种方式没法使用 focus 伪类选择器高亮父元素的边框。终极绝招还得是 box-sizing。所以最佳实践是:

.father {
  width: 100px;
  border: 1px solid red;
  padding: 10px;
}
textarea {
  width: 100%;
  -ms-box-sizing: border-box;
  box-sizing: border-box;
}
height

auto

  无高度比无宽度要单纯的多。原因是 CSS 的默认流是水平方向的,宽度才是稀缺资源。 元素 float 容器高度没了、 margin 直接穿过去,高度比预期的矮了,这些都不是 height 的问题。那是谁的问题?

  height: auto 具有外部尺寸特性,仅存在于绝对定位中,即“格式化高度”,与格式化宽度类似。

百分比值

  无高度和无宽度的一个区别是百分比单位,width: auto 的元素宽度是父级容器宽度的100%,而 height: auto 却会被忽略(在文档流中)。文档流中元素的高度百分比想要生效,父级元素的高度值必须是一个具体值。

  所谓的宽度死循环、高度死循环是不能解释无高度为啥失效的。从浏览器渲染的原理来讲,从上到下、从外到内渲染 dom,会先渲染父元素,再渲染子元素,是有先后顺序的。先渲染父元素时,宽度就是内部内容的宽度。渲染子元素的时候,父元素的宽度已经确定了,子元素 width: 100% 就是父元素的宽度,并不会死循环。属于是静态渲染,一次到位。如果宽度不够,就溢出 overflow。

  高度不支持就是规范没有规定,不像宽度,虽然默认值是 auto,但是实际上是父元素的 100%。而高度就是 auto 这个字面值。所以也计算不出结果,‘auto’ * 100 / 100 = NaN。宽度的话,规范没有明确 auto 时的计算方式,各大浏览器都比较一致,就是 100%。

  要想让 height:100% 生效,有两种方法,第一,给父元素设置具体的高度值,第二,设置当前元素为绝对定位(脱离文档流)。

  绝对定位和非绝对定位元素的百分比计算有区别。绝对定位的宽高百分比计算是相对于 padding box 的。非绝对定位元素则是相对于 content box 的。

  显式高度方法中规中矩,意料之中;绝对定位方法剑走偏锋,支持隐式高度计算,给人意外之喜,但本身脱离文档流,使其仅在某些场景有四两拨千斤的效果,比方说“图片左右半区点击分别上一张图下一张图效果”的布局。

*-width/ *-height

  min-width / max-width / min-height / max-height 的盒尺寸机制,渲染规则和 width/height 都是一样的,除了这两点还有其他相似的地方。

  不同的是,这些值具有边界行为这一特性,一般用在自适应布局或者流体布局中。而且这4个值的使用门槛还比较高,兼顾还原性的同时还要兼顾扩展性和适配性,才用得到这4个值。

  用这种边界值,可以实现特定区间内的自适应布局方案。


初始值

  这4个边界值得初始值比 width / height 复杂,min-* 的一般是 auto,max-* 一般是 none。auto 不是具体的数值,就由内容决定。max-* 初始值为 none 的原因是 max-* 会覆盖 width/height。那么子元素的宽度就没用了,根本渲染不出来。

  -width/-height、width/height 之间有相互覆盖的规则。他们之间的相互覆盖关系会超越 !import、内联样式,优先级更高。min-* 比 max-* 设置的值大,就采用 min-* 的值。

  任意高度元素展开收起动画技术。通常用 display 在 none 和其他值之间切换,但是滑动效果不好。jquery 的 slideUp、slideDown 方法滑动效果就挺可以。在移动端,css3 动画支持效果好,就可以用 css 实现。height + overflow: hidden。

  如果展开的内容是动态变化的,也就是高度不固定,而 height 默认是 auto,从 0 到 auto 并不会触发滑动的效果。使用 max-height 设置一个足够小的最大值就可以了。如果值太大,会有明显的延迟。

.element {
  max-height: 0;
  overflow: hidden;
  transition: max-height .25s;/* property duration timing-function delay */
}
.element:active {
  max-height: 666px;/* 一个足够大的最大高度值 */
}
<input id="check">
<label for="check">更多</label>/* 绑定到id为check的表单元素 */
内联元素

  外在盒子有三种,inline / block / run-in。inline / block 盒子瓜分了盒子世界,是流体布局的本质所在。css2.1 世界是以图文为中心的。图文是最经典的内联元素,内联元素尤其重要。

  内联元素比块级元素更难解析的原因就在于,内联元素的属性多,属性又有继承特性,混合在一起共同作用。要想解析这种多个属性共同作用的结果,需要对内联元素特性、内联盒模型、内联元素的属性很了解。

  内联元素。内联的意思是外在盒子是 inline,和 display: inline 不是一个概念哈。外在盒子是内联盒子的元素就是内联元素。内联元素的典型特征就是可以和文字在一行显示,不会换行。浮动元素虽然也能和文字一行显示,但是已经脱离了文档流,并不是真的是文字在一行,而是恰好在那个位置。

内联盒模型

  内联盒模型比块级盒模型难多了,是正儿八经进阶的东西。一段普通的html <p>普普通通<em>em</em></p>,包含了很多盒子。有内容区域盒子、内联盒子、行框盒子、包含盒子。

  内容区域盒子的范围就是围绕 p 标签内的文字,大小受字符本身的特性控制。对于一些替换元素 ,内容区域就是元素本身。内容区域没有明确的定义。根据实践,文本选中区域就是基本盒尺寸的 content-box,也就是内容区域。IE 和 firefox 是精准的,chrome 的 ::section 范围不总是准的,图片混排、垂直padding的时候会偏大。

  内联盒子,不让内容成块显示,而是排成一行。内联盒子指的是元素的外在盒子,用来决定元素是“内联”还是“块级”。内联盒子又可以分为非匿名和匿名的。如果有明显的内联标签,那么就属于内联盒子,如果是光秃秃的文字,那就属于匿名内联盒子。如果文字前后的标签是块级,那么还有可能是“匿名块级盒子”。

  行框盒子,由一个个的内联盒子组成。

  包含盒子,由一个个的行框盒子组成,在规范中叫做包含块,containing block。

幽灵空白节点

  幽灵节点只有在 h5 的文档声明中有。是一个内联盒子,拥有这个元素的字体、行高属性。,并且宽度为 0,透明。内联元素解析和渲染时都表现为每个行框盒子前有一个空白节点。

  todo 继承的是谁的字体、行高呢?

  理解幽灵节点是理解后面很多内联元素表现的基础。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值