CSS基础-即学即用 -- 笔记1

目录

前言

只需一分钟就能学会,却要用一辈子的时间去精通。

CSS 规则不难,容易上手,它是一种 Web 语言,与其它编程语言不同,它更像是绘画,你可以使用 CSS 绘制页面,而不用担心出任何错误或编译失败的提示。但是要精通 CSS,难在需要知道在何时做何事。

CSS 基础

CSS 其本质上就是声明一些规则,在各种条件下产生特定的效果。最基本内容包括:层叠、相对单位、盒模型等。

1. 层叠

CSS(cascading style sheet)里的 cascade 表示层叠。

如果对于同一元素应用了多个规则时,可能包含了冲突的声明,那么哪一个会生效呢?浏览器为解决这个问题会遵循一些规则来解决冲突,下面的示例中,规则规定了第二个声明(ID 选择器)生效,显示绿色:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    h1 {
      color: red;
    }
    
	#page-title {
      color: green;
    }

	.title {
      color: blue;
    }
  </style>
</head>
<body>
  <header class="page-header">
    <h1 id="page-title" class="title">水果</h1>
    <nav>
      <ul id="main-nav" class="nav">
        <li><a href="/">首页</a></li>
        <li><a href="/apple">苹果</a></li>
        <li><a href="/banana">香蕉</a></li>
        <li><a href="/orange" class="featured">橘子</a></li>
      </ul>
    </nav>
  </header>
</body>
</html>

当声明冲突时,层叠会依据三种条件解决冲突:

  • 样式表的来源:样式从哪来,包括自己写的样式和浏览器默认样式等
  • 选择器的优先级:选择器根据重要性有优先级
  • 源码顺序:样式的声明顺序

样式表来源

你自己写的样式表属于作者样式表,除此之外还有用户代理样式表,即浏览器默认样式。用户代理样式表优先级低,你的样式会覆盖它们。

用户代理样式在不同浏览器上稍有差异,但是大体上是相同的。

着重说明下 !important 声明,这是个例外,标记为重要的声明。此标记会被当作更高优先级的来源,优先级如下:

  • 作者的 !important
  • 作者的
  • 用户代理

理解优先级

如果来源无法解决冲突声明,浏览器会通过检查优先级。浏览器的优先级分为两部分:HTML 的行内样式和选择器的样式。

  1. 行内样式
    行内样式属于"带作用域的"声明,它会覆盖任何来自样式表或者<style>标签的样式。行内样式没有选择器,它们直接作用于所在的元素。

为了在样式表里覆盖行内声明,需要为声明添加 !important,这样能将它提升到一个更高优先级的来源。

  1. 选择器优先级
    优先级的准确规则:
  • 如果选择器的ID数量更多,则它会胜出(即它更明确)
  • 如果ID数量一致,那么拥有最多类的选择器胜出
  • 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。

怎么理解上面的规则,看示例,下面的优先级由低到高排列:

css 复制代码
html body header h1 {
  color: blue;
}

body header.page-header h1 {
  color: orange;
}

.page-header .title {
  color: green;
}

#page-title {
  color: red;
}

伪类选择器(如:hover)和属性选择器(如 [type="input"]​)与一个类选择器的优先级相同。通用选择器(*)和组合器(>、+、~)对优先级没有影响

  1. 优先级标记

一个常用的表示优先级的方式:数值形式,通常用逗号隔开。如,"1,2,2" 表示选择器由1个 ID、2个类、2个标签组成。优先级最高的 ID 列为第一位,然后是类、标签。 例如,"1,0,0" 的优先级高于 "0,2,2" 甚至 "0,10,0"​(不推荐)​,因为第一个数(ID)有最高优先级。

还有一种用4个数的标记,将最重要的位置用0或1来表示,代表是否是用行内样式添加的。此时,行内样式的优先级为"1,0,0,0"​。它会覆盖通过选择器添加的样式,比如优先级为"0,1,2,0"​(1个ID和2个类)的选择器。

  1. 优先级的思考
    优先级容易发展为一种"军备竞赛"。在大型项目中这一点尤为突出。实践中,通常最好让优先级尽可能低,这样当需要覆盖一些样式时,才能有选择空间。

