分享几个 CSS 技巧 - 第一波
February 10, 2021
前言
在实际工作中,为了百分百还原设计师们精致而又严格(变态)的设计稿,我们经常需要借助一些
CSS-Tricks 来保障页面的高还原度,不然设计妹子的像素眼分分钟找出遗漏点,向你发难。
晚痛不如早痛,而我切页面的原则有三:
- 能单凭 CSS 解决,绝不让 JS 混入其中
- 能利用优先级覆盖,绝不使用
!important
- 大胆使用 CSS 新特性、CSS-Tricks(只需兼容 Chrome 大法好)
因此,这边文章分享了关于 CSS 的几个小技巧,可能正解救了处于水生火热的你。
FBI WARNING:本文所有例子均采用 jsfiddle 呈现,需要科学上网。
子元素无视父元素的 overflow: hidden
限制
场景如下,父元素设置了 overflow: hidden
,但要求子元素能一部分显示在外,这显然与父元素的 hidden 所矛盾。
换个角度,可以使子元素脱离文档流并不依据父元素定位,即添加 position: absolute
,你可以看下面的示例:
但要注意,此时父元素不可设置为 position: relative | absolute | fixed | sticky
,要以父元素外层的元素,作为 position: absolute
的基准定位元素。
因为 position: absolute
的定位原则是以 第一个不为 static 定位(默认定位,即初始值) 的元素来进行定位,如果全是 static,则依据根元素 <html>
进行定位。
利用 flex 实现伸缩布局
不多解释,直接上 demo:
这类布局在各 Website、App 会经常看到,大致有两个特点:
- 容器总高度固定,
<header>
&<footer>
高度随内容而定 <main>
为一个 可滚动区域,其内容会占据所有剩余空间
乍一看好像没什么,但内有玄机,在我以往的认知中,要为一个元素呈现 overflow-y: scroll
的效果,必须显式设置该元素的高度(height)。
而且还要求该元素的高度能动态调整,占满剩余高度,难不成要使用万能的 JS 进行计算?No,这违背了我的原则。
借助于 flex 弹性布局,我们可以很完美得解决这个问题,<main>
的 flex: 1
其实等同于:
- flex-grow: 1
- flex-shrink: 1
- flex-basis: 0%
关键在于前面两个属性定义了该 flex 子元素总是会向外增长,即父 flex 容器有剩余空间时,总是会占满。相当于隐式设置了高度,从而能进行滚动。
滚动条不占据内容宽度
继续围绕 overflow-y: scroll
出现滚动条的话题,以 Mac 下的 Chrome 为例,滚动条默认不会占据内容宽度,也不会显示,只有当鼠标在可滚动区域内滚动时,滚动条才会显示。
但当我们主动设置滚动条的样式时,滚动条会默认占据内容的宽度,你可以看下面的 demo 示例:
借助于 overflow-y: overlay
属性,它可以使滚动条不占据内容宽度,就好比设置了 position: fixed
定位一般,固定于右侧。
我设置了盒子的 padding-right: 8px
,而滚动条宽度也为 8px,可以看到 "Placeholder" 紧贴着滚动条,说明 overflow-y: overlay
起作用了。
还原样式属性
cursor: pointer
这个属性并不陌生,当光标经过设置该属性的元素时,会变成可点击形态。那么问题来了,如果在该元素的内部,一些子元素不需要可点击的光标形态,该如何设置子元素的 cursor 属性来覆盖父元素的 pointer 行为?
或许你可以去 MDN 上查询 cursor 的所有可选值,并找到默认值。我猜是 default,恰巧 default 确实存在,但其表现还是与默认形态有一定的差异(一直是箭头形态,经过文字时不会变化,比如括号中的文字就是设置了 default 值),经过官方文档的查阅,auto 才是光标的 “正统” 默认值。
上述的方法未免太过繁琐,有没有又快又好的技巧,the answer is YES!
官方文档中明确指出 cursor 的规范定义如下:
Initial value | auto | |||
Applies to | all elements | |||
Inherited | yes |
轻松得知两个关键信息:
- 它是一个可继承属性,因此子元素不显式设置
cursor: pointer
也会显示可点击形态,正是继承了父元素的属性 - 它的初始值是
cursor: auto
同时对于所有 CSS 属性,都存在三个可选值:
- initial,该属性使用默认值
- inherit,该属性继承父元素的值
- unset,如果该属性是可继承属性,该值等同于 inherit;如果该属性是非继承属性,该值等同于 initial
问题迎刃而解,我无需知道 cursor 的默认值是哪个关键词(auto),只需知道 initial.
width: fit-content | min-content | max-content
以前觉得 width 只是个平平无奇的属性,用来设置的元素的宽度,如果强行增加难度,无非就是:
- 配合
box-sizing: border-box
设置整个盒子模型的宽度,而非 content-width - max-width 和 min-width 属性会覆盖 width 属性
但其实它还有三个关键词可供选择,能快速实现一些布局效果。
fit-content 配合 margin: auto
实现收缩且居中
当我提到水平居中一个元素时,你会想到什么方法?对于不同 display 的元素自然有着不同的方法:
display: block
,只需添加margin: auto
display: inline-block
,需要父元素额外设置text-align: center
其实,display 可以拆分为两个属性:display-outside
和 display-inside
,它们分别设置一个元素的 “外部排列” 和 “内部排列” 特性。
以 display: inline-block
为例,它的外部表现是一个行内元素(inline):宽度根据内容拓展,不占据一行,但内部表现是一个块级元素(block):可设置宽高以及竖直方向上的 margin、padding
css
{display: inline-block;/* display-outside: inline; *//* display-inside: block; */}
css
{display: inline-block;/* display-outside: inline; *//* display-inside: block; */}
假设,我们既要实现元素 收缩效果 的同时,又要保持原本的元素 外部 block 状态,该如何是好?使用 width: fit-content
可以轻松解决,该属性维持了原先的 block 状态并向内自适应(根据内容显示宽度,不再默认占满一行,和 inline-block 很相似,但本质上有着差距),可以直接配合 margin: auto
实现居中的效果。
min-content 实现最小宽度
当想实现一个元素根据其子元素的最小宽度来自动设置宽度时,这个属性就派上了用场,那么 “最小宽度” 到底指什么?在子元素没有显式声明宽度的前提下,默认规则如下:
- 对于可替换元素(img、input、textarea...),最小宽度就是可替换元素的宽度,例如图片的宽度
- 对于中文文本元素,最小宽度值就是一个中文字符的宽度
- 对于英文文本元素,最小宽度就是其中最长英文单词的宽度
可替换元素,顾名思义,它们拥有默认的宽高,并且可以被设置具体的宽高值
为了方便解释,这边举了三个例子:
max-content 实现不折行
有 min-content,就有 max-content,当一个元素的 width 属性被赋予该值时,他的宽度值会仅可能得大。即假设我们的容器有足够的宽度,足够的空间,此时,所占据最大宽度的子元素的宽度就是 max-content 的值。
在普通的容器中,子元素过长,会自动换行,排列到下一行空间,但 max-content
的存在,就好比设置了 white-space: nowrap
,具体表现如 demo 所示: