wallleap / myblogs

blog, Issue
https://myblog.wallleap.cn
4 stars 1 forks source link

CSS 世界笔记 #89

Open wallleap opened 1 year ago

wallleap commented 1 year ago

title: CSS 世界笔记 date: 2022-10-12 20:32 updated: 2022-10-12 20:32 cover: //cdn.wallleap.cn/img/pic/illustrtion/202210121558633.jpg category: 技术杂谈 tags:

本文由个人学习张鑫旭老师的《CSS 世界》整理而来,通过阅读这本书,发现了很多之前没注意到的细节,文中加入了自己的想法和理解,舍弃了有关 IE 兼容性的问题,建议有一定 CSS 基础的同学阅读,如有错误请指正。

✨ CSS 有别于传统程序语言,在 CSS 的世界里,页面上的任何看似简单的呈现都是由许许多多 CSS 属性共同作用的结果。

CSS 并无逻辑可言,看重的是特性间的相互联系和具象能力。

基本概念

层叠样式表

CSS 全称是 Cascading Style Sheets,翻译成中文就是“层叠样式表”,所谓“层叠”,顾名思义,就是样式可以层层累加,比方说页面元素都继承了 12 像素的大小,某标题就可以设置成 14 像素进行叠加。这种层叠策略对于样式的显示是相当的灵活。

CSS 规则集

CSS 是由一个个规则集(ruleset)组成的,规则集包括选择器和声明块两部分

Code

其他概念:

选择器

选择器是用来瞄准(选择)目标元素的东西,例如,上面的 .selector 就是一个选择器

CSS 世界中的“未定义行为”

Web 应用场景千变万化,Web 标准也是不可能面面俱到的,也会存在规范描述以外的场景,此时,各大浏览器厂家只能根据自己的理解与喜好去实现,一旦个性化就会出现差异,就比如 Firefox 和 IE/Chrome 浏览器表现不一样。

实际上,此时遇到的表现差异并不是浏览器的 bug,用计算机领域的专业术语描述应该是“未定义行为”(undefined behavior)。

CSS 世界的“世界观”

文档流

“流”实际上是 CSS 世界中的一种基本的定位和布局机制,可以理解为现实世界的一套物理规则,“流”跟现实世界的“水流”有异曲同工的表现。

所谓“流”,就是 CSS 世界中引导元素排列和定位的一条看不见的“水流”。

CSS 世界构建的基石是 HTML,而 HTML 最具代表的两个基石 <div><span> 正好是 CSS 世界中块级元素和内联级元素的代表,它们对应的正是图 1-3 所示的盛水容器中的水和木头,其特性表现也正如现实世界的水和木头,如图 1-4 所示。

流是如何影响整个 CSS 世界的?

📌 table 有自己的世界,“流”的特性对 <table> 并不适用

CSS 世界的基石——HTML 元素

HTML 常见的标签有 <div><p><li><table> 以及 <span><img><strong><em> 等。

虽然标签种类繁多,但通常我们就把它们分为两类:块级元素(block-level element)和内联元素(inline element)。

块级元素

块级元素占据其父元素(容器)的整个水平空间(一般独占一行),垂直空间等于其内容高度,常见的块级元素有 <div><li><table> 等。

这些元素的 display 属性值默认是 blocktablelist-item 等。


🌰 应用:清除浮动

正是由于“块级元素”具有换行特性,因此理论上它都可以配合 clear 属性来清除浮动带来的影响。

.clearfix:after {
  content: '';
  display: table; /* 也可以是 block 或者是 list-item */
  clear: both;
}

📌 为什么 list-item 元素会出现项目符号

——之所以 list-item 元素会出现项目符号是因为生成了一个附加的盒子,学名“标记盒子”(marker box),专门用来放圆点、数字这些项目符号。

内联元素

内联元素又叫行内元素,指只占据它对应标签的边框所包含的空间的元素,这些元素如果父元素宽度足够则并排在一行显示的,如 spanaemiimgtd 等。

“内联元素”的“内联”特指后文提到的“外在盒子”,这些元素的 display 值默认是 inlineinline-blockinline-tabletable-cell 等。

✨ 一般情况下,行内元素只能包含数据和其他行内元素,而块级元素可以包含行内元素和其他块级元素

就行为表现来看,“内联元素”的典型特征就是可以和文字在一行显示,浮动元素貌似也是可以和文字在一个水平上显示的,实际上,浮动元素和后面的文字并不在一行显示,它已经在文档流之外了,浮动元素会生成“块盒子”

CSS 盒模型

外在盒子和内在盒子

每个元素都两个盒子,外在盒子和内在盒子

外在盒子是流体布局的本质所在,从作用上来讲,块级负责结构内联负责内容

按照 display 的属性值不同,外在盒子和内在盒子组成不同