根据上面 html 内容,给出如下示例,我们要让 .featured 选择器生效:

css 复制代码
/* 优先级 1,0,1 */
#main-nav a {
  background-color: blue;
}

/* 方法1:添加 !important。这种方法简单也最快,但也很低级。虽然解决了当前问题,有可能会在以后带来更多问题。当给一些声明加上 !important时,就会先比较来源,再使用常规的优先级规则。最终会让一切回到起点:一旦引入一个 !important,就会带来更多的 !important */
.featured {
  background-color: orange !important;
}

/* 方法2:将优先级提升到 1,1,0 */
#main-nav .featured {
  background-color: orange;
}

/* 方法3:不提升第二个选择器的优先级,降低第一个  */
/*降低优先级为 0,1,1*/
.nav a {
  background-color: blue;
}
/*降低优先级为 0,2,0*/
.nav .featured {
  background-color: orange;
}

源码顺序

层叠的最后一个判断,是源码顺序。如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出。

经验法则

  1. 在选择器中不要使用 ID。就算只用一个 ID,也会大幅提升优先级。当需要覆盖这个选择器时,通常找不到另一个有意义的ID,于是就会复制原来的选择器,然后加上另一个类,让它区别于想要覆盖的选择器。
  2. 不要使用 !important。它比 ID 更难覆盖,一旦用了它,想要覆盖原先的声明,就需要再加上一个 !important,而且依然要处理优先级的问题。

这两条规则是很好的建议,但不必固守它们,因为也有例外。不要为了赢得优先级竞赛而习惯性地使用这两个方法。

建议尽量不要在 JavaScript 里使用行内样式。如果这样做了,就是在强迫使用该包的开发人员要么全盘接受包里的样式,要么给每个想修改的属性加上 !important。

正确的做法是在包里包含一个样式表。如果组件需要频繁修改样式,通常最好用 JavaScript 给元素添加或者移除类。这样用户就可以在使用这份样式表的同时,在不引入优先级竞赛的前提下,按照自己的喜好选择编辑其中的样式。

继承

如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。继承是顺着 DOM 树向下传递的。

并不是所有的属性都能被继承。默认情况下,只有特定的一些属性能被继承。比如更文本相关的属性:color、font、line-height、white-space等,列表属性如:list-style、list-style-position、list-style-image等

inherit 关键字

有时,我们想用继承代替一个层叠值。这时候可以用 inherit 关键字。可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。

继承有个好处,就是如果父元素样式改变,它的样式跟着一起改变。

initial 关键字

撤销作用于某个元素的样式,用 initial 关键字来实现。每一个CSS属性都有初始(默认)值。如果将 initial 值赋给某个属性,那么就会有效地将其重置为默认值,这种操作相当于硬复位了该值。

这么做的好处是简单高效。如果想删除一个元素的边框,设置 border: initial 即可。如果想让一个元素恢复到默认宽度,设置 width: initial 即可。

2. 相对单位

CSS 的像素单位(px)是绝对单位,即 10px 放在哪都一样大。其他单位,如 em 和 rem 是相对单位。相对单位的值会根据外部因素发生变化。如 2em 的具体值会根据它作用到的元素而变化。

相对单位有其独特的价值,只要我们掌握了控制其变化的方式,使用恰当,会让代码更简洁灵活,也更简单。

em 和 rem

em 是最常见的相对长度单位,适合基于特定的字号进行排版。1em等于当前元素的字号,其准确值取决于作用的元素。

css 复制代码
.padded {
  font-size: 16px;
  padding: 1em
}

规则集指定了字号为16px,设置内边距的值为1em。浏览器将其乘以字号,最终渲染为16px。重要:浏览器会根据相对单位的值计算出绝对值,称作计算值(computed value)​

当设置padding、height、width、border-radius等属性时,使用em会很方便。这是因为当元素继承了不同的字号,或者用户改变了字体设置时,这些属性会跟着元素均匀地缩放。

谈到 font-size 属性时,em 表现得不太一样。之前提到过,当前元素的字号决定了 em。如果声明 font-size:1.2em,这个 font-size 是根据继承的字号来计算的。

