CSS 盒子模型深度解析与实战
一、盒子模型核心概念
Box-sizing
CSS 中的 box-sizing 属性定义了引擎应该如何计算一个元素的总宽度和总高度
语法:
box-sizing: content-box|border-box|inherit:
content-box 默认值,元素的 width/height 不包含padding,border,与标准盒子模型表现一致
border-box 元素的 width/height 包含 padding,border,与怪异盒子模型表现一致
inherit 指定 box-sizing 属性的值,应该从父元素继承
1. 盒子模型组成
CSS 盒子模型由四个部分组成(从内到外):
Content(内容区):显示文本、图像等实际内容
Padding(内边距):内容与边框之间的透明区域
Border(边框):围绕内容和内边距的可见边界线
Margin(外边距):盒子与其他元素之间的透明间距
2. 两种盒子模型类型
/* 标准盒模型(默认) */
.box-standard {
box-sizing: content-box; /* width仅包含content */
width: 200px;
padding: 20px;
border: 5px solid;
/* 实际宽度 = 200 + 40 + 10 = 250px */
}
/* IE怪异盒模型 */
.box-ie {
box-sizing: border-box; /* width包含content+padding+border */
width: 200px;
padding: 20px;
border: 5px solid;
/* 实际宽度 = 200px(内容区自动缩小) */
}
二、盒子模型计算原理
标准盒模型计算公式
总宽度 = width + padding-left + padding-right + border-left + border-right + margin-left + margin-right
总高度 = height + padding-top + padding-bottom + border-top + border-bottom + margin-top + margin-bottom怪异盒模型计算公式
总宽度 = width + margin-left + margin-right
总高度 = height + margin-top + margin-bottom
三、实战代码案例
案例1:盒子尺寸对比
<!DOCTYPE html>
<html>
<head>
<style>
.box {
height: 100px;
margin: 20px;
background: #f0f0f0;
}
.content-box {
box-sizing: content-box;
width: 200px;
padding: 20px;
border: 5px solid red;
}
.border-box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid blue;
}
</style>
</head>
<body>
<div class="box content-box">标准盒模型(实际宽度:270px)</div>
<div class="box border-box">怪异盒模型(实际宽度:200px)</div>
</body>
</html>
案例2:margin合并现象
<style>
.parent {
background: lightyellow;
margin-bottom: 50px;
}
.child {
background: lightblue;
margin-top: 30px;
height: 100px;
/* 实际间距为50px而非80px */
}
</style>
<div class="parent">
<div class="child">margin合并示例</div>
</div>
四、面试深度问题
- 如何解决margin合并问题?
使用padding替代margin
创建BFC(设置overflow: hidden等)
使用透明边框(border: 1px solid transparent) - 为什么推荐使用border-box?
更直观的尺寸控制(width即实际可见宽度)
简化响应式布局计算
避免padding/border导致的布局溢出 - 获取元素最终尺寸的方法对比
// 包含padding+border+scrollbar element.offsetWidth
// 包含padding但不包含border和scrollbar element.clientWidth
// 获取计算样式(字符串形式) window.getComputedStyle(element).width
// 获取精确的几何位置和尺寸 element.getBoundingClientRect().width
五、可视化记忆图表
盒子模型对比图
标准盒模型(content-box)
+---------------------------+
| margin |
| +---------------------+ |
| | border | |
| | +-------------+ | |
| | | padding | | |
| | | +-----+ | | |
| | | |content| | | |
| | | +-----+ | | |
| | +-------------+ | |
| +---------------------+ |
+---------------------------+
怪异盒模型(border-box)
+---------------------------+
| margin |
| +---------------------+ |
| | border+padding | |
| | +-------------+ | |
| | | content | | |
| | | | | |
| | | | | |
| | +-------------+ | |
| +---------------------+ |
+---------------------------+
css选择器有哪些?优先级?哪些属性可以继承?
一、选择器
CSS选择器是CSS规则的第一部分
它是元素和其他部分组合起来告诉浏览器哪个HTML元素应当是被选为应用规则中的CSS属性值的方式
选择器所选择的元素,叫做“选择器的对象”
从一个Html结构开始
<div id="box">
<div class="one">
<p class="one_1">
</p >
<p class="one_1">
</p >
</div>
<div class="two"></div>
<div class="two"></div>
<div class="two"></div>
</div>
关于css属性选择器常用的有:
id选择器(#box),选择id为box的元素
类选择器( . one),选择类名为one的所有元素
标签选择器(div),选择标签为div的所有元素
通配符选择器:(*),选择所有元素
后代选择器(#box div),选择id为box元素内部所有的div元素
子选择器(.one > one_1),选择 父元素为.one的所有.one_1的元素
相邻同胞选择器(.one + .two),选择紧接在.one之后的所有.two元素
群组选择器(div , p),选择div、p的所有元素
还有一些使用频率相对没那么多的选择器:
伪类选择器示例
/* 未被访问的链接 */
a:link { color: blue; }
/* 已被访问的链接 */
a:visited { color: purple; }
/* 鼠标悬停时 */
a:hover { color: red; }
/* 活动链接(被点击时) */
a:active { color: green; }
/* 获得焦点的输入框 */
input:focus { border-color: yellow; }
/* 父元素的首个子元素 */
li:first-child { font-weight: bold; }
伪元素选择器示例
/* 段落首字母 */
p::first-letter { font-size: 2em; }
/* 段落首行 */
p::first-line { text-transform: uppercase; }
/* 在元素前插入内容 */
h1::before { content: "★ "; }
/* 在元素后插入内容 */
h1::after { content: " ★"; }
属性选择器示例
/* 带有title属性的元素 */
[title] { border: 1px dotted gray; }
/* href等于指定值的链接 */
a[href="https://example.com"] { color: red; }
/* class包含"logo"的元素 */
[class~="logo"] { background: yellow; }
/* lang属性以"en"开头的元素 */
[lang|="en"] { quotes: '"' '"'; }
CSS3新增选择器示例
层次选择器
/* 选择前面有p元素的每个ul元素 */
p ~ ul { margin-left: 20px; }
新增伪类选择器
/* 同类型中的第一个元素 */
p:first-of-type { color: blue; }
/* 同类型中的最后一个元素 */
p:last-of-type { color: red; }
/* 没有同类型兄弟的元素 */
div:only-of-type { border: 1px solid black; }
/* 第二个子元素 */
li:nth-child(2) { background: lightgray; }
/* 倒数第二个同类型元素 */
p:nth-last-of-type(2) { font-style: italic; }
/* 禁用状态的输入框 */
input:disabled { opacity: 0.5; }
/* 未被选中的复选框 */
input[type="checkbox"]:not(:checked) + label {
color: #ccc;
}
新增属性选择器
/* href包含"example"的链接 */
a[href*="example"] { color: purple; }
/* href以"https"开头的链接 */
a[href^="https"] { font-weight: bold; }
/* src以".png"结尾的图片 */
img[src$=".png"] { border: 1px solid green; }
二、优先级计算规则
优先级由四个级别 (A, B, C, D) 组成:
- 内联样式 (A):
style="..."
→ A=1 - ID选择器 (B):每有一个ID选择器,B+1
- 类/属性/伪类(C ):每有一个,C+1
- 元素/伪元素 (D):每有一个,D+1
优先级速查表
选择器类型 | 示例 | 优先级 (A,B,C,D) |
---|---|---|
内联样式 | style=“color:red” | (1,0,0,0) |
ID选择器 | #main | (0,1,0,0) |
类/属性/伪类 | .box, [type], :hover | (0,0,1,0) |
元素/伪元素 | div, ::before | (0,0,0,1) |
通配符/继承 | *, 继承属性 | (0,0,0,0) |
关键规则总结
- 比较顺序:从左到右逐级比较 (A→B→C→D)
- !important:强制生效(慎用,难以覆盖)
- 权重顺序:内联 > ID > 类/伪类 > 元素 > 通配符
- 同级比较:相同优先级时,后定义的生效
- 组合选择器:各部分的权重相加计算
CSS 选择器优先级实战解析
示例1:基础优先级比较
<div class="box" id="main">Hello, CSS!</div>
#main { color: blue; } /* (0,1,0,0) */
.box { color: red; } /* (0,0,1,0) */
div { color: green; } /* (0,0,0,1) */
✅ 结果:蓝色
🔍 解析:ID选择器(#main) > 类选择器(.box) > 元素选择器(div)
示例2:组合选择器优先级
<div class="container">
<p class="text">Hello, World!</p>
</div>
.container .text { color: blue; } /* (0,0,2,0) */
p.text { color: red; } /* (0,0,1,1) */
.text { color: green; } /* (0,0,1,0) */
✅ 结果:蓝色
🔍 解析:两个类选择器 > (1类+1元素) > 单个类选择器
示例3:内联样式 vs ID选择器
<p id="title" style="color: purple;">CSS Priority</p>
#title { color: blue; } /* (0,1,0,0) */
p { color: red; } /* (0,0,0,1) */
✅ 结果:紫色
🔍 解析:内联样式(1,0,0,0) > ID选择器(0,1,0,0)
示例4:!important 的威力
<p class="message">Hello!</p>
.message { color: red !important; } /* 强制生效 */
p { color: blue; } /* (0,0,0,1) */
✅ 结果:红色
🔍 解析:!important 强制覆盖所有普通规则
示例5:伪类选择器优先级
<a href="#" class="link">Click Me</a>
a.link:hover { color: orange; } /* (0,0,2,1) */
.link { color: blue; } /* (0,0,1,0) */
a { color: red; } /* (0,0,0,1) */
✅ 悬停结果:橙色
🔍 解析:a.link:hover = 1元素+1类+1伪类(0,0,2,1) > .link(0,0,1,0)
实战技巧
- 避免过度使用ID选择器:会导致优先级过高,难以覆盖
- 谨慎使用!important:除非必要,否则用提升选择器优先级的方式
- 利用继承特性:合理使用
inherit
关键字 - 调试工具:浏览器开发者工具会显示应用样式的优先级
/* 良好的优先级管理示例 */
.component .item { ... } /* (0,0,2,0) */
.item.active { ... } /* (0,0,2,0) */
/* 而不是 */
#component div { ... } /* (0,1,0,1) 过高优先级 */
通过理解这些优先级规则,你可以更精准地控制样式应用,避免意外的样式覆盖问题!
说说em/px/rem/vh/vw区别?
#一、介绍
传统的项目开发中,我们只会用到px
、%
、em
这几个单位,它可以适用于大部分的项目开发,且拥有比较良好的兼容性
从CSS3
开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了rem
、vh
、vw
、vm
等一些新的计量单位
利用这些新的单位开发出比较良好的响应式页面,适应多种不同分辨率的终端,包括移动设备等
#二、单位
在css
单位中,可以分为长度单位、绝对单位,如下表所指示
CSS单位 | |
---|---|
相对长度单位 | em、ex、ch、rem、vw、vh、vmin、vmax、% |
绝对长度单位 | cm、mm、in、px、pt、pc |
这里我们主要讲述px、em、rem、vh、vw
#px
px,表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中
有些人会把px
认为是相对长度,原因在于在移动端中存在设备像素比,px
实际显示的大小是不确定的
这里之所以认为px
为绝对单位,在于px
的大小和元素的其他属性无关
#em
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(1em = 16px
)
为了简化 font-size
的换算,我们需要在css
中的 body
选择器中声明font-size
= 62.5%
,这就使 em 值变为 16px*62.5% = 10px
这样 12px = 1.2em
, 10px = 1em
, 也就是说只需要将你的原来的px
数值除以 10,然后换上 em
作为单位就行了
特点:
- em 的值并不是固定的
- em 会继承父级元素的字体大小
- em 是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸
- 任意浏览器的默认字体高都是 16px
举个例子
<div class="big">
我是14px=1.4rem<div class="small">我是12px=1.2rem</div>
</div>
样式为
<style>
html {font-size: 10px; } /* 公式16px*62.5%=10px */
.big{font-size: 1.4rem}
.small{font-size: 1.2rem}
</style>
这时候.big
元素的font-size
为14px,而.small
元素的font-size
为12px
#rem
rem,相对单位,相对的只是HTML根元素font-size
的值
同理,如果想要简化font-size
的转化,我们可以在根元素html
中加入font-size: 62.5%
html {font-size: 62.5%; } /* 公式16px*62.5%=10px */
这样页面中1rem=10px、1.2rem=12px、1.4rem=14px、1.6rem=16px;使得视觉、使用、书写都得到了极大的帮助
特点:
- rem单位可谓集相对大小和绝对大小的优点于一身
- 和em不同的是rem总是相对于根元素,而不像em一样使用级联的方式来计算尺寸
#vh、vw
vw ,就是根据窗口的宽度,分成100等份,100vw就表示满宽,50vw就表示一半宽。(vw 始终是针对窗口的宽),同理,vh
则为窗口的高度
这里的窗口分成几种情况:
-
在桌面端,指的是浏览器的可视区域
-
移动端指的就是布局视口
像vw
、vh
,比较容易混淆的一个单位是%
,不过百分比宽泛的讲是相对于父元素:
- 对于普通定位元素就是我们理解的父元素
- 对于position: absolute;的元素是相对于已定位的父元素
- 对于position: fixed;的元素是相对于 ViewPort(可视窗口)
#三、总结
px:绝对单位,页面按精确像素展示
em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size
按自身来计算,整个页面内1em
不是一个固定的值
rem:相对单位,可理解为root em
, 相对根节点html
的字体大小来计算
vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
说说设备像素、css像素、设备独立像素、dpr、ppi 之间的区别?
#一、背景
在css
中我们通常使用px作为单位,在PC浏览器中css
的1个像素都是对应着电脑屏幕的1个物理像素,这会造成一种错觉,我们会认为css
中的像素就是设备的物理像素
但实际情况却并非如此,css
中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css
中的1px所代表的设备物理像素是不同的
当我们做移动端开发时,同为1px的设置,在不同分辨率的移动设备上显示效果却有很大差异
这背后就涉及了css像素、设备像素、设备独立像素、dpr、ppi的概念
#二、介绍
#CSS像素
CSS像素(css pixel, px): 适用于web编程,在 CSS 中以 px 为后缀,是一个长度单位
在 CSS 规范中,长度单位可以分为两类,绝对单位以及相对单位
px是一个相对单位,相对的是设备像素(device pixel)
一般情况,页面缩放比为1,1个CSS像素等于1个设备独立像素
CSS
像素又具有两个方面的相对性:
- 在同一个设备上,每1个 CSS 像素所代表的设备像素是可以变化的(比如调整屏幕的分辨率)
- 在不同的设备之间,每1个 CSS 像素所代表的设备像素是可以变化的(比如两个不同型号的手机)
在页面进行缩放操作也会 引起css
中px
的变化,假设页面放大一倍,原来的 1px 的东西变成 2px,在实际宽度不变的情况下1px 变得跟原来的 2px 的长度(长宽)一样了(元素会占据更多的设备像素)
假设原来需要 320px 才能填满的宽度现在只需要 160px
px会受到下面的因素的影响而变化:
- 每英寸像素(PPI)
- 设备像素比(DPR)
#设备像素
设备像素(device pixels),又称为物理像素
指设备能控制显示的最小物理单位,不一定是一个小正方形区块,也没有标准的宽高,只是用于显示丰富色彩的一个“点”而已
可以参考公园里的景观变色彩灯,一个彩灯(物理像素)由红、蓝、绿小灯组成,三盏小灯不同的亮度混合出各种色彩
从屏幕在工厂生产出的那天起,它上面设备像素点就固定不变了,单位为pt
#设备独立像素
设备独立像素(Device Independent Pixel):与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,包括了CSS像素
在
javaScript
中可以通过window.screen.width/ window.screen.height
查看
比如我们会说“电脑屏幕在 2560x1600分辨率下不适合玩游戏,我们把它调为 1440x900”,这里的“分辨率”(非严谨说法)指的就是设备独立像素
一个设备独立像素里可能包含1个或者多个物理像素点,包含的越多则屏幕看起来越清晰
至于为什么出现设备独立像素这种虚拟像素单位概念,下面举个例子:
iPhone 3GS 和 iPhone 4/4s 的尺寸都是 3.5 寸,但 iPhone 3GS 的分辨率是 320x480,iPhone 4/4s 的分辨率是 640x960
这意味着,iPhone 3GS 有 320 个物理像素,iPhone 4/4s 有 640 个物理像素
如果我们按照真实的物理像素进行布局,比如说我们按照 320 物理像素进行布局,到了 640 物理像素的手机上就会有一半的空白,为了避免这种问题,就产生了虚拟像素单位
我们统一 iPhone 3GS 和 iPhone 4/4s 都是 320 个虚拟像素,只是在 iPhone 3GS 上,最终 1 个虚拟像素换算成 1 个物理像素,在 iphone 4s 中,1 个虚拟像素最终换算成 2 个物理像素
至于 1 个虚拟像素被换算成几个物理像素,这个数值我们称之为设备像素比,也就是下面介绍的dpr
#dpr
dpr(device pixel ratio),设备像素比,代表设备独立像素到设备像素的转换关系,在
JavaScript
中可以通过window.devicePixelRatio
获取
计算公式如下:
- 当设备像素比为1:1时,使用1(1×1)个设备像素显示1个CSS像素
- 当设备像素比为2:1时,使用4(2×2)个设备像素显示1个CSS像素
- 当设备像素比为3:1时,使用9(3×3)个设备像素显示1个CSS像素
如下图所示:
当dpr
为3,那么1px
的CSS
像素宽度对应3px
的物理像素的宽度,1px的CSS
像素高度对应3px
的物理像素高度
#ppi
ppi (pixel per inch),每英寸像素,表示每英寸所包含的像素点数目,更确切的说法应该是像素密度。数值越高,说明屏幕能以更高密度显示图像
计算公式如下:
#三、总结
无缩放情况下,1个CSS像素等于1个设备独立像素
设备像素由屏幕生产之后就不发生改变,而设备独立像素是一个虚拟单位会发生改变
PC端中,1个设备独立像素 = 1个设备像素 (在100%,未缩放的情况下)
在移动端中,标准屏幕(160ppi)下 1个设备独立像素 = 1个设备像素
设备像素比(dpr) = 设备像素 / 设备独立像素
每英寸像素(ppi),值越大,图像越清晰
📱 设备像素(物理小灯)
│
├── 🔍 PPI(每英寸小灯数量)→ 越高越清晰
│
📐 设备独立像素(设计图格子)
│
├── ⚖️ DPR(格子与小灯的比例)→ 例如 DPR=2: 1格=4小灯
│
🖌️ CSS像素(你写的代码:width: 100px)
│
├── 🔄 用户缩放页面 → 改变格子实际占用的小灯数量
│
📦 实际显示效果 = CSS像素 × DPR × 物理小灯尺寸
让Chrome支持小于12px 的文字方式有哪些?区别?
#一、背景
Chrome 中文版浏览器会默认设定页面的最小字号是12px,英文版没有限制
原由 Chrome 团队认为汉字小于12px就会增加识别难度
- 中文版浏览器
与网页语言无关,取决于用户在Chrome的设置里(chrome://settings/languages)把哪种语言设置为默认显示语言
- 系统级最小字号
浏览器默认设定页面的最小字号,用户可以前往 chrome://settings/fonts 根据需求更改
而我们在实际项目中,不能奢求用户更改浏览器设置
对于文本需要以更小的字号来显示,就需要用到一些小技巧
#二、解决方案
常见的解决方案有:
- zoom
- -webkit-transform:scale()
- -webkit-text-size-adjust:none
#Zoom
zoom
的字面意思是“变焦”,可以改变页面上元素的尺寸,属于真实尺寸
其支持的值类型有:
- zoom:50%,表示缩小到原来的一半
- zoom:0.5,表示缩小到原来的一半
使用 zoom
来”支持“ 12px 以下的字体
代码如下:
<style type="text/css">
.span1{
font-size: 12px;
display: inline-block;
zoom: 0.8;
}
.span2{
display: inline-block;
font-size: 12px;
}
</style>
<body>
<span class="span1">测试10px</span>
<span class="span2">测试12px</span>
</body>
效果如下:
需要注意的是,
Zoom
并不是标准属性,需要考虑其兼容性
#
#-webkit-transform:scale()
针对chrome
浏览器,加webkit
前缀,用transform:scale()
这个属性进行放缩
注意的是,使用scale
属性只对可以定义宽高的元素生效,所以,下面代码中将span
元素转为行内块元素
实现代码如下:
<style type="text/css">
.span1{
font-size: 12px;
display: inline-block;
-webkit-transform:scale(0.8);
}
.span2{
display: inline-block;
font-size: 12px;
}
</style>
<body>
<span class="span1">测试10px</span>
<span class="span2">测试12px</span>
</body>
效果如下:
#-webkit-text-size-adjust:none
该属性用来设定文字大小是否根据设备(浏览器)来自动调整显示大小
属性值:
- percentage:字体显示的大小;
- auto:默认,字体大小会根据设备/浏览器来自动调整;
- none:字体大小不会自动调整
html { -webkit-text-size-adjust: none; }
这样设置之后会有一个问题,就是当你放大网页时,一般情况下字体也会随着变大,而设置了以上代码后,字体只会显示你当前设置的字体大小,不会随着网页放大而变大了
所以,我们不建议全局应用该属性,而是单独对某一属性使用
需要注意的是,自从
chrome 27
之后,就取消了对这个属性的支持。同时,该属性只对英文、数字生效,对中文不生效
#三、总结
Zoom
非标属性,有兼容问题,缩放会改变了元素占据的空间大小,触发重排
-webkit-transform:scale()
大部分现代浏览器支持,并且对英文、数字、中文也能够生效,缩放不会改变了元素占据的空间大小,页面布局不会发生变化
-webkit-text-size-adjust
对谷歌浏览器有版本要求,在27之后,就取消了该属性的支持,并且只对英文、数字生效
特性 | zoom 属性 | transform: scale() | text-size-adjust |
---|---|---|---|
兼容性 | ❌ 非标准属性 | ✅ 主流浏览器支持 | 🚫 Chrome 27+ 失效 |
布局影响 | ⚠️ 触发重排 | ✅ 不改变布局 | ✅ 不影响布局 |
中文支持 | ✅ 有效 | ✅ 有效 | ❌ 无效 |
响应式能力 | ❌ 固定缩放 | ✅ 动态调整 | ❌ 固定大小 |
性能影响 | ⚠️ 较高 | ✅ GPU加速 | ✅ 无额外消耗 |
推荐使用场景 | 传统IE兼容 | 现代浏览器元素动画/适配 | 已弃用 |
如果要做优化,CSS提高性能的方法有哪些?
#一、前言
每一个网页都离不开css
,但是很多人又认为,css
主要是用来完成页面布局的,像一些细节或者优化,就不需要怎么考虑,实际上这种想法是不正确的
作为页面渲染和内容展现的重要环节,css
影响着用户对整个网站的第一体验
因此,在整个产品研发过程中,css
性能优化同样需要贯穿全程
#二、实现方式
实现方式有很多种,主要有如下:
- 内联首屏关键CSS
- 异步加载CSS
- 资源压缩
- 合理使用选择器
- 减少使用昂贵的属性
- 不要使用@import
#内联首屏关键CSS
在打开一个页面,页面首要内容出现在屏幕的时间影响着用户的体验,而通过内联css
关键代码能够使浏览器在下载完html
后就能立刻渲染
而如果外部引用css
代码,在解析html
结构过程中遇到外部css
文件,才会开始下载css
代码,再渲染
所以,CSS
内联使用使渲染时间提前
注意:但是较大的css
代码并不合适内联(初始拥塞窗口、没有缓存),而其余代码则采取外部引用方式
#异步加载CSS
在CSS
文件请求、下载、解析完成之前,CSS
会阻塞渲染,浏览器将不会渲染任何已处理的内容
前面加载内联代码后,后面的外部引用css
则没必要阻塞浏览器渲染。这时候就可以采取异步加载的方案,主要有如下:
- 使用javascript将link标签插到head标签最后
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
- 设置link标签media属性为noexis,浏览器会认为当前样式表不适用当前类型,会在不阻塞页面渲染的情况下再进行下载。加载完成后,将
media
的值设为screen
或all
,从而让浏览器开始解析CSS
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
- 通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。同样别忘了加载完成之后,将rel设回stylesheet
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
#资源压缩
利用webpack
、gulp/grunt
、rollup
等模块化工具,将css
代码进行压缩,使文件变小,大大降低了浏览器的加载时间
#合理使用选择器
css
匹配的规则是从右往左开始匹配,例如#markdown .content h3
匹配规则如下:
- 先找到h3标签元素
- 然后去除祖先不是.content的元素
- 最后去除祖先不是#markdown的元素
如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高
所以我们在编写选择器的时候,可以遵循以下规则:
- 不要嵌套使用过多复杂选择器,最好不要三层以上
- 使用id选择器就没必要再进行嵌套
- 通配符和属性选择器效率最低,避免使用
#减少使用昂贵的属性
在页面发生重绘的时候,昂贵属性如box-shadow
/border-radius
/filter
/透明度/:nth-child
等,会降低浏览器的渲染性能
#不要使用@import
css样式文件有两种引入方式,一种是link
元素,另一种是@import
@import
会影响浏览器的并行下载,使得页面在加载时增加额外的延迟,增添了额外的往返耗时
而且多个@import
可能会导致下载顺序紊乱
比如一个css文件index.css
包含了以下内容:@import url("reset.css")
那么浏览器就必须先把index.css
下载、解析和执行后,才下载、解析和执行第二个文件reset.css
#其他
- 减少重排操作,以及减少不必要的重绘
- 了解哪些属性可以继承而来,避免对这些属性重复编写
- cssSprite,合成所有icon图片,用宽高加上backgroud-position的背景图方式显现出我们要的icon图,减少了http请求
- 把小的icon图片转成base64编码
- CSS3动画或者过渡尽量使用transform和opacity来实现动画,不要使用left和top属性
#三、总结
css
实现性能的方式可以从选择器嵌套、属性特性、减少http
这三面考虑,同时还要注意css
代码的加载顺序
css中,有哪些方式可以隐藏页面元素?区别?
#一、前言
在平常的样式排版中,我们经常遇到将某个模块隐藏的场景
通过css
隐藏元素的方法有很多种,它们看起来实现的效果是一致的
但实际上每一种方法都有一丝轻微的不同,这些不同决定了在一些特定场合下使用哪一种方法
#二、实现方式
通过
css
实现隐藏元素方法有如下:
- display:none
- visibility:hidden
- opacity:0
- 设置height、width模型属性为0
- position:absolute
- clip-path
#display:none
设置元素的display
为none
是最常用的隐藏元素的方法
.hide {
display:none;
}
将元素设置为display:none
后,元素在页面上将彻底消失
元素本身占有的空间就会被其他元素占有,也就是说它会导致浏览器的重排和重绘
消失后,自身绑定的事件不会触发,也不会有过渡效果
特点:元素不可见,不占据空间,无法响应点击事件
#visibility:hidden
设置元素的visibility
为hidden
也是一种常用的隐藏元素的方法
从页面上仅仅是隐藏该元素,DOM结果均会存在,只是当时在一个不可见的状态,不会触发重排,但是会触发重绘
.hidden{
visibility:hidden
}
给人的效果是隐藏了,所以他自身的事件不会触发
特点:元素不可见,占据页面空间,无法响应点击事件
#opacity:0
opacity
属性表示元素的透明度,将元素的透明度设置为0后,在我们用户眼中,元素也是隐藏的
不会引发重排,一般情况下也会引发重绘
如果利用 animation 动画,对 opacity 做变化(animation会默认触发GPU加速),则只会触发 GPU 层面的 composite,不会触发重绘
.transparent {
opacity:0;
}
由于其仍然是存在于页面上的,所以他自身的的事件仍然是可以触发的,但被他遮挡的元素是不能触发其事件的
需要注意的是:其子元素不能设置opacity来达到显示的效果
特点:改变元素透明度,元素不可见,占据页面空间,可以响应点击事件
#设置height、width属性为0
将元素的margin
,border
,padding
,height
和width
等影响元素盒模型的属性设置成0,如果元素内有子元素或内容,还应该设置其overflow:hidden
来隐藏其子元素
.hiddenBox {
margin:0;
border:0;
padding:0;
height:0;
width:0;
overflow:hidden;
}
特点:元素不可见,不占据页面空间,无法响应点击事件
#position:absolute
将元素移出可视区域
.hide {
position: absolute;
top: -9999px;
left: -9999px;
}
特点:元素不可见,不影响页面布局
#clip-path
通过裁剪的形式
.hide {
clip-path: polygon(0px 0px,0px 0px,0px 0px,0px 0px);
}
特点:元素不可见,占据页面空间,无法响应点击事件
#小结
最常用的还是display:none
和visibility:hidden
,其他的方式只能认为是奇招,它们的真正用途并不是用于隐藏元素,所以并不推荐使用它们
#三、区别
关于display: none
、visibility: hidden
、opacity: 0
的区别,如下表所示:
display: none | visibility: hidden | opacity: 0 | |
---|---|---|---|
页面中 | 不存在 | 存在 | 存在 |
重排 | 会 | 不会 | 不会 |
重绘 | 会 | 会 | 不一定 |
自身绑定事件 | 不触发 | 不触发 | 可触发 |
transition | 不支持 | 支持 | 支持 |
子元素可复原 | 不能 | 能 | 不能 |
被遮挡的元素可触发事件 | 能 | 能 | 不能 |
如何实现单行/多行文本溢出的省略样式?
#一、前言
在日常开发展示页面,如果一段文本的数量过长,受制于元素宽度的因素,有可能不能完全显示,为了提高用户的使用体验,这个时候就需要我们把溢出的文本显示成省略号
对于文本的溢出,我们可以分成两种形式:
- 单行文本溢出
- 多行文本溢出
#二、实现方式
#单行文本溢出省略
理解也很简单,即文本在一行内显示,超出部分以省略号的形式展现
实现方式也很简单,涉及的css
属性有:
- text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本
- white-space:设置文字在一行显示,不能换行
- overflow:文字长度超出限定宽度,则隐藏超出的内容
overflow
设为hidden
,普通情况用在块级元素的外层隐藏内部溢出元素,或者配合下面两个属性实现文本溢出省略
white-space:nowrap
,作用是设置文本不换行,是overflow:hidden
和text-overflow:ellipsis
生效的基础
text-overflow
属性值有如下:
- clip:当对象内文本溢出部分裁切掉
- ellipsis:当对象内文本溢出时显示省略标记(...)
text-overflow
只有在设置了overflow:hidden
和white-space:nowrap
才能够生效的
举个例子
<style>
p{
overflow: hidden;
line-height: 40px;
width:400px;
height:40px;
border:1px solid red;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
<p 这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本</p >
效果如下:
可以看到,设置单行文本溢出较为简单,并且省略号显示的位置较好
#多行文本溢出省略
多行文本溢出的时候,我们可以分为两种情况:
- 基于高度截断
- 基于行数截断
#基于高度截断
#伪元素 + 定位
核心的css
代码结构如下:
- position: relative:为伪元素绝对定位
- overflow: hidden:文本溢出限定的宽度就隐藏内容)
- position: absolute:给省略号绝对定位
- line-height: 20px:结合元素高度,高度固定的情况下,设定行高, 控制显示行数
- height: 40px:设定当前元素高度
- ::after {} :设置省略号样式
代码如下所示:
<style>
.demo {
position: relative;
line-height: 20px;
height: 40px;
overflow: hidden;
}
.demo::after {
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding: 0 20px 0 10px;
}
</style>
<body>
<div class='demo'>这是一段很长的文本</div>
</body>
实现原理很好理解,就是通过伪元素绝对定位到行尾并遮住文字,再通过 overflow: hidden
隐藏多余文字
这种实现具有以下优点:
- 兼容性好,对各大主流浏览器有好的支持
- 响应式截断,根据不同宽度做出调整
一般文本存在英文的时候,可以设置word-break: break-all
使一个单词能够在换行时进行拆分
#基于行数截断
纯css
实现也非常简单,核心的css
代码如下:
- -webkit-line-clamp: 2:用来限制在一个块元素显示的文本的行数,为了实现该效果,它需要组合其他的WebKit属性)
- display: -webkit-box:和1结合使用,将对象作为弹性伸缩盒子模型显示
- -webkit-box-orient: vertical:和1结合使用 ,设置或检索伸缩盒对象的子元素的排列方式
- overflow: hidden:文本溢出限定的宽度就隐藏内容
- text-overflow: ellipsis:多行文本的情况下,用省略号“…”隐藏溢出范围的文本
<style>
p {
width: 400px;
border-radius: 1px solid red;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<p>
这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本
这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本
</p >
可以看到,上述使用了webkit
的CSS
属性扩展,所以兼容浏览器范围是PC
端的webkit
内核的浏览器,由于移动端大多数是使用webkit
,所以移动端常用该形式
需要注意的是,如果文本为一段很长的英文或者数字,则需要添加word-wrap: break-word
属性
还能通过使用javascript
实现配合css
,实现代码如下所示:
css结构如下:
p {
position: relative;
width: 400px;
line-height: 20px;
overflow: hidden;
}
.p-after:after{
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding-left: 40px;
background: -webkit-linear-gradient(left, transparent, #fff 55%);
background: -moz-linear-gradient(left, transparent, #fff 55%);
background: -o-linear-gradient(left, transparent, #fff 55%);
background: linear-gradient(to right, transparent, #fff 55%);
}
javascript代码如下:
$(function(){
//获取文本的行高,并获取文本的高度,假设我们规定的行数是五行,那么对超过行数的部分进行限制高度,并加上省略号
$('p').each(function(i, obj){
var lineHeight = parseInt($(this).css("line-height"));
var height = parseInt($(this).height());
if((height / lineHeight) >3 ){
$(this).addClass("p-after")
$(this).css("height","60px");
}else{
$(this).removeClass("p-after");
}
});
})
说说flexbox(弹性盒布局模型),以及适用场景?
#一、是什么
Flexible Box
简称 flex
,意为”弹性布局”,可以简便、完整、响应式地实现各种页面布局
采用Flex布局的元素,称为flex
容器container
它的所有子元素自动成为容器成员,称为flex
项目item
容器中默认存在两条轴,主轴和交叉轴,呈90度关系。项目默认沿主轴排列,通过flex-direction
来决定主轴的方向
每根轴都有起点和终点,这对于元素的对齐非常重要
#二、属性
关于flex
常用的属性,我们可以划分为容器属性和容器成员属性
容器属性有:
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
#flex-direction
决定主轴的方向(即项目的排列方向)
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
属性对应如下:
- row(默认值):主轴为水平方向,起点在左端
- row-reverse:主轴为水平方向,起点在右端
- column:主轴为垂直方向,起点在上沿。
- column-reverse:主轴为垂直方向,起点在下沿
如下图所示:
#flex-wrap
弹性元素永远沿主轴排列,那么如果主轴排不下,通过flex-wrap
决定容器内项目是否可换行
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
属性对应如下:
- nowrap(默认值):不换行
- wrap:换行,第一行在下方
- wrap-reverse:换行,第一行在上方
默认情况是不换行,但这里也不会任由元素直接溢出容器,会涉及到元素的弹性伸缩
#flex-flow
是flex-direction
属性和flex-wrap
属性的简写形式,默认值为row nowrap
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
#justify-content
定义了项目在主轴上的对齐方式
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
属性对应如下:
- flex-start(默认值):左对齐
- flex-end:右对齐
- center:居中
- space-between:两端对齐,项目之间的间隔都相等
- space-around:两个项目两侧间隔相等
效果图如下:
#align-items
定义项目在交叉轴上如何对齐
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
属性对应如下:
- flex-start:交叉轴的起点对齐
- flex-end:交叉轴的终点对齐
- center:交叉轴的中点对齐
- baseline: 项目的第一行文字的基线对齐
- stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
#align-content
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
属性对应如吓:
- flex-start:与交叉轴的起点对齐
- flex-end:与交叉轴的终点对齐
- center:与交叉轴的中点对齐
- space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
- space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
- stretch(默认值):轴线占满整个交叉轴
效果图如下:
容器成员属性如下:
order
flex-grow
flex-shrink
flex-basis
flex
align-self
#order
定义项目的排列顺序。数值越小,排列越靠前,默认为0
.item {
order: <integer>;
}
#flex-grow
上面讲到当容器设为flex-wrap: nowrap;
不换行的时候,容器宽度有不够分的情况,弹性元素会根据flex-grow
来决定
定义项目的放大比例(容器宽度>元素总宽度时如何伸展)
默认为0
,即如果存在剩余空间,也不放大
.item {
flex-grow: <number>;
}
如果所有项目的flex-grow
属性都为1,则它们将等分剩余空间(如果有的话)
如果一个项目的flex-grow
属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍
弹性容器的宽度正好等于元素宽度总和,无多余宽度,此时无论flex-grow
是什么值都不会生效
#flex-shrink
定义了项目的缩小比例(容器宽度<元素总宽度时如何收缩),默认为1,即如果空间不足,该项目将缩小
.item {
flex-shrink: <number>; /* default 1 */
}
如果所有项目的flex-shrink
属性都为1,当空间不足时,都将等比例缩小
如果一个项目的flex-shrink
属性为0,其他项目都为1,则空间不足时,前者不缩小
在容器宽度有剩余时,flex-shrink
也是不会生效的
#flex-basis
设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-grow
和flex-shrink
生效前的尺寸
浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto
,即项目的本来大小,如设置了width
则元素尺寸由width/height
决定(主轴方向),没有设置则由内容决定
.item {
flex-basis: <length> | auto; /* default auto */
}
当设置为0的是,会根据内容撑开
它可以设为跟width
或height
属性一样的值(比如350px),则项目将占据固定空间
#flex
flex
属性是flex-grow
, flex-shrink
和 flex-basis
的简写,默认值为0 1 auto
,也是比较难懂的一个复合属性
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
一些属性有:
- flex: 1 = flex: 1 1 0%
- flex: 2 = flex: 2 1 0%
- flex: auto = flex: 1 1 auto
- flex: none = flex: 0 0 auto,常用于固定尺寸不伸缩
flex:1
和 flex:auto
的区别,可以归结于flex-basis:0
和flex-basis:auto
的区别
当设置为0时(绝对弹性元素),此时相当于告诉flex-grow
和flex-shrink
在伸缩的时候不需要考虑我的尺寸
当设置为auto
时(相对弹性元素),此时则需要在伸缩时将元素尺寸纳入考虑
注意:建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值
#align-self
允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性
默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
效果图如下:
#三、应用场景
在以前的文章中,我们能够通过flex
简单粗暴的实现元素水平垂直方向的居中,以及在两栏三栏自适应布局中通过flex
完成,这里就不再展开代码的演示
包括现在在移动端、小程序这边的开发,都建议使用flex
进行布局
介绍一下grid网格布局
#一、是什么
Grid
布局即网格布局,是一个二维的布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列
擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系
这与之前讲到的flex
一维布局不相同
设置display:grid/inline-grid
的元素就是网格布局容器,这样就能出发浏览器渲染引擎的网格布局算法
<div class="container">
<div class="item item-1">
<p class="sub-item"></p >
</div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
上述代码实例中,.container
元素就是网格布局容器,.item
元素就是网格的项目,由于网格元素只能是容器的顶层子元素,所以p
元素并不是网格元素
这里提一下,网格线概念,有助于下面对grid-column
系列属性的理解
网格线,即划分网格的线,如下图所示:
上图是一个 2 x 3 的网格,共有3根水平网格线和4根垂直网格线
#二、属性
同样,Grid
布局属性可以分为两大类:
- 容器属性,
- 项目属性
关于容器属性有如下:
#display 属性
文章开头讲到,在元素上设置display:grid
或 display:inline-grid
来创建一个网格容器
-
display:grid 则该容器是一个块级元素
-
display: inline-grid 则容器元素为行内元素
#grid-template-columns 属性,grid-template-rows 属性
grid-template-columns
属性设置列宽,grid-template-rows
属性设置行高
.wrapper {
display: grid;
/* 声明了三列,宽度分别为 200px 200px 200px */
grid-template-columns: 200px 200px 200px;
grid-gap: 5px;
/* 声明了两行,行高分别为 50px 50px */
grid-template-rows: 50px 50px;
}
以上表示固定列宽为 200px 200px 200px,行高为 50px 50px
上述代码可以看到重复写单元格宽高,通过使用repeat()
函数,可以简写重复的值
- 第一个参数是重复的次数
- 第二个参数是重复的值
所以上述代码可以简写成
.wrapper {
display: grid;
grid-template-columns: repeat(3,200px);
grid-gap: 5px;
grid-template-rows:repeat(2,50px);
}
除了上述的repeact
关键字,还有:
- auto-fill:示自动填充,让一行(或者一列)中尽可能的容纳更多的单元格
grid-template-columns: repeat(auto-fill, 200px)
表示列宽是 200 px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置元素
- fr:片段,为了方便表示比例关系
grid-template-columns: 200px 1fr 2fr
表示第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/3 和 2/3
- minmax:产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。第一个参数就是最小值,第二个参数就是最大值
minmax(100px, 1fr)
表示列宽不小于100px
,不大于1fr
- auto:由浏览器自己决定长度
grid-template-columns: 100px auto 100px
表示第一第三列为 100px,中间由浏览器决定长度
#grid-row-gap 属性, grid-column-gap 属性, grid-gap 属性
grid-row-gap
属性、grid-column-gap
属性分别设置行间距和列间距。grid-gap
属性是两者的简写形式
grid-row-gap: 10px
表示行间距是 10px
grid-column-gap: 20px
表示列间距是 20px
grid-gap: 10px 20px
等同上述两个属性
#grid-template-areas 属性
用于定义区域,一个区域由一个或者多个单元格组成
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-template-areas: 'a b c'
'd e f'
'g h i';
}
上面代码先划分出9个单元格,然后将其定名为a
到i
的九个区域,分别对应这九个单元格。
多个单元格合并成一个区域的写法如下
grid-template-areas: 'a a a'
'b b b'
'c c c';
上面代码将9个单元格分成a
、b
、c
三个区域
如果某些区域不需要利用,则使用"点"(.
)表示
#grid-auto-flow 属性
划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。
顺序就是由grid-auto-flow
决定,默认为行,代表"先行后列",即先填满第一行,再开始放入第二行
当修改成column
后,放置变为如下:
#justify-items 属性, align-items 属性, place-items 属性
justify-items
属性设置单元格内容的水平位置(左中右),align-items
属性设置单元格的垂直位置(上中下)
两者属性的值完成相同
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}
属性对应如下:
- start:对齐单元格的起始边缘
- end:对齐单元格的结束边缘
- center:单元格内部居中
- stretch:拉伸,占满单元格的整个宽度(默认值)
place-items
属性是align-items
属性和justify-items
属性的合并简写形式
#justify-content 属性, align-content 属性, place-content 属性
justify-content
属性是整个内容区域在容器里面的水平位置(左中右),align-content
属性是整个内容区域的垂直位置(上中下)
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
两个属性的写法完全相同,都可以取下面这些值:
- start - 对齐容器的起始边框
- end - 对齐容器的结束边框
- center - 容器内部居中
-
space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍
-
space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔
-
space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔
-
stretch - 项目大小没有指定时,拉伸占据整个网格容器
#grid-auto-columns 属性和 grid-auto-rows 属性
有时候,一些项目的指定位置,在现有网格的外部,就会产生显示网格和隐式网格
比如网格只有3列,但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目。超出的部分就是隐式网格
而grid-auto-rows
与grid-auto-columns
就是专门用于指定隐式网格的宽高
关于项目属性,有如下:
#grid-column-start 属性、grid-column-end 属性、grid-row-start 属性以及grid-row-end 属性
指定网格项目所在的四个边框,分别定位在哪根网格线,从而指定项目的位置
- grid-column-start 属性:左边框所在的垂直网格线
- grid-column-end 属性:右边框所在的垂直网格线
- grid-row-start 属性:上边框所在的水平网格线
- grid-row-end 属性:下边框所在的水平网格线
举个例子:
<style>
#container{
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
.item-1 {
grid-column-start: 2;
grid-column-end: 4;
}
</style>
<div id="container">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
</div>
通过设置grid-column
属性,指定1号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线
#grid-area 属性
grid-area
属性指定项目放在哪一个区域
.item-1 {
grid-area: e;
}
意思为将1号项目位于e
区域
与上述讲到的grid-template-areas
搭配使用
#justify-self 属性、align-self 属性以及 place-self 属性
justify-self
属性设置单元格内容的水平位置(左中右),跟justify-items
属性的用法完全一致,但只作用于单个项目。
align-self
属性设置单元格内容的垂直位置(上中下),跟align-items
属性的用法完全一致,也是只作用于单个项目
.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}
这两个属性都可以取下面四个值。
- start:对齐单元格的起始边缘。
- end:对齐单元格的结束边缘。
- center:单元格内部居中。
- stretch:拉伸,占满单元格的整个宽度(默认值)
#三、应用场景
文章开头就讲到,Grid
是一个强大的布局,如一些常见的 CSS 布局,如居中,两列布局,三列布局等等是很容易实现的,在以前的文章中,也有使用Grid
布局完成对应的功能
关于兼容性问题,结果如下:
总体兼容性还不错,但在 IE 10 以下不支持
目前,Grid
布局在手机端支持还不算太友好
谈谈你对BFC的理解?
#一、是什么
我们在页面布局的时候,经常出现以下情况:
- 这个元素高度怎么没了?
- 这两栏布局怎么没法自适应?
- 这两个元素的间距怎么有点奇怪的样子?
- ......
原因是元素之间相互的影响,导致了意料之外的情况,这里就涉及到BFC
概念
BFC
(Block Formatting Context),即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:
- 内部的盒子会在垂直方向上一个接一个的放置
- 对于同一个BFC的俩个相邻的盒子的margin会发生重叠,与方向无关。
- 每个元素的左外边距与包含块的左边界相接触(从左到右),即使浮动元素也是如此
- BFC的区域不会与float的元素区域重叠
- 计算BFC的高度时,浮动子元素也参与计算
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
BFC
目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素
#二、触发条件
触发BFC
的条件包含不限于:
- 根元素,即HTML元素
- 浮动元素:float值为left、right
- overflow值不为 visible,为 auto、scroll、hidden
- display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
- position的值为absolute或fixed
#三、应用场景
利用BFC
的特性,我们将BFC
应用在以下场景:
#防止margin重叠(塌陷)
<style>
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p >
<p>Hehe</p >
</body>
页面显示如下:
两个p
元素之间的距离为100px
,发生了margin
重叠(塌陷),以最大的为准,如果第一个P的margin
为80的话,两个P之间的距离还是100,以最大的为准。
前面讲到,同一个BFC
的俩个相邻的盒子的margin
会发生重叠
可以在p
外面包裹一层容器,并触发这个容器生成一个BFC
,那么两个p
就不属于同一个BFC
,则不会出现margin
重叠
<style>
.wrap {
overflow: hidden;// 新的BFC
}
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p >
<div class="wrap">
<p>Hehe</p >
</div>
</body>
这时候,边距则不会重叠:
#清除内部浮动
<style>
.par {
border: 5px solid #fcc;
width: 300px;
}
.child {
border: 5px solid #f66;
width:100px;
height: 100px;
float: left;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
页面显示如下:
而BFC
在计算高度时,浮动元素也会参与,所以我们可以触发.par
元素生成BFC
,则内部浮动元素计算高度时候也会计算
.par {
overflow: hidden;
}
实现效果如下:
#自适应多栏布局
这里举个两栏的布局
<style>
body {
width: 300px;
position: relative;
}
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
background: #fcc;
}
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>
效果图如下:
前面讲到,每个元素的左外边距与包含块的左边界相接触
因此,虽然.aslide
为浮动元素,但是main
的左边依然会与包含块的左边相接触
而BFC
的区域不会与浮动盒子重叠
所以我们可以通过触发main
生成BFC
,以此适应两栏布局
.main {
overflow: hidden;
}
这时候,新的BFC
不会与浮动的.aside
元素重叠。因此会根据包含块的宽度,和.aside
的宽度,自动变窄
效果如下:
#小结
可以看到上面几个案例,都体现了BFC
实际就是页面一个独立的容器,里面的子元素不影响外面的元素
BFC通过创建独立的布局环境,解决三大常见问题:
-
外边距合并:隔离元素,避免
margin
重叠。 -
浮动高度塌陷:强制包含浮动子元素,正确计算高度。
-
布局自适应:避免与浮动元素重叠,实现灵活排版。
核心价值:将元素封闭在独立空间内,隔绝内外相互影响,是CSS布局中控制元素位置、间距、层叠的关键机制。
说说对Css预编语言的理解?有哪些区别?
#一、是什么
Css
作为一门标记性语言,语法相对简单,对使用者的要求较低,但同时也带来一些问题
需要书写大量看似没有逻辑的代码,不方便维护及扩展,不利于复用,尤其对于非前端开发工程师来讲,往往会因为缺少 Css
编写经验而很难写出组织良好且易于维护的 Css
代码
Css
预处理器便是针对上述问题的解决方案
#预处理语言
扩充了 Css
语言,增加了诸如变量、混合(mixin)、函数等功能,让 Css
更易维护、方便
本质上,预处理是Css
的超集
包含一套自定义的语法及一个解析器,根据这些语法定义自己的样式规则,这些规则最终会通过解析器,编译生成对应的 Css
文件
#二、有哪些
Css
预编译语言在前端里面有三大优秀的预编处理器,分别是:
- sass
- less
- stylus
#sass
2007 年诞生,最早也是最成熟的 Css
预处理器,拥有 Ruby 社区的支持和 Compass
这一最强大的 Css
框架,目前受 LESS
影响,已经进化到了全面兼容 Css
的 Scss
文件后缀名为.sass
与scss
,可以严格按照 sass 的缩进方式省去大括号和分号
#less
2009年出现,受SASS
的影响较大,但又使用 Css
的语法,让大部分开发者和设计师更容易上手,在 Ruby
社区之外支持者远超过 SASS
其缺点是比起 SASS
来,可编程功能不够,不过优点是简单和兼容 Css
,反过来也影响了 SASS
演变到了Scss
的时代
#stylus
Stylus
是一个Css
的预处理框架,2010 年产生,来自 Node.js
社区,主要用来给 Node
项目进行 Css
预处理支持
所以Stylus
是一种新型语言,可以创建健壮的、动态的、富有表现力的Css
。比较年轻,其本质上做的事情与SASS/LESS
等类似
#三、区别
虽然各种预处理器功能强大,但使用最多的,还是以下特性:
- 变量(variables)
- 作用域(scope)
- 代码混合( mixins)
- 嵌套(nested rules)
- 代码模块化(Modules)
因此,下面就展开这些方面的区别
#基本使用
less和scss
.box {
display: block;
}
sass
.box
display: block
stylus
.box
display: block
#嵌套
三者的嵌套语法都是一致的,甚至连引用父级选择器的标记 & 也相同
区别只是 Sass 和 Stylus 可以用没有大括号的方式书写
less
.a {
&.b {
color: red;
}
}
#变量
变量无疑为 Css 增加了一种有效的复用方式,减少了原来在 Css 中无法避免的重复「硬编码」
less
声明的变量必须以@
开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:
分隔开
@red: #c00;
strong {
color: @red;
}
sass
声明的变量跟less
十分的相似,只是变量名前面使用$开头
$red: #c00;
strong {
color: $red;
}
stylus
声明的变量没有任何的限定,可以使用$
开头,结尾的分号;
可有可无,但变量与变量值之间需要使用=
在stylus
中我们不建议使用@
符号开头声明变量
red = #c00
strong
color: red
#作用域
Css
预编译器把变量赋予作用域,也就是存在生命周期。就像 js
一样,它会先从局部作用域查找变量,依次向上级作用域查找
sass
中不存在全局变量
$color: black;
.scoped {
$bg: blue;
$color: white;
color: $color;
background-color:$bg;
}
.unscoped {
color:$color;
}
编译后
.scoped {
color:white;/*是白色*/
background-color:blue;
}
.unscoped {
color:white;/*白色(无全局变量概念)*/
}
所以,在sass
中最好不要定义相同的变量名
less
与stylus
的作用域跟javascript
十分的相似,首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到根为止
@color: black;
.scoped {
@bg: blue;
@color: white;
color: @color;
background-color:@bg;
}
.unscoped {
color:@color;
}
编译后:
.scoped {
color:white;/*白色(调用了局部变量)*/
background-color:blue;
}
.unscoped {
color:black;/*黑色(调用了全局变量)*/
}
#混入
混入(mixin)应该说是预处理器最精髓的功能之一了,简单点来说,Mixins
可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用
可以在Mixins
中定义变量或者默认参数
在less
中,混合的用法是指将定义好的ClassA
中引入另一个已经定义的Class
,也能使用够传递参数,参数变量为@
声明
.alert {
font-weight: 700;
}
.highlight(@color: red) {
font-size: 1.2em;
color: @color;
}
.heads-up {
.alert;
.highlight(red);
}
编译后
.alert {
font-weight: 700;
}
.heads-up {
font-weight: 700;
font-size: 1.2em;
color: red;
}
Sass
声明mixins
时需要使用@mixinn
,后面紧跟mixin
的名,也可以设置参数,参数名为变量$
声明的形式
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
stylus
中的混合和前两款Css
预处理器语言的混合略有不同,他可以不使用任何符号,就是直接声明Mixins
名,然后在定义参数和默认值之间用等号(=)来连接
error(borderWidth= 2px) {
border: borderWidth solid #F00;
color: #F00;
}
.generic-error {
padding: 20px;
margin: 4px;
error(); /* 调用error mixins */
}
.login-error {
left: 12px;
position: absolute;
top: 20px;
error(5px); /* 调用error mixins,并将参数$borderWidth的值指定为5px */
}
#代码模块化
模块化就是将Css
代码分成一个个模块
scss
、less
、stylus
三者的使用方法都如下所示
@import './common';
@import './github-markdown';
@import './mixin';
@import './variables';
css3动画有哪些?
#一、是什么
CSS动画(CSS Animations)是为层叠样式表建议的允许可扩展标记语言(XML)元素使用CSS的动画的模块
即指元素从一种样式逐渐过渡为另一种样式的过程
常见的动画效果有很多,如平移、旋转、缩放等等,复杂动画则是多个简单动画的组合
css
实现动画的方式,有如下几种:
- transition 实现渐变动画
- transform 转变动画
- animation 实现自定义动画
#二、实现方式
#transition 实现渐变动画
transition
的属性如下:
- property:填写需要变化的css属性
- duration:完成过渡效果需要的时间单位(s或者ms)
- timing-function:完成效果的速度曲线
- delay: 动画效果的延迟触发时间
其中timing-function
的值有如下:
值 | 描述 |
---|---|
linear | 匀速(等于 cubic-bezier(0,0,1,1)) |
ease | 从慢到快再到慢(cubic-bezier(0.25,0.1,0.25,1)) |
ease-in | 慢慢变快(等于 cubic-bezier(0.42,0,1,1)) |
ease-out | 慢慢变慢(等于 cubic-bezier(0,0,0.58,1)) |
ease-in-out | 先变快再到慢(等于 cubic-bezier(0.42,0,0.58,1)),渐显渐隐效果 |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值 |
注意:并不是所有的属性都能使用过渡的,如display:none<->display:block
举个例子,实现鼠标移动上去发生变化动画效果
<style>
.base {
width: 100px;
height: 100px;
display: inline-block;
background-color: #0EA9FF;
border-width: 5px;
border-style: solid;
border-color: #5daf34;
transition-property: width, height, background-color, border-width;
transition-duration: 2s;
transition-timing-function: ease-in;
transition-delay: 500ms;
}
/*简写*/
/*transition: all 2s ease-in 500ms;*/
.base:hover {
width: 200px;
height: 200px;
background-color: #5daf34;
border-width: 10px;
border-color: #3a8ee6;
}
</style>
<div class="base"></div>
#transform 转变动画
包含四个常用的功能:
- translate:位移
- scale:缩放
- rotate:旋转
- skew:倾斜
一般配合transition
过度使用
注意的是,transform
不支持inline
元素,使用前把它变成block
举个例子
<style>
.base {
width: 100px;
height: 100px;
display: inline-block;
background-color: #0EA9FF;
border-width: 5px;
border-style: solid;
border-color: #5daf34;
transition-property: width, height, background-color, border-width;
transition-duration: 2s;
transition-timing-function: ease-in;
transition-delay: 500ms;
}
.base2 {
transform: none;
transition-property: transform;
transition-delay: 5ms;
}
.base2:hover {
transform: scale(0.8, 1.5) rotate(35deg) skew(5deg) translate(15px, 25px);
}
</style>
<div class="base base2"></div>
可以看到盒子发生了旋转,倾斜,平移,放大
#animation 实现自定义动画
animation
是由 8 个属性的简写,分别如下:
属性 | 描述 | 属性值 |
---|---|---|
animation-duration | 指定动画完成一个周期所需要时间,单位秒(s)或毫秒(ms),默认是 0 | |
animation-timing-function | 指定动画计时函数,即动画的速度曲线,默认是 "ease" | linear、ease、ease-in、ease-out、ease-in-out |
animation-delay | 指定动画延迟时间,即动画何时开始,默认是 0 | |
animation-iteration-count | 指定动画播放的次数,默认是 1 | |
animation-direction 指定动画播放的方向 | 默认是 normal | normal、reverse、alternate、alternate-reverse |
animation-fill-mode | 指定动画填充模式。默认是 none | forwards、backwards、both |
animation-play-state | 指定动画播放状态,正在运行或暂停。默认是 running | running、pauser |
animation-name | 指定 @keyframes 动画的名称 |
CSS
动画只需要定义一些关键的帧,而其余的帧,浏览器会根据计时函数插值计算出来,
通过 @keyframes
来定义关键帧
因此,如果我们想要让元素旋转一圈,只需要定义开始和结束两帧即可:
@keyframes rotate{
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
from
表示最开始的那一帧,to
表示结束时的那一帧
也可以使用百分比刻画生命周期
@keyframes rotate{
0%{
transform: rotate(0deg);
}
50%{
transform: rotate(180deg);
}
100%{
transform: rotate(360deg);
}
}
定义好了关键帧后,下来就可以直接用它了:
animation: rotate 2s;
#三、总结
属性 | 含义 |
---|---|
transition(过度) | 用于设置元素的样式过度,和animation有着类似的效果,但细节上有很大的不同 |
transform(变形) | 用于元素进行旋转、缩放、移动或倾斜,和设置样式的动画并没有什么关系,就相当于color一样用来设置元素的“外表” |
translate(移动) | 只是transform的一个属性值,即移动 |
animation(动画) | 用于设置动画属性,他是一个简写的属性,包含6个属性 |