✨ 在 CSS 中,所有的元素都被一个个的“盒子”(box)包围着(容器盒子

每个盒子由四个部分(或称区域)组成,其效用由它们各自的边界(Edge)所定义,与盒子的四个组成区域相对应

每个盒子有四个边界:内容边界 Content edge内边距边界 Padding Edge边框边界 Border Edge外边框边界 Margin Edge

标准盒模型和怪异盒模型

可以通过设置 box-sizing 属性修改盒模型

有 content 和 border,那有没有可能还有其他的?

.box1 { box-sizing: content-box; } /* 默认值 */
.box2 { box-sizing: padding-box; } /* Firefox 曾经支持 */
.box3 { box-sizing: border-box; } /* 全线支持 */
.box4 { box-sizing: margin-box; } /* 从未支持过,本身就没有价值(设定好了宽高之后 margin 值并不能再影响盒子大小) */

box-sizing

内联盒模型

这里介绍的“内联盒模型”是简易版

内联盒模型

内容区域(content area)

inline-box 又名内联盒子

line-box 名为行框盒子

container-box 就是包含块的意思

strut “幽灵空白节点”

内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样。

“幽灵空白节点”实际上也是一个盒子,不过是个假想盒,名叫“strut”,中文直译为“支柱”,是一个存在于每个“行框盒子”前面,同时具有该元素的字体和行高属性的 0 宽度的内联盒。

基本尺寸

width 和 height

因为块级元素的流体特性主要体现在水平方向上,所以我们这里先着重讨论 width

width/height 的默认值是 auto,由”浏览器决定“,基于元素的类型和父元素的宽度来计算

max-widthmax-height 的初始值是none

虽然 MDN 和 W3C 维基的文档上都显示 min-width/min-height 的初始值是 0,但是,根据作者的分析和测试,所有浏览器中的 min-width/min-height 的初始值都是 auto(❓ 这里我没有太理解嘿,盒子默认没有内容,高度就是 0,有了内容,盒子高度由内容决定,min-height 始终为 0 也是合理的)

深藏不露的 width: auto

width 的默认值是 auto,它至少包含了以下 4 种不同的宽度表现:

相对简单而单纯的 height: auto

CSS 的默认流是水平方向的,宽度是稀缺的,高度是无限的,宽度的分配规则就比较复杂,高度就显得比较随意

height:auto 的表现:有几个元素盒子,每个多高,然后一加,就是最终的高度值了(由内容高度决定

不一定能生效的 height: 100%

heightwidth 还有一个比较明显的区别就是对百分比单位的支持

对于 width 属性,就算父元素 widthauto,其百分比值也是支持的;但是,对于 height 属性,如果父元素 heightauto,只要子元素在文档流中,其百分比值完全就被忽略了

让元素支持 height:100% 效果:

设定显式的高度值,对于普通文档流中的元素,百分比高度值要想起作用,其父级必须有一个可以生效的高度值!

html, body {
 height: 100%;
}

使用绝对定位,绝对定位的元素的百分比高度值是相对于最近的非 static 定位的祖先元素计算的

div {
  position: absolute;
  height: 100%;
}

📌 绝对定位的宽高百分比计算是相对于 padding box 的,也就是说会把 padding 大小值计算在内

非绝对定位元素则是相对于 content box 计算的

min-width/max-width 和 min-height/max-min-height

CSS 世界中,min-width/max-widthmin-height/max-height 属性间,以及与 widthheight 之间有一套相互覆盖的规则:超越 !important,超越最大

🌰 例子1:图片最后呈现的宽度是 256px

<img src="1.jpg" style="width:480px !important;">
img { max-width: 256px; }

🌰 例子2:最小宽度比最大宽度设置得还大,此时,“超越最大”规则,min-width 活下来,max-width 被忽略,.container 元素表现为至少 1400 像素宽

.container {
  min-width: 1400px;
  max-width: 1200px;
}

🌰 案例:任意高度元素的展开收起动画技术

.element {
  max-height: 0;
  overflow: hidden;
  transition: max-height .25s;
}
.element.active {
  max-height: 666px; /* 一个足够大的最大高度值 */
}

展开后的 max-height 值,我们只需要设定为保证比展开内容高度大的值就可以,但是,如果 max-height 值太大,在收起的时候可能会有“效果延迟”的问题


玩转盒模型

盒尺寸中的 4 个盒子 content box、padding box、border box 和 margin box 分别对应 CSS 世界中的 contentpaddingbordermargin 属性

content 与替换元素

CSS 的 content CSS 属性用于在元素的 ::before::after 伪元素中插入内容

使用 content 属性插入的内容都是匿名的可替换元素,它们不属于文档的一部分,因此不会被 CSS 选择器选中,也不会被 JavaScript 的 document.querySelector() 方法选中

可替换元素

根据“外在盒子”是内联还是块级我们可以把元素分为内联元素和块级元素

而根据是否具有可替换内容,我们也可以把元素分为替换元素和非替换元素

替换元素:通过修改某个属性值(例如 valuesrc 等)呈现的内容就可以被替换的元素就称为“替换元素”,<img><object><video><iframe> 或者表单元素 <textarea><input> 都是典型的替换元素

非替换元素:内容不可替换,除了上述的元素基本都是非替换元素


替换元素的尺寸:从内而外分为 3 类——固有尺寸、HTML 尺寸和 CSS 尺寸

尺寸

替换元素的尺寸计算规则:


🌰 首屏以下的图片处理

Web 开发的时候,为了提高加载性能以及节约带宽费用,首屏以下的图片就会通过滚屏加载的方式异步加载,当图片的 src 属性缺省的时候,图片不会有任何请求

<img src="./img/pic.jpg" > <!-- 首屏图片 -->
<img data-src="./img/pic1.jpg"> <!-- 首屏之外的图片 -->
<style>
img {
  display: inline-block; /* 对于 Firefox 浏览器,src 缺省的 <img> 不是替换元素,而是一个普通的内联元素,宽高会无效 */
  visibility: hidden;
}
img[src] { visibility: visible; }
</style>

🌰 使用 content 属性生成图片

在 Chrome 浏览器下,所有的元素都支持 content 属性

直接使用 content 属性添加图片路径,视觉上和 src 引入路径一致;如果图片原来是有 src 地址的,我们也是可以使用 content 属性把图片内容给置换掉的

content 属性改变的仅仅是视觉呈现,当我们以右键或其他形式保存这张图片的时候,所保存的还是原来 src 对应的图片

可前往 content 属性测试 - JS Bin 查看

图片来源于网络,仅作展示用

🌰 H1 显示 logo 图片

使用 content 属性,我们还可以让普通标签元素变成替换元素

之前实现网站主标题处仅显示 logo,不显示文字(视觉上展示图片,SEO 仍索引标题文字)是这样实现的:

<h1>网站主标题</h1>
<style>
h1 {
  width: 180px;
  height: 36px;
  background: url(logo.png);
  /* 通过设置文字缩进隐藏文字 */
  text-indent: -999px;
}
</style>

我们可以通过添加 content 属性实现,代码更简洁但效果相同

传统 CSS 代码的 <h1> 是一个普通元素,因此需要设定尺寸隐藏文字

但是,下面使用 content 属性实现,<h1> 分分钟就变成了替换元素,文字自动被替换,同时尺寸规则就是替换元素的尺寸规则,完美适应原始图片大小

h1 {
  content: url(logo.png);
}

查看:H1 title - JS Bin


在 CSS 世界中,我们把 content 属性生成的对象称为“匿名替换元素”(anonymous replaced element)

content 内容生成技术

在实际项目中,content 属性几乎都是用在 ::before/::after 这两个伪元素中,因此,“content 内容生成技术”有时候也称 “::before/::after 伪元素技术”。


🌰 把 content 的属性值设置为空字符串,再利用其他 CSS 代码来生成辅助元素,或实现图形效果

.element:before { 
   content: ''; 
} 

🌰 清除浮动带来的影响

.clear:after { 
  content: ''; 
  display: table;  /* 也可以是 'block' 等 */ 
  clear: both;
}

🌰 辅助实现“两端对齐”以及“垂直居中/上边缘/下边缘对齐”效果

<div class="box"><i class="bar"></i> 
  <i class="bar"></i> 
  <i class="bar"></i> 
  <i class="bar"></i> 
</div> 
<style>
.box { 
  width: 256px; height: 256px; 
  /* 两端对齐关键 */ 
  text-align: justify; } 
.box:before { 
  content: ""; 
  display: inline-block; 
  height: 100%; } 
.box:after { 
  content: ""; 
  display: inline-block; 
  width: 100%; } 
.bar { 
  display: inline-block; 
  width: 20px; } 
</style>

:before 伪元素用于辅助实现底对齐,:after 伪元素用于辅助实现两端对齐

使用这种方式,需要注意 HTML 代码有些地方不能换行或者空格,有些地方则必须要换行或者有空格

🌰 content 字符内容生成:比较常见的应用就是配合 @font-face 规则实现图标字体效果

<span class="icon-home"></span> 
<style>
@font-face { 
  font-family: "myico"; /* 自定义字体名称 */
  src:  url("/fonts/4/myico.eot"); 
  src:  url("/fonts/4/myico.eot#iefix") format("embedded-opentype"), 
    url("/fonts/4/myico.ttf") format("truetype"), 
    url("/fonts/4/myico.woff") format("woff"); }
.icon-home:before { 
  font-size: 64px; 
  font-family: myico; 
  content: "家"; 
}
</style>

除常规字符之外,我们还可以插入 Unicode 字符,例如换行符

:after { 
  content: '\A'; 
  white-space: pre; 
}

🌰 来实现字符动画效果

正在加载中<dot>...</dot>
<style>
dot { 
  display: inline-block;  
  height: 1em; 
  line-height: 1; 
  text-align: left; 
  vertical-align: -.25em; 
  overflow: hidden; } 
dot::before { 
  display: block; 
  content: '...\A..\A.';
  white-space: pre-wrap; 
  animation: dot 3s infinite step-start both; } 
@keyframes dot { 
  33% { transform: translateY(-2em); } 
  66% { transform: translateY(-1em); } } 
</style>

🌰 content 图片生成

/* 直接用 url 功能符显示图片 */
div:before { 
  content: url(1.jpg); 
} 
/* 伪元素中的图片更多的是使用 background-image 模拟 */
div:before { 
  content: ''; 
  background: url(1.jpg);
} 

🌰 content 开启闭合符号生成

常规实现:

q:before { 
  content: '“'; 
} 
q:after { 
  content: '”'; 
}

自带属性 quotes

<p lang="ch"><q>这本书很赞!</q></p> 
<p lang="en"><q>This book is very good!</q></p>
<p lang="no"><q>denne bog er fantastisk!</q></p>
<script>
 /* 为不同语言指定引号的表现 */ 
:lang(ch) > q { quotes: '“' '”'; } 
:lang(en) > q { quotes: '"' '"'; } 
:lang(no) > q { quotes: '«' '»'; } 
/* 在 q 标签的前后插入引号 */ 
q:before { content: open-quote; } 
q:after { content: close-quote; } 
</script>

可以任意指定 quotes 的字符,CSS 中还有 no-open-quote 和 no-close-quote 关键字,顾名思义,引号不需要了

🌰 content attr 属性值内容生成

img::after { 
  /* 生成 alt 信息 */ 
  content: attr(alt); 
  /* 其他 CSS 略 */ 
}
/* 也支持自定义的 HTML 属性 */
.icon::before { 
  content: attr(data-title); 
}

🌰 使用 counter() 实现 ol 前的序号展示

CSS 函数 counter(),返回一个代表计数器的当前值的字符串。它通常和伪元素搭配使用,但是理论上可以在支持 <string> 值的任何地方使用。 可以直接看这篇文章:使用 CSS 计数器更改有序列表序号样式

🌰 content 内容生成的混合特性

各种 content 内容生成语法是可以混合在 一起使用的

a:after { 
  content: "(" attr(href) ")";
} 
q:before { 
  content: open-quote url(1.jpg);
} 
.counter:before { 
  content: counters(name, '-') '. ';
}

温和的 padding 属性

”温和”指的是我们在使用 padding 进行页面开发的时候很少会出现意想不到的情况。

CSS 中还有很多其他场景或属性会出现这种不影响其他元素布局而是出现层叠效果的现象,可以分为两类

判断:如果父容器 overflow:auto,层叠区域超出父容器的时候,没有滚动条出现,则是纯视觉的;如果出现滚动条,则会影响尺寸、影响布局


🌰 在不影响当前布局的情况下,优雅地增加链接或按钮的点击区域大小

article a { 
  padding: .25em 0;
}

除了使用 padding,也可以使用透明的 border

🌰 利用内联元素的 padding 实现高度可控的分隔线

<a href="">登录</a><a href="">注册</a>
<style>
a + a:before { 
 content: "";
  font-size: 0;
  padding: 10px 3px 1px;
  margin-left: 6px;
  border-left: 1px solid gray;
}
</style>

🌰 不使用伪元素,仅一层标签实现大队长的“三道杠”分类图标效果

.icon-menu { 
  display: inline-block; 
  width: 140px; height: 10px; 
  padding: 35px 0; 
  border-top: 10px solid; 
  border-bottom: 10px solid; 
  background-color: currentColor; 
  background-clip: content-box; 
}

🌰 不使用伪元素,仅一层标签实现双层圆点效果

.icon-dot { 
  display: inline-block; 
  width: 100px; height: 100px; 
  padding: 10px; 
  border: 10px solid; 
  border-radius: 50%; 
  background-color: currentColor; 
  background-clip: content-box; 
} 

功勋卓越的 border 属性

border 就是“边框”,border 属性在图形构建、体验优 化以及网页布局这几块大放异彩,同时保证其良好的兼容性和稳定的特性表现


🌰 右下方 background 定位的技巧

假设现在有一个宽度不固定的元素,我们需要在距离右边缘 50 像素的位置设置一个背景图片,可以使用透明边框(默认 background 背景图片是相对于 padding box 定位的,也就是说,background-position: 100% 的位置计算默认是不会把 border-width 计算在内的):

.box { 
  border-right: 50px solid transparent;  /* 对 50px 的间距我们使用 transparent 边框表示 */
  background-position: 100% 50%; /* 使用百分比 background- position 定位到我们想要的位置 */
}

🌰 优雅地增加点击区域大小

可以在 icon 外嵌套一层标签或者在 icon 上使用 padding 或透明 border

.icon-clear { 
  width: 16px; 
  height: 16px; 
  border: 11px solid transparent; 
  ... 
}

🌰 三角等图形绘制

border 属性可以轻松实现兼容性非常好的三角图形效果,其底层原因受 inset/outset 等看上去没有实用价值的 border-style 属性影响,这一转角规则也被 solid 类型的边框给沿用了,只要是与三角形或者梯形相关的图形,都可以使用 border 属性来模拟

/* 四色边框,只留一边有颜色就是梯形,将宽高置为0就是三角形 */
div { 
  width: 10px; height: 10px;  
  border: 10px solid;  
  border-color: #f30 #00f #396 #0f0; 
} 
/* 等腰直角三角形 */
div { 
  width: 0; height: 0;  
  border: 10px solid transparent;  /* 仅调整垂直方向 border-width 可以让其更扁或更高 */
  border-top-color: #f30; /* 保留两个方向的颜色,可以构造更多不同的三角形 */
} 
/* 利用梯形可以构造倒角矩形 */
div {
  position: relative;
  width: 200px;
  height: 100px;
  background: red;
  margin: 20px 20px;
}
div::before, div::after {
  content: '';
  position: absolute;
  box-sizing: border-box;
  width: 200px;
  height: 10px;
  border: 10px solid transparent;
}
div::before{
  top: -20px;
  border-bottom-color: red;
}
div::after{
  top: 100px;
  border-top-color: red;
}

🌰 使用 border 实现等高布局

如下:左侧深色背景区域是由 border-left 属性生成的,元素边框高度总是和元素自身高度保持一致,因此可以巧妙地实现等高布局效果

<div class="box clearfix">
  <nav>
    <h3 class="nav">导航1</h3>
  </nav>
  <section>
    <div class="module">模块1</div>
  </section>
</div>
<style>
/* 需要用 clearfix 清除浮动,这里不写出来 */
.box { 
 border-left: 150px solid #333; 
 background-color: #f0f3f9; 
}
.box > nav { 
 width: 150px; 
 margin-left: -150px; 
 float: left; 
}
.box > section { 
 overflow: hidden; 
}
</style>

激进的 margin 属性

方便后面理解,先看下元素尺寸相关概念:

margin 与元素的内部尺寸

margin 同样可以改变元素的可视尺寸,但是和 padding 几乎是互补态势

<div class="father"> 
  <div class="son"></div>
</div>
<script>
.father { width: 300px; }  /* 宽度300 */ 
.son {  margin: 0 -20px; } /* 宽度340(300+20+20) */ 
</script>

对于普通块状元素,在默认的水平流下,margin 只能改变左右方向的内部尺寸,垂直方向则无法改变

但是,对于具有拉伸特性的绝对定位元素,则水平或垂直方向都可以

使用 writing-mode 改变流向为垂直流,则水平方向内部尺寸无法改变,垂直方向可以改变(这是由 margin: auto 的计算规则决定的)


🌰 一侧定宽的两栏自适应布局效果

以下案例文字内容就会根据 .box 盒子的宽度变化而自动排列,形成自适应布局效果,无论盒子是 200 像素还是 400 像素,布局依然良好,不会像纯浮动布局那样发生错位

<style>
  .box { overflow: hidden; } 
  .box > img { float: left; } 
  /* .box > img { float: right; } */ /* 图片右侧定位 */
  .box > p { margin-left: 140px; }
</style>
<div class="box"> 
  <img src="1.jpg"> <p>文字内容...</p>
</div> 

图片右侧定位,但是按 HTML 顺序

<style>
  .box { overflow: hidden; } 
  .full { width: 100%; float: left; } 
  .box > img { float: left; margin-left: -128px; }
  .full > p { margin-right: 140px; }
</style>
<div class="box"> 
  <div class="full"> 
    <p>文字内容...</p>
  </div> 
  <img src="1.jpg">
</div> 

🌰 两端对齐布局

列表块两端对齐,一行显示 3 个,中间有 2 个 20 像素的间隙

li { 
  float: left; 
  width: 100px; 
  margin-right: 20px; 
}
/* 最右边也会有 30 的 margin,可以用下面的选择器或在第 3 个加上个类名 */
li:nth-of-type(3n) { 
  margin-right: 0; 
}

还可以通过给父容器添加 margin 属性,增加容器的可用宽度来实现,此时 ul 的宽度就相当于 100% + 20px

ul { 
  margin-right: -20px; 
} 
ul > li { 
  float: left; 
  width: 100px; 
  margin-right: 20px; 
}

margin 与元素的外部尺寸

对于外部尺寸,margin 属性的影响则更为广泛,只要元素具有块状特性,无论有没有设置 width/height,无论是水平方向还是垂直方向,即使发生了 margin 合并,margin 对外部尺寸都着着实实发生了影响


🌰 借助 margin 的外部尺寸特性来实现底部留白

只能使用子元素margin-bottom 来实现滚动容器的底部留白

<div style="height:200px;"> 
 <img height="300" style="margin:50px 0;">
</div>

🌰 利用 margin 外部尺寸实现等高布局

针对具有块状特性的元素而言,垂直方向 margin 无法改变元素的内部尺寸,但却能改变外部尺寸

默认情况下,垂直方向块级元素上下距离是 0,一旦 margin-bottom: -9999px 就意味着后面所有元素和上面元素的空间距离变成了-9999px,也就是后面元素都往上移动了 9999px

此时,通过神来一笔 padding-bottom: 9999px 增加元素高度,这正负一抵消,对布局层并无影响,但却带来了我们需要的东西——视觉层多了 9999px 高度的可使用的背景色,需要配合父级 overflow: hidden 把多出来的色块背景隐藏掉,于是实现了视觉上的等高布局效果

如果需要有子元素定位到容器之外,父级的 overflow: hidden 是一个棘手的限制;其次,当触发锚点定位或者使用DOM.scrollIntoview() 方法的时候,可能就会出现奇怪的定位问题

.column-box { 
  overflow: hidden; 
} 
.column-left, .column-right { 
  margin-bottom: -9999px; 
  padding-bottom: 9999px; 
}

内联元素垂直方向的 margin 是没有任何影响的,既不会影响外部尺寸,也不会影响内部尺寸,有种石沉大海的感觉

对于水平方向,由于内联元素宽度表现为“包裹性”,也不会影响内部尺寸


margin 的百分比值

padding 属性一样,margin 的百分比值无论是水平方向还是垂直方向都是相对于宽度计算的

元素设置 margin 在垂直方向上无法改变元素自身的内部尺寸,往往需要父元素作为载体

此外,由于 margin 合并的存在,垂直方向往往需要双倍尺寸才能和 padding 表现一致

margin 合并场景

块级元素的上外边距(margin-top)与下外边距(margin-bottom)有时会合并为单个外边距,这样的现象称为“margin 合并”

margin 合并的意义:

margin 合并的 3 种场景

1、相邻兄弟元素 margin 合并

<p>第一行</p>
<p>第二行</p>
<style>
p { margin: 1em 0; outline: 1px solid red;} 
</style>

margin合并

2、父级和第一个/最后一个子元素

<!-- 三种写法,无论是 son 还是 father 距离上边的距离都是 80px -->
<div class="father"> 
  <div class="son" style="margin-top:80px;"></div> 
</div> 
<div class="father" style="margin-top:80px;"> 
  <div class="son"></div> 
</div> 
<div class="father" style="margin-top:80px;"> 
  <div class="son" style="margin-top:80px;"></div> 
</div>

margin合并

解决父子 margin 合并:

对于 margin-top 合并,可以进行如下操作(满足一个条件即可):

对于 margin-bottom 合并,可以进行如下操作(满足一个条件即可):

3、空块级元素的 margin 合并

因为垂直方向的上下 margin 值合二为一了,所以垂直方向的外部尺寸只有水平方向的一半。

<!-- 此时 .father 所在的这个父级元素高度仅仅是 1em,因为 .son 这个空元素的 margin-top 和 margin-bottom 合并在一起了 -->
<div class="father"> 
  <div class="son"></div>
</div>
<!-- 此时第一行和第二行之间的距离还是 1em,中间看上去隔了一个 <div> 元素,但对最终效果却没有任何影响 -->
<p>第一行</p>
<div></div>
<p>第二行</p>
<style>
div { outline: 1px solid red; } 
.father { overflow: hidden; }
.son { margin: 1em 0; }

p { margin: 1em 0; }
</style>

如果不希望空元素有 margin 合并,可以进行如下操作:

margin 合并的计算规则

如果同号,取绝对值最大的那个

如果异号,则 margin 结果为相加的值

margin: auto

margin:auto 的填充规则如下:

margin 属性的 auto 计算就是为块级元素左中右对齐而设计的,和内联元素使用 text-align 控制左中右对齐正好遥相呼应(对于替换元素,如果我们设置 display: block,则 margin: auto 的计算规则同样适合)

.container {
  margin: 0 auto;
  width: 200px;
}

触发 margin: auto 计算有一个前提条件,就是 widthheightauto 时,元素是具有对应方向的自动填充特性的,需要 margin: auto 可以让元素在垂直方向居中:

/* 第一种 */
.father { 
  height: 200px;
  writing-mode: vertical-lr; /* 更改文档流方向 */
} 
.son { 
  height: 100px;
  margin: auto;
}
/* 第二种 */
.father { 
  width: 300px; height:150px;
  position: relative;
}
.son { 
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  width: 200px; height: 100px;
  margin: auto;
}

margin 无效情形

内联元素与流

✨ 块级元素负责结构,内联元素接管内容,而 CSS 世界是面向图文混排,也就是内联元素设计的

行高 line-height

line-height 对元素高度的影响

默认div 的高度是 0

对于非替换元素的纯内联元素,他的可视高度完全line-height 决定,paddingborder 属性对它的可视高度没有任何影响

line-height 不可以影响替换元素(如图片的高度)

对于块级元素line-height 对其本身是没有任何作用的

line-height 属性值

默认值为 normal

数值:如 line-height: 1.5,其最终的计算值是和当前 font-size 相乘后的值

百分比值:如 line-height: 150%,其最终的计算值是和当前 font-size 相乘后的值

长度值:也就是带单位的值,如 line-height: 21px 或者 line-height: 1.5em

内联元素 line-height 的“大值特性”

看一下示例代码:

<div class="box">
  <span>内容...</span>
</div>
<div class="box1">
  <span>内容...</span>
</div>
<style>
  .box { line-height: 96px; }
  .box span { line-height: 20px; }
  .box1 { line-height: 20px; }
  .box1 span { line-height: 96px; }
</style>

会发现 .box.box1 全都是 96px 高

✨ 无论内联元素 line-height 如何设置,最终父级元素的高度都是由数值大的那个 line-height 决定的,我称之为“内联元素 line-height 的大值特性”

解释:幽灵节点!!!

利用 line-height 实现文本居中

🌰 要让单行文字垂直居中,只需要 line-height 这一个属性就可以,并不需要依靠 height 属性

.title { line-height: 24px; }

line-height 可以让单行或多行元素近似垂直居中(通过 line-height 设置的垂直居中,并不是真正意义上的垂直居中)

🌰 行高实现多行文本或者图片等替换元素的垂直居中效果

<style>
  .box { line-height: 120px; background-color: #f0f3f9; }
  .content { display: inline-block; line-height: 20px; margin: 0 20px; vertical-align: middle; }
</style>
<div class="box">
  <div class="content">基于行高实现的...</div>
</div>

实现原理

垂直对齐 vertical-align

📌 凡是 line-height 起作用的地方 vertical-align 也一定起作用

字母 x

在各种内联相关模型中,凡是涉及垂直方向的排版或者对齐的,都离不开最基本的基线(baseline)

x

字母 x 的下边缘(线)就是我们的基线

基线

基线

vertical-align: middlemiddle 指的是基线往上1/2 x-height 高度。我们可以近似理解为字母 x 交叉点那个位置。

vertical-align: middle 并不是绝对的垂直居中对齐,我们平常看到的 middle 效果只是一种近似效果,因为不同的字体在行内盒子中的位置是不一样的。

对于内联元素垂直居中应该是对文字,而非居外部的块级容器所言。


🌰 应用:小图标对齐

.icon-arrow { 
  display: inline-block;
  width: 20px;
  height: 1ex;
  background: url(arrow.png) no-repeat center; 
}

内联元素默认是基线对齐的,而基线就是 x 的底部,而 1ex 就是一个x的高度。设想一下,假如图标高度就是 1ex ,同时背景图片居中,岂不是图标和文字天然垂直居中,而且完全不受字体和字号的影响?因为 ex 就是一个相对于字体和字号的单位。


vertical-align 作用的前提

vertical-align 属性值

除去 inherit 这类全局属性值不谈,可以把 vertical-align 属性值分为以下4类:

线类,如 baseline(默认值)、topmiddlebottom

文本类,如 text-toptext-bottom

数值百分比类,如 20px2em20%

无处不在的 vertical-align

✨ 对于内联元素,如果遇到不太好理解的现象,请一定要意识到,有个“幽灵空白节点”以及无处不在的 vertical-align 属性

不同属性值定义完全不同,且很多属性 table-cell 元素有着不同的定义;同时最终表现与字符 x、line-height,和 font-sizefont-family 属性密切相关


🌰 基于 20px 图标对齐的处理技巧

.icon { 
  display: inline-block; width: 20px; height: 20px;
  background: url(sprite.png) no-repeat;
  white-space: nowrap; letter-spacing: -1em; text-indent: -999em;
} 
.icon:before { 
  content: '\3000';
} 
/* 具体图标 */
.icon-xxx { 
  background-position: 0 -20px; 
}
...

🌰 基于 vertical-align 属性的水平垂直居中弹框

无论浏览器尺寸是多大,也无论弹框尺寸是多少,弹框永远都是居中的

<div class="container"> 
  <div class="dialog"></div>
</div>
<style>
.container { 
  position: fixed; top: 0; right: 0; bottom: 0; left: 0;
  background-color: rgba(0,0,0,.5);
  text-align: center; font-size: 0; white-space: nowrap;
  overflow: auto;
}
.container:after { 
  content: '';
  display: inline-block;
  height: 100%; vertical-align: middle; 
}
.dialog { 
  display: inline-block; vertical-align: middle; text-align: left;
  font-size: 14px; white-space: normal; 
}
</style>

流的破坏与保护

CSS 世界中正常的流内容或者流布局虽然也足够强大,但是实现的总是方方正正、规规矩矩的效果,有时候需要一些特殊的布局表现,例如,文字环绕效果,或者元素固定在某个位置,浮动和定位就在这里生效了

浮动 float

浮动的本质就是为了实现文字环绕效果而设计的

纯浮动布局容错性差,容易出现比较严重的布局问题,也容易出现意料之外的情况,这里的意料之外除了 float 属性自身特性(如父元素高度塌陷)导致的布局问题外,还包括诸多兼容性问题

float 的特性

float 的作用机制

float 与流体布局

利用 float 破坏 CSS 正常流的特性,实现两栏或多栏的自适应布局


🌰 一侧定宽的两栏自适应布局

<div class="father">
  <div class="menu"></div>
  <div class="content">this is content … Lorem100</div>
</div>
<style>
.father { overflow: hidden; } 
.father .menu { width: 60px; height: 64px;   float: left; background: #eee;} 
.father .content { margin-left: 70px; background: #eee;} 
</style>

两栏自适应布局

左侧定宽且浮动,右侧元素 margin-left 比左侧宽多 10 像素,不会发生环绕,且是自适应的

清除浮动 clear

语法 clear: none | left | right | both,基本使用 both 就可以了

clear: both 的作用本质是让自己不和 float 元素在一行显示,并不是真正意义上的清除浮动,而是抗浮动,float 一些特性仍存在:

clear 属性只有块级元素才有效,因此经常这样写:

.clearfix::after {
  content: ''; /* 默认是内联 */
  display: table; /* block list-item 也可以 */
  clear: both;
}

BFC

clear: both 只能在一定程度上消除浮动的影响,要想完美地去除浮动元素的 影响,还需要使用其他 CSS 声明

BFC 全称是 Block Formatting Context,块级格式化上下文

BFC 表现原则:

BFC 形成条件:

一般认为使用 BFC 特性清除浮动的影响要比使用 clear 更优,但是使用不同属性也有不同的效果:

所以好用一点的还是:overflow: hidden

overflow

生成 BFC 特性

overflow 设置 hiddenautoscroll,利用 BFC 的“结界”特性彻底解决浮动对外部或兄弟元素的影响,能够清除浮动的影响和解决 margin 嵌套合并

裁剪特性

设置 overflow: hidden 之后,元素会把超出部分进行裁剪

裁剪的边界是 border 的内边缘

滚动条

visible 是默认值;hidden 会进行裁剪;scroll 滚动条会一直出现;auto 当内容少时没有滚动条,当内容超出时滚动条出现

如果 overflow-xoverflow-y 属性中的一个值设置为 visible 而另外一个设置为 scrollautohidden,则 visible 的样式表现会如同 auto

除非 overflow-xoverflow-y 的属性值都是 visible,否则 visible 会当成 auto 来解析

永远不可能实现一个方向溢出剪裁或滚动,另一方向内容溢出显示的效果

HTML 中有两个标签是默认可以产生滚动条的,一个是根元素 <html>,另一个是文本域 <textarea>(这两个默认的是 auto

在 PC 端,无论是什么浏览器,默认滚动条均来自 <html>,而不是标签 <body>

去除页面默认滚动条:html { overflow: hidden; }

PC 端滚动条会占用容器的可用宽度或高度(默认是 17px

移动端则不一定

滚动条可以自定义,Chrome 下:

文本溢出

🌰 单行文字溢出点点点

.ell {
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden; 
}

🌰 多行文本溢出省略

.ell {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; /* 几行就设几 */
}

定位也能破坏流

absolute 绝对定位

relative 相对定位

fixed 固定定位

position: fixed 固定定位元素的“包含块”是根元素,我们可以将其近似看成 <html> 元素


🌰 模态框的蒙层无法覆盖浏览器右侧的滚动栏,并且鼠标滚动的时候后面的背景内容依然可以被滚动,并没有被锁定

position: fixed 蒙层之所以出现背景依然滚动,那是因为滚动元素是根元素,正好是 position: fixed 的“包含块”。所以,如果希望背景被锁定,让页面滚动条由内部的普通元素产生即可

移动端项目,阻止 touchmove 事件的默认行为可以防止滚动;如果是桌面端项目,可以让根元素直接 overflow: hidden,并且使用同等宽度的透明边框填充消失的滚动条

在蒙层显示的同时执行下面的 JavaScript 代码

var widthBar = 17, root = document.documentElement;
if (typeof window.innerWidth == 'number') {
  widthBar = window.innerWidth - root.clientWidth;
}  
root.style.overflow = 'hidden';  
root.style.borderRight = widthBar + 'px solid transparent';

隐藏的时候执行下面的 JavaScript 代码

var root = document.documentElement;
root.style.overflow = '';
root.style.borderRight = '';

CSS 中的层叠规则

“层叠规则”,指的是当网页中的元素发生层叠时的表现规则

层叠上下文

层叠上下文,英文称作 stacking context,是 HTML 中的一个三维的概念

如果一个元素含有层叠上下文,我们可以理解为这个元素在 z 轴上就“高人一等”

层叠水平

层叠水平,英文称作 stacking level,决定了同一个层叠上下文中元素在 z 轴上的显示顺序

所有的元素都有层叠水平,包括层叠上下文元素,也包括普通元素

然而,对普通元素的层叠水平探讨只局限在当前层叠上下文元素

某些情况下 z-index 确实可以影响层叠水平,但是只限于定位元素以及 flex 盒子的孩子元素;而层叠水平所有的元素都存在

元素的层叠顺序

层叠顺序,英文称作 stacking order,表示元素发生层叠时有着特定的垂直显示顺序。

CSS 2.1 下,层叠顺序规则如下图所示:

层叠顺序

(1)位于最下面的 background/border 特指层叠上下文元素的边框和背景色。每一个层叠顺序规则仅适用于当前层叠上下文元素的小世界。

(2)inline 水平盒子指的是包括 inline/inline-block/inline-table 元素的“层叠顺序”,它们都是同等级别的。

(3)单纯从层叠水平上看,实际上 z-index: 0z-index: auto 是可以看成是一样的。

background/border装饰属性,浮动和块状元素一般用作布局,而内联元素都是内容

两条层叠领域的黄金准则

(1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的 z-index 属性值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。

(2)后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。

层叠上下文的特性

层叠上下文的创建

1、根层叠上下文

根层叠上下文指的是页面根元素,可以看成是元素。因此,页面中所有的元素一定处于至少一个“层叠结界”中。

2、定位元素与传统层叠上下文

对于 position 值为 relative/absolute 以及 Firefox/IE 浏览器(不包括 Chrome 浏览 器)下含有 position: fixed 声明的定位元素,当其 z-index 值不是 auto 的时候,会创建层叠上下文。

3、CSS3 与新时代的层叠上下文

(1)元素为 flex 布局元素(父元素 display: flex|inline-flex),同时 z-index 值不是 auto (2)元素的 opacity 值不是 1 (3)元素的 transform 值不是 none (4)元素 mix-blend-mode 值不是 normal (5)元素的 filter 值不是 none (6)元素的 isolation 值是 isolate (7)元素的 will-change 属性值为上面 2~6 的任意一个(如 will-change: opacitywill-change: transform 等) (8)元素的 -webkit-overflow-scrolling 设为 touch

层叠上下文与层叠顺序

(1)如果层叠上下文元素不依赖 z-index 数值,则其层叠顺序是 z-index: auto,可看成 z-index: 0 级别;

(2)如果层叠上下文元素依赖 z-index 数值,则其层叠顺序由 z-index 值决定。

新的层叠顺序规则

元素一旦成为定位元素,其 z-index 就会自动生效,此时其 z-index 就是默认的 auto,也就是 0 级别,根据上面的层叠顺序表,就会覆盖 inlineblockfloat 元素

而不支持 z-index 的层叠上下文元素天然是 z-index: auto 级别,也就意味着,层叠上下文元素和定位元素是 一个层叠顺序的,于是当它们发生层叠的时候,遵循的是“后来居上”准则

从图中可以看到 z-index 负值元素的层级是在层叠上下文元素上面、block 元素的下面,也就是 z-index 虽然名为负数层级,但依然无法突破当前层叠上下文所包裹的小世界

文本

字号 font-size

内联元素默认基线对齐,图片的基线可以看成是图片的下边缘,文字内容的基线是字符 x 下边缘

因此想让一个图片图标和文字对齐,可以设置图片的 vertical-align 的值为文字的行高 * -25%.6ex

之前有说 1ex 指的是字符 x 的高度,而 1em 指的是一个子模的高度('M')

在 CSS 中,1em 的计算值等同于当前元素所在的 font-size 计算值,可以将其想象成当前元素中(如果有)汉字的高度

em 相对于当前元素,rem 相对于根元素

font-size 的关键词属性

桌面 Chrome 浏览器下有个 12px 的字号限制,如果 font-size: 0 的字号表现就是 0,那么文字会直接被隐藏掉,并且只能是 font-size: 0,哪怕设置成 font-size: 0.0000001px,都还是会被当作 12px 处理的

据我测试,最新版的 Chrome 浏览器已经没有这个限制了

字体属性家族 font

font-family 字体家族

font-family 默认值由操作系统和浏览器共同决定

font-family 支持两类属性值,一类是“字体名”,一类是“字体族”,如果字体名包含空格,需要使用引号包起来(可以不用区分大小写;如果有多个字体设定,从左往右依次寻找本地是否有对应的字体即可)

body {
  font-family: 'PingFang SC', 'Microsoft Yahei', simsun;
}

字体族分类:

serifsans-serif 一定要写在最后,因为在大多数浏览器下,写在 serifsans-serif 后面的所有字体都会被忽略

等宽字体一般用于展示代码、一些字符

1ch 表示一个 0 字符的宽度,所以 6 个 0 所占据的宽度就是 6ch,用这个单位和等宽字体可以实现数字/字母一个个出现的效果

font-weight 字重

/* 平常用的最多的 */ font-weight: normal; font-weight: bold; 
/* 相对于父级元素 */ font-weight: lighter; font-weight: bolder; 
/* 字重的精细控制 */ font-weight: 100; font-weight: 200; font-weight: 300; font-weight: 400; font-weight: 500; font-weight: 600; font-weight: 700; font-weight: 800; font-weight: 900;
/* 400 等同于 normal,700 等同于 bold */

这些数值关键字浏览器都是支持的,之所以没有看到任何粗细的变化,是因为我们的系统里面缺乏对应粗细的字体

font-weight 要想真正发挥潜力,问题不在于 CSS 的支持,而在于是否存在对应的字体文件

font-style 倾斜

font-style: normal;
font-style: italic;
font-style: oblique;

italic 是使用当前字体的斜体字体,而 oblique 只是单纯地让文字倾斜

如果当前字体没有对应的斜体字体,则退而求其次,解析为 oblique,也就是单纯形状倾斜

font 属性

可以缩写在 font 属性中的属性非常多,包括 font-stylefont-variantfont-weightfont-sizeline-heightfont-family

完整语法为:

font: [ [ font-style || font-variant || font-weight ]? font-size [ / line-height ]? font-family ]
/* ||表示或,?和正则表达式中的?的含义一致,表示 0 个或 1 个 */

font-sizefont-family 是必需的,是不可以省略的

font 还支持关键字属性值,使用关键字作为属性值的时候必须是独立的,只能使用一下值

font:caption | icon | menu | message-box | small-caption | status-bar

如果将 font 属性设置为上面的一个值,就等同于设置 font 为操作系统该部件对应的 font,也就是说直接使用系统字体

@font-face 规则

@font-face 本质上就是一个定 义字体或字体集的变量,这个变量不仅仅是简单地自定义字体,还包括字体重命名、默认字体样式设置等

@font-face 规则支持的 CSS 属性有 font-familysrcfont-stylefont-weighunicode-rangefont-variantfont-stretchfont-feature-settings,例如:

@font-face {
  font-family: 'example'; /* 给字体取个名字 */
  src: url(example.ttf); /* 字体资源 */
  font-style: normal;
  font-weight: normal;
  unicode-range: U+0025-00FF;
  font-variant: small-caps;
  font-stretch: expanded;
  font-feature-settings:"liga1" on; 
}

src 可以给多种字体格式,因为不同系统兼容性不同,我们可以优先使用 woff2,然后是 woff 格式字体

文本的控制

text-indent 文本缩进

p { text-indent: 2em; }

text-indent 的百分比值是相对于当前元素的“包含块”计算的,而不是当前元素

letter-spacing 字符间距

默认值是 normal,计算值还是 0,支持负值

word-spacing 单词间距

letter-spacing 作用于所有字符,但 word-spacing 仅作用于空格字符

word-break 和 word-wrap

word-break 属性,语法如下:

word-break: normal;
word-break: break-all;
word-break: keep-all;

word-wrap

word-wrap: normal;
word-wrap: break-word;

word-break: break-allword-wrap: break-word 效果区别

white-space

white-space 属性声明了如何处理元素内的空白字符,这类空白字符包括 Space(空格) 键、Enter(回车)键、Tab(制表符)键产生的空白

white-space 的功能分 3 个维度,分别是:是否合并空白字符,是否合并换行符,以及文本是否自动换行

white-space

white-space 设置为 nowrap 的时候,元素的宽度此时表现为“最大可用宽度”,换行符和一些空格全部合并,文本一行显示

text-align 对齐

text-align: justify 两端对齐,除了实现文本的两端对齐,还可以实现容错性更强的两端对齐布局效果

在默认设置下,text-align: justify 要想有两端对齐的效果,需要满足两点:一是有分隔点,如空格;二是要超过一行,此时非最后一行内容会两端对齐

所以可以把子元素设置为 inline-block,在容器上设置伪元素且设置内敛快宽度撑满

text-decoration

text-decoration 属性用于设置或删除文本装饰,装饰线是一条横穿文本基线的线

text-decoration 属性支持的属性值有 noneunderlineoverlineline-throughblink,其中 blink 已经被废弃

下划线可能会和文字重叠,所以一般用 border-bottom 模拟下划线

a {
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: .2em;
}

text-transform 字符大小写

text-transform 也是为英文字符设计的,要么全大写 text-transform: uppercase, 要么全小写 text-transform: lowercase

::first-letter/::first-line 伪元素


🌰 修改价格前面的美元符号

/* .price{$13.50} */
.price::first-letter {
  margin-right: 5px;
  font-size: .8em;
  vertical-align: -2px;
}

🌰 适合单行的使用了 currentColor 的场景

<button class="btn-normal green">确定</button>
<button class="btn-normal red">取消</button>
<style>
  .green { color: #1E887D; }
  .red { color: red; }
  button {
    background: currentColor;
  }
  button::first-line {
    color: white;
  }
</style>

颜色和背景色

color

系统颜色

background

当我们使用 background 属性的时候,实际上使用的是一系列 background 相关属性的集合,包括:

background-position

属性值可以是具体数值,也可以是百分比值,还可以是 lefttoprightcenterbottom 等关键字(CSS 中几乎带 position 的都是这样)

position

如果缺省偏移关键字,则会认为是 center,因此 background-position:top center 可以直接写成 background-position:top

还支持同时出现 3 个值或 4 个值,作用是指定定位的偏移计算从哪个方位算起 background-position: right 40px bottom 20px; 表示距离右边缘 40 像素,距离底边缘 20 像素

也支持百分比值,positionX = (容器的宽度 - 图片的宽度) * percentX;positionY = (容器的高度 - 图片的高度) * percentY;

background-repeat

background-repeat支持 repeatrepeat-xrepeat-y 这几个值

其中 repeat 是默认值,表示在水平和垂直方向都重复,repeat-x 表示在水平方向重复,repeat-y 表示在垂直方向重复

background-attachment

支持 scrollfixed 两个属性值

其中 scroll 是默认值,背景图片会跟着页面滚动

fixed 表示背景相对于当前文档视区定位,也就是页面再怎么滚动背景图片位置依旧纹丝不动

background-color

background-color 背景色永远是最低的(无论是单背景图还是多背景图,背景色一定是在最底下的位置)

设置了背景色的元素,在激活状态(:active/:hover)的时候,可以使用背景图片设置渐变,这样最底部还是原来的背景色,而渐变色是在背景色上层

a[href]:active, button:active {
  background-image: linear-gradient(to top, rgba(0,0,0,.05), rgba(0,0,0,.05));
}

元素的显示与隐藏

使用 CSS 让元素不可见的方法很多,剪裁、定位到屏幕外、明度变化等都是可以的

如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,可以使用 <script> 标签隐藏

<script type="text/html">
  <img src="1.jpg">
</script>

此时,图片 1.jpg 是不会有请求的

<script> 标签是不支持嵌套的,因此,如果希望在 <script> 标签中再放置其他不渲染的模板内容,可以试试使用 <textarea> 元素

<script type="text/html"> 
  <img src="1.jpg"> 
  <textarea style="display:none;"> 
    <img src="2.jpg"> 
  </textarea>
</script> 

图片 2.jpg 也是不会有请求的,<script> 标签隐藏内容获取使用 script.innerHTML<textarea> 使用textarea.value

如果希望元素不可见,同时不占据空间,辅助设备无法访问,但资源有加载,DOM 可访问,则可以直接使用 display: none 隐藏

el { display: none; }

display 计算值是 none 则该元素以及所有后代元素都隐藏

Chrome 和 Safari 浏览器,若父元素 display: none,图片不加载,若本身背景图所在元素隐藏,则图片依旧会去加载

HTML 中有很多标签和属性天然 display: none,如 <style><script><dialog> 元素,如果这些标签在 <body> 元素中,那么设置 display: block 可以让标签内的内容显示在页面中(设置 contenteditable = "true" 可以实时编辑预览)

有的属性也是自带 display: none 的,例如 <input type="hidden" name="id" value="1"><div hidden>None</div> (如果不放心可以在 CSS 加一条 [hidden]{ display: none }

display: none 显隐控制并不会影响 CSS3 animation 动画的实现,但是会影响 CSS3 transition 过渡效果执行(因此 transition 一般搭配 visibilityopacity 使用)

对于计数器列表元素,如果设置 display:none,则该元素不加入计数队列(例如原来 10 个有序列表,将第 2 个设置了 display: none,那么这个元素会消失,且第 3 个会变成 2,总计数是 9)

如果希望元素不可见,同时不占据空间,辅助设备无法访问,但显隐的时候可以有 transition 淡入淡出效果,则可以使用 visibility

.hidden {
  position: absolute;
  visibility: hidden; 
}

如果希望元素不可见,不能点击,辅助设备无法访问,但占据空间保留,则可以使用 visibility:hidden 隐藏

el { visibility: hidden; }

父元素设置 visibility:hidden,子元素也会看不见,究其原因是继承性,子元素继承了 visibility:hidden,但是,如果子元素设置了 visibility:visible,则子元素又会显示出来

visibility:hidden 不会影响计数器的计数,这和 display:none 完全不一样

如果希望元素不可见,不能点击,不占据空间,但键盘可访问,则可以使用 clip 剪裁隐藏

.clip {
  position: absolute;
  clip: rect(0 0 0 0);
}
.out {
  position: relative;
  left: -999em;
}

如果希望元素不可见,不能点击,但占据空间,且键盘可访问,则可以试试 relative 隐藏。例如,如果条件允许,也就是和层叠上下文之间存在设置了背景色的父元素,则也可以使用更友好的 z-index 负值隐藏

.lower {
  position: relative; z-index: -1;
}

如果希望元素不可见,但可以点击,而且不占据空间,则可以使用透明度

.opacity {
  position: absolute;
  opacity: 0;
  filter: Alpha(opacity=0);
}

如果单纯希望元素看不见,但位置保留,依然可以点可以选,则直接让透明度为 0

.opacity {
  opacity: 0;
  filter: Alpha(opacity=0);
}

轮廓和光标

outline 轮廓

outline 表示元素的轮廓,语法和 border 属性非常类似,分宽度、类型和颜色,支持的关键字和属性值与 border 属性一模一样

.outline {
  outline: 1px solid #000;
}

表单按钮 focus 的时候会显示轮廓,按 Tab 可以聚焦到下一个元素,按 Enter 相当于鼠标点击(不要把全局的轮廓都去掉,只去掉需要的就可以)

.input { outline: 0; /* 或者 none */ }
.input:focus {
  border-color: Highlight;
}

outline 是一个真正意义上不占任何空间的属性


🌰 图片镂空效果

<div class="crop">
  <div class="crop-area"></div>
  <img src="1.png" alt="1">
</div>
<style>
.crop { overflow: hidden; }
.crop > .crop-area {
  width: 80px; height: 80px;
  outline: 256px solid rgba(0,0,0,.5); /* 宽度比容器要大 */
  cursor: move;
}
</style>

cursor 光标

常规

链接和状态

选择

拖曳

滚动

拉伸

缩放

抓取

除了自带的还可以自定义光标:

.cur-none {
  cursor: url(transparent.cur);
}

改变流向

direction

通过属性 direction 改变文档流的水平方向

direction: ltr; // 默认值
direction: rtl;

direction 属性默认有这么一个特性,即可以改变替换元素或者 inline-block/ inline-table 元素的水平呈现顺序

HTML 中可以改变顺序

<p dir="rtl">
  <img src="1.jpg">
  <img src="2.jpg">
</p>

按钮的顺序就可以通过这个改变

文字省略也可以用这个改变到前面去

<p class="ell" dir="ltr">这个是默认的,省略号会在这里显示<p>
<p class="ell" dir="rtl">省略号会在前面显示,这里的文字会完整显示出来<p>
<style>
.ell {
  width: 240px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
</style>

direction 属性还可以轻松改变表格中列的呈现顺序(左边的单元格到右边)

directionL:rtl 还可以让 text-justify 两端对齐元素,最后一行落单的元素右对齐

只要是内联元素,只要与书写流相关,都可以试试 direction 属性

unicode-bidi

搭配 unicode-bidi 可以改变文字的方向

unicode-bidi: normal; // 默认值
unicode-bidi: embed;  /* 如果是被下面的声明嵌套的,那么方向会相反 */
unicode-bidi: bidi-override; /* 强制所有的字符按照 direction 的方向排列 */

writing-mode

writing-mode 原本是为控制内联元素的显示而设计的(即所谓的垂直文本布局),用来实现文字竖向呈现

/* 关键字值 */  
writing-mode: horizontal-tb; /* 默认值 文本流是水平方向,元素是从上往下的 */
writing-mode: vertical-rl;  /* 文本是垂直方向,阅读的顺序是从右往左 */
writing-mode: vertical-lr; /* 文本是垂直方向,阅读顺序是从左往由 */
writing-mode: inherit;  
writing-mode: initial;  
writing-mode: unset;

writing-mode 将页面默认的水平流改成了垂直流

.vertical-mode {
  writing-mode: tb-rl;
  -webkit-writing-mode: vertical-rl;
  writing-mode: vertical-rl;
}