em用在内边距、外边距以及元素大小上很好,但是用在字号上就会很复杂。但是,我们有更好的选择:rem。

在文档中,根节点是所有其他元素的祖先节点。根节点有一个伪类选择器(:root)​,可以用来选中它自己。这等价于类型选择器 html,但是html 的优先级相当于一个类名,而不是一个标签。

rem 是 root em 的缩写。rem 不是相对于当前元素,而是相对于根元素的单位。不管在文档的什么位置使用rem,1.2rem都会有相同的计算值:1.2乘以根元素的字号。

css 复制代码
:root {
  font-size: 1em;
}

ul {
  font-size: .8rem;
}

示例中,如果根元素的字号为浏览器默认的字号16px(根元素上的em是相对于浏览器默认值的)​。无序列表的字号设置为0.8rem,计算值为12.8px。因为相对根元素,所以所有字号始终一致,就算是嵌套列表也一样。

与 em 相比,rem 降低了复杂性。实际上,rem 结合了 px 和 em 的优点,既保留了相对单位的优势,又简单易用。

但是,使用还得根据场景来定。拿不准的时候,用rem设置字号,用px设置边框,用em设置其他大部分属性。

响应式面板

我们可以根据屏幕尺寸,用媒体查询改变根元素的字号。这样就能够基于不同用户的屏幕尺寸,渲染出不同大小的面板。

媒体查询,即 @media 规则,可以指定某种屏幕尺寸或者媒体类型(比如,打印机或者屏幕)下的样式。这是响应式设计的关键部分。

css 复制代码
:root {
  font-size: 0.75em;
}

@media (min-width: 800px) {
  :root {
    font-size: 0.875em;
  }
}

@media (min-width: 1200px) {
  :root {
    font-size: 1em;
  }
}

通过给页面根元素设置不同字号,我们响应式地重新定义了整个网页的 em和 rem。也就是说,即使不直接修改面板的样式,它也是响应式的。缩放浏览器窗口可以看到这些变化。

视口的相对单位

视口:浏览器窗口里网页可见部分的边框区域。它不包括浏览器的地址栏、工具栏、状态栏。

  • vh:视口高度的1/100
  • vw:视口宽度的1/100
  • vmin:视口宽、高中较小的一方的1/100(IE9中叫vm,而不是vmin)
  • vmax:视口宽、高中较大的一方的1/100(本书写作时IE和Edge均不支持vmax)[插图]。

如,50vw 等于视口宽度的一半,25vh等于视口高度的25%。vmin 取决于宽和高中较小的一方,这可以保证元素在屏幕方向变化时适应屏幕。在横屏时,vmin 取决于高度;在竖屏时,则取决于宽度。

视口相对长度非常适合展示一个填满屏幕的大图。我们可以将图片放在一个很长的容器里,然后设置图片的高度为100vh,让它等于视口的高度。

使用vw定义字号

相对视口单位有一个不起眼的用途,就是设置字号,它或许比用 vh 和 vw 设置元素的宽和高还要实用。

比如,我们设置 font-size: 2vw。 即,在一个1200px的桌面显示器上,计算值为24px(1200的2%)​。在一个768px宽的平板上,计算值约为15px(768的2%)​。这样做的好处在于元素能够在这两种大小之间平滑地过渡,这意味着不会在某个断点突然改变。当视口大小改变时,元素会逐渐过渡。

但有一个问题,24px 在大屏上来说有可能太大了。更糟糕的是,在手机上可能会缩小到只有7.5px。如果能够保留这种缩放的能力,但是让极端情况缓和一些就更棒了。CSS 的 calc() 函数可以提供帮助。

使用calc()定义字号

calc() 函数内可以对两个及其以上的值进行基本运算。当要结合不同单位的值时,calc() 特别实用。支持的运算包括:加(+)​、减(−)​、乘(×)​、除(÷)​。加号和减号两边必须有空白。

示例:calc() 结合 em 和 vw 两种单位。删除之前样式表的基础字号(以及相关的媒体查询)​,换成如下代码:

css 复制代码
:root {
  font-size: calc(0.5em + 1vw);
}

打开网页,慢慢缩放浏览器,字体会平滑地缩放。0.5em 保证了最小字号,1vw 则确保了字体会随着视口缩放。这段代码保证基础字号从手机里的11.75px一直过渡到1200px的浏览器窗口里的20px。可以按照自己的喜好调整这个值。

自定义属性(即CSS变量)

要定义一个自定义属性,只需要像其他CSS属性那样声明即可。看个例子:

css 复制代码
:root {
  --main-font: Helvetica, Arial, sans-serif;
}

p {
  font-family: var(--main-font);
}

这个代码清单定义了一个名叫 --main-font 的变量。将其值设置为一些常见的 sans-serif 字体。变量名前面必须有两个连字符(--)​,用来跟CSS 属性区分,剩下的部分可以随意命名。变量必须在一个声明块内声明。这里使用了:root选择器,因此该变量可以在整个网页使用。

变量声明本身什么也没做,我们使用时才能看到效果。自定义属性就像作用域变量一样,因为它的值会被后代元素继承。

首先还是在 :root 选择器的规则集中定义变量。这很重要,如此一来这些值就可以提供给根元素(整个网页)下的任何元素。当根元素的后代元素使用这个变量时,就会解析这里的值。

3. 盒模型

页面中的每一个标签,都可以看做是一个 "盒子",通过盒子的视角,我们可以更方便的进行布局。

盒子模型:CSS 中规定每个盒子分别由:内容(content)、内边距(padding)、边框(border)、外边距(margin)构成。

计算公式:

  • 盒子宽度 = 左边框 + 左 padding + 内容宽度 + 右 padding + 右边框
  • 盒子高度 = 上边框 + 上 padding + 内容宽度 + 下 padding + 下边框

调整盒模型

CSS 中我们可以使用 box-sizing 属性来调整盒模型的行为。

box-sizing 的默认值为 content-box ,这意味任何指定的宽或高都只会设置内容盒子 的大小。

将 box-sizing 设置为 border-box 后,height 和width 属性会设置内容、内边距以及边框的大小总和

示例,设置全局的 border-box:

css 复制代码
*,
::before,
::after {
  box-sizing: border-box;
}

用通用选择器(*)选中了页面上所有元素,并用两个选择器选中了网页的所有伪元素。将这段代码放到样式表开头已是普遍做法了。

但是,如果网页中使用了带样式的第三方组件而且没有考虑到使用者会修改盒模型时,就可能会因此破坏其中一些组件的布局。因为全局设置 border-box 时使用的通用选择器会选中第三方组件内的每个元素,修改盒模型可能会有问题,所以最终需要写另外的样式将组件内的元素恢复为 content-box。

下面示例,让全局修改盒模型为border-box更稳健:

css 复制代码
:root {
  box-sizing: border-box;
}

*,
::before,
::after {
  box-sizing: inherit;
}

盒模型通常不会被继承,但是使用 inherit 关键字可以强制继承。

开发过程中,建议将上面代码加到 CSS 中,因为从长远来看,这会省去很多麻烦。

但是,如果给已有的样式表加上上面代码后可能有问题,尤其是当你已基于默认的内容盒模型写了很多样式后。如果非要给已有项目加上这段代码,那么一定要彻底检查一遍看会不会有问题。

相关推荐
天天扭码5 分钟前
一分钟解决 | 高频面试算法题——滑动窗口最大值(单调队列)
前端·算法·面试
星释8 分钟前
ASP.NET常见安全漏洞及修复方式
前端·ui·asp.net
Bunury26 分钟前
element-plus添加暗黑模式
开发语言·前端·javascript
心走31 分钟前
八股文中TCP三次握手怎么具象理解?
前端·面试
Aiolimp40 分钟前
React常见Hooks使用(二)
前端·react.js
By北阳40 分钟前
CSS 中实现 div 居中有以下几种常用方法
前端·css
在广东捡破烂的吴彦祖42 分钟前
window配置Flutter开发环境
前端·flutter
辣椒粉丝1 小时前
记rspack想提issuse,提太慢白嫖不上了
前端·javascript
腰间盘突出的红利1 小时前
npm组件库搭建
前端
火星思想1 小时前
前端基础布局写法详解:左右、左中右及弹性布局实践
前端·css