首发于 JowayYoung谈前端
8个硬核技巧带你迅速提升CSS技术 | 掘金直播总结

8个硬核技巧带你迅速提升CSS技术 | 掘金直播总结

作者: JowayYoung
仓库: Github、 CodePen
博客: 官网、 掘金、 思否、 知乎
公众号: IQ前端
特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系笔者授权

前言

前段时间笔者收到可爱漂亮的小册姐姐的邀请,做了人生首次直播分享。分享主题是《玩转CSS的艺术之美》,跟笔者在9月底发布的 掘金小册同名。

9月底发布的 玩转CSS的艺术之美,首日预售就达到709本,预售仅三日就破1000本。这也让笔者感到惊讶,没想到CSS技术还是那么受倔友们的欢迎,让笔者觉得熬夜半年写这本小册还是值得的,毕竟能将自己的学习心路分享出去,让更多同学学到更多东西,也是一件值得开心的事情。

由于首次做直播分享,感觉比较紧张,家里网络不是特别好,还有其他原因,导致认真准备的内容未在预料时间内完成分享,因此通过本文将来不及分享的内容整理出来。



目录

对分享内容感兴趣的同学可关注笔者的公众号 IQ前端,回复CSSPPT下载分享PPT。分享内容包含历史背景概念原理开发技巧三节。第一二节比较无聊,可自行查看PPT,在此就不多说了。主要是第三节的干货,是笔者认真准备了好几天的内容,每个主题都会有对应的源码及其效果。



笔者选择了一些常用甚至有些小册都未提及到的干货作为分享内容,相信这些内容能帮助同学们在短期内提升CSS编码素质,实现一些看似只能由JS才能实现的效果。

准备工作

整个分享过程不搞那些乱七八糟的环境搭建。既然只玩CSS,那只有html文件css文件就足够了。另外还需一个浏览器Chrome和一个编辑器VSCode

VSCode还需安装Live Sass CompilerLive Server两个插件。Live Sass Compiler用于实时编译sass/scss文件css文件Live Server用于启动具有实时刷新功能的本地开发服务器,以处理静态页面和动态页面。

新建index.htmlindex.scss。为了使各大浏览器默认样式一致,还需引入一个磨平浏览器默认样式的css文件,同学们可下载笔者写好的 reset.css到本地目录里。

上述文件骨架完成后,打开index.scss,按F1Cmd + Shift + P打开命令面板,输入Watch Sass监听index.scss并生成index.css,再输入Open With Live Server启动本地开发服务器并打开浏览器。到此为止就完成了所有准备工作了。

神奇的选择器

很多CSS编码习惯都是清一色的类而无相应的选择器,层层嵌套的标签都包含至少一个类。选择器对比起来性能上确实没后者那么好,但如今浏览器对于CSS的解析速度已得到大大的提升,完全可忽略选择器那丁点的性能问题。

可是CSS模块众多,依次推出的选择器也很多。若无特别方法记熟这些选择器对应的功能,也很难将选择器发挥到最大作用。玩转CSS的最关键一步是能熟悉大部分选择器及其功能与使用场景

笔者根据选择器的功能划分出八大类,每个类别的选择器都能在一个使用场景中互相组合,记熟这些类别的选择器,相信就能将选择器发挥到最大作用。以下选择器的常用选项里若打勾可强行记熟,这些选择器都是笔者久经沙场而标记出来且认为是最好用的选择器。

基础选择器

选择器|别名|说明|版本|常用 :-:|:-:|-|:-:|:-: tag|标签选择器|指定类型的标签|1|√ #id|ID选择器|指定身份的标签|1|√ .class|类选择器|指定类名的标签|1|√ *|通配选择器|所有类型的标签|2|√

层次选择器

选择器|别名|说明|版本|常用 :-:|:-:|-|:-:|:-: elemP elemC|后代选择器|元素的后代元素|1|√ elemP>elemC|子代选择器|元素的子代元素|2|√ elem1+elem2|相邻同胞选择器|元素相邻的同胞元素|2|√ elem1~elem2|通用同胞选择器|元素后面的同胞元素|3|√

集合选择器

选择器|别名|说明|版本|常用 :-:|:-:|-|:-:|:-: elem1,elem2|并集选择器|多个指定的元素|1|√ elem.class|交集选择器|指定类名的元素|1|√

条件选择器

选择器|说明|版本|常用 :-:|-|:-:|:-: :lang|指定标记语言的元素|2|× :dir()|指定编写方向的元素|4|× :has|包含指定元素的元素|4|× :is|指定条件的元素|4|× :not|非指定条件的元素|4|√ :where|指定条件的元素|4|× :scope|指定元素作为参考点|4|× :any-link|所有包含href链接元素|4|× :local-link|所有包含href且属于绝对地址的链接元素|4|×

状态选择器

选择器|说明|版本|常用 :-:|-|:-:|:-: :active|鼠标激活的元素|1|× :hover|鼠标悬浮的元素|1|√ :link|未访问的链接元素|1|× :visited|已访问的链接元素|1|× :target|当前锚点的元素|3|× :focus|输入聚焦的表单元素|2|√ :required|输入必填的表单元素|3|√ :valid|输入合法的表单元素|3|√ :invalid|输入非法的表单元素|3|√ :in-range|输入范围以内的表单元素|3|× :out-of-range|输入范围以外的表单元素|3|× :checked|选项选中的表单元素|3|√ :optional|选项可选的表单元素|3|× :enabled|事件启用的表单元素|3|× :disabled|事件禁用的表单元素|3|√ :read-only|只读的表单元素|3|× :read-write|可读可写的表单元素|3|× :target-within|内部锚点元素处于激活状态的元素|4|× :focus-within|内部表单元素处于聚焦状态的元素|4|√ :focus-visible|输入聚焦的表单元素|4|× :blank|输入为空的表单元素|4|× :user-invalid|输入合法的表单元素|4|× :indeterminate|选项未定的表单元素|4|× :placeholder-shown|占位显示的表单元素|4|√ :current()|浏览中的元素|4|× :past()|已浏览的元素|4|× :future()|未浏览的元素|4|× :playing|开始播放的媒体元素|4|× :paused|暂停播放的媒体元素|4|×

结构选择器

选择器|说明|版本|常用 :-:|-|:-:|:-: :root|文档的根元素|3|× :empty|无子元素的元素|3|√ :nth-child(n)|元素中指定顺序索引的元素|3|√ :nth-last-child(n)|元素中指定逆序索引的元素|3|× :first-child|元素中为首的元素|2|√ :last-child|元素中为尾的元素|3|√ :only-child|父元素仅有该元素的元素|3|√ :nth-of-type(n)|标签中指定顺序索引的标签|3|√ :nth-last-of-type(n)|标签中指定逆序索引的标签|3|× :first-of-type|标签中为首的标签|3|√ :last-of-type|标签中为尾标签|3|√ :only-of-type|父元素仅有该标签的标签|3|√

属性选择器

选择器|说明|版本|常用 :-:|-|:-:|:-: [attr]|指定属性的元素|2|√ [attr=val]|属性等于指定值的元素|2|√ [attr*=val]|属性包含指定值的元素|3|√ [attr^=val]|属性以指定值开头的元素|3|√ [attr$=val]|属性以指定值结尾的元素|3|√ [attr~=val]|属性包含指定值(完整单词)的元素(不推荐使用)|2|× [attr\|=val]|属性以指定值(完整单词)开头的元素(不推荐使用)|2|×

伪元素

选择器|说明|版本|常用 :-:|-|:-:|:-: ::before|在元素前插入的内容|2|√ ::after|在元素后插入的内容|2|√ ::first-letter|元素的首字母|1|× ::first-line|元素的首行|1|× ::selection|鼠标选中的元素|3|× ::backdrop|全屏模式的元素|4|× ::placeholder|表单元素的占位|4|√

选择器真正的用处不仅仅是说明选项里的描述,更多是搭配起来能起到的最大作用。这些选择器组成的选择器系统是整个CSS体系里的核心,使用选择器能带来以下好处。

浅谈布局那些事

掌握一些常用布局是一个前端必不可少的技能。养成看设计图就能大概规划出整体布局的前提是必须熟悉这些常用布局的特点与构造。曾经需结合很多属性才能完成一个布局,如今在现代属性的加持下能更好地快速实现各种布局,节约更多时间去做更重要的事情。

全屏布局

经典的全屏布局顶部底部主体三部分组成,其特点为三部分左右满屏拉伸顶部底部高度固定主体高度自适应。该布局很常见,也是大部分Web应用主体的主流布局。通常使用<header><footer><main>三个标签语义化排版,<main>内还可插入<aside>侧栏或其他语义化标签。



position + left/right/top/bottom

三部分统一声明left:0right:0将其左右满屏拉伸;顶部和底部分别声明top:0bottom:0将其吸顶和吸底,并声明俩高度为固定值;将主体的topbottom分别声明为顶部高度和底部高度。通过绝对定位的方式将三部分固定在特定位置,使其互不影响。

flex

使用flex实现会更简洁。display:flex默认会令子节点横向排列,需声明flex-direction:column改变子节点排列方向为纵向排列;顶部和底部高度固定,所以主体需声明flex:1让高度自适应。

<main>需表现成可滚动状态,千万不要声明overflow:auto让容器自适应滚动,这样做有可能因为其他格式化上下文的影响而导致自适应滚动失效或产生其他未知效果。需在<main>内插入一个<div>并声明如下。

多列布局

两列布局

经典的两列布局左右两列组成,其特点为一列宽度固定另一列宽度自适应两列高度固定且相等。以下以左列宽度固定和右列宽度自适应为例,反之同理。



float + margin-left/right

左列声明float:left和固定宽度,由于float使节点脱流,右列需声明margin-left为左列宽度,以保证两列不会重叠。

overflow + float

左列声明同上,右列声明overflow:hidden使其形成BFC区域与外界隔离。BFC相关详情请查看小册第4章 盒模型。

flex

使用flex实现会更简洁。左列声明固定宽度,右列声明flex:1自适应宽度。

三列布局

经典的三列布局左中右三列组成,其特点为连续两列宽度固定剩余一列宽度自适应三列高度固定且相等。以下以左中列宽度固定和右列宽度自适应为例,反之同理。整体的实现原理与上述两列布局一致。



为了让右列宽度自适应计算,就不使用float + margin-left的方式了,若使用margin-left还得结合左中列宽度计算。

overflow + float
flex

圣杯布局与双飞翼布局

经典的圣杯布局双飞翼布局都是由左中右三列组成,其特点为左右两列宽度固定中间一列宽度自适应三列高度固定且相等。其实也是上述两列布局和三列布局的变体,整体的实现原理与上述N列布局一致,可能就是一些细节需注意。

圣杯布局双飞翼布局在大体相同下也存在一点不同,区别在于双飞翼布局中间列需插入一个子节点。在常规的实现方式中也是在这个中间列里做文章,如何使中间列内容不被左右列遮挡



圣杯布局float + margin-left/right + padding-left/right

由于浮动节点在位置上不能高于前面或平级的非浮动节点,否则会导致浮动节点下沉。因此在编写HTML结构时,将中间列节点挪到右列节点后面。

双飞翼布局float + margin-left/right

HTML结构大体同上,只是在中间列里插入一个子节点<div>。根据两者区别,CSS声明会与上述圣杯布局有一点点出入,可观察对比找出不同地方。

圣杯布局/双飞翼布局flex

使用flex实现圣杯布局/双飞翼布局可忽略上述分析,左右两列宽度固定,中间列宽度自适应。

均分布局

经典的均分布局多列组成,其特点为每列宽度相等每列高度固定且相等。总体来说也是最简单的经典布局,由于每列宽度相等,所以很易找到合适的方式处理。



float + width

每列宽度声明为相等的百分比,若有4列则声明width:25%。N列就用公式100 / n求出最终百分比宽度,记得保留2位小数,懒人还可用width:calc(100% / n)自动计算呢。

flex

使用flex实现会更简洁。节点声明display:flex后,生成的FFC容器里所有子节点的高度都相等,因为容器的align-items默认为stretch,所有子节点将占满整个容器的高度。每列声明flex:1自适应宽度。

居中布局

居中布局父容器若干个子容器组成,子容器在父容器中横向排列或竖向排列且呈水平居中或垂直居中。居中布局是一个很经典的问题,所以笔者在小册中罗列了所有居中布局方式,详情请查看小册第6章 布局方式。



在此直接上一个目前最简单最高效的居中方式。display:flexmargin:auto的强行组合,同学们自行体会。

绘制三角的原理

盒模型从理论上来说是一个标准的矩形,很难将其联想到基于盒模型绘制一个三角形。当然存在一个叫clip-path的属性,可绘制三角形,鉴于其兼容性较差通常不会大范围使用它绘制三角形。

很多同学都会基于盒模型编写三角形,但大部分都是复制粘贴的操作。从原理上正确理解其成因,才能无需复制粘贴就能得心应手地绘制各种三角形。以下从零到一熟悉一次绘制三角形的原理。

绘制一个边框分别为四种颜色的正方形。



分别将widthheight累减到0,发现正方形由四个不同颜色的等腰三角形组成。



尝试将右边框颜色声明为透明,会发现右边框隐藏起来。



同样原理,将上边框颜色和下边框颜色同时声明为透明,就会得到一个指向右边的三角形。



可简写成以下代码。细心的同学可能还会发现三角形的宽是高的2倍,而高正好是边框宽度border-width。从中可得出一个技巧:若绘制三角形的方向为左右上下,则将四条边框颜色声明为透明且将指定方向的反方向的边框着色,即可得到所需方向的三角形

若绘制左上角、左下角、右上角或右下角的三角形,使用上述技巧就无法完成了。可稍微变通思维,其实指向左上角的三角形是由左边框和上边框组成,其他三角形也是如此。



基于上述原理,可得心应手绘制出左右上下、左上角、左下角、右上角和右下角的三角形了,再结合绝对定位(position/left/right/top/bottom)、边距(margin/margin-*)或变换(transform)调整位置即可。



完美极致的变量

变量又名自定义属性,指可在整个文档中重复使用的值。它由自定义属性--var和函数var()组成,var()用于引用自定义属性。使用变量能带来以下好处。

同时变量也是浏览器原生特性,无需经过任何转译可直接运行,也是DOM对象,极大便利了CSS与JS间的联系。变量除了具备简洁性和复用性,在重构组件样式时能让代码更易控制,同时还隐藏了一个强大的技巧,那就是与calc()结合使用。

看看一个简单的例子。一个条形加载条通常由几条线条组成,每条线条对应一个存在不同时延的相同动画,通过时间差运行相同动画,从而产生加载效果。估计大部分同学可能会把代码编写成以下形式。



分析代码发现,每个<li>只是animation-delay不同,其余代码则完全相同,换成其他类似的List集合,那岂不是有10个<li>就写10个:nth-child(n)。显然这种方式不灵活也不易封装成组件,若能像JS那样封装成一个函数,并根据参数输出不同样式效果,那就更棒了。

对于HTML部分的修改,让每个<li>拥有一个自己作用域下的变量。对于CSS部分的修改,就需分析哪些属性是随着index递增而发生规律变化的,对规律变化的部分使用变量表达式代替即可。当然以下<li style="--line-index: n;"></li>可用React JSXVue Template的遍历语法编写。

代码中的变量--line-index--time使每个<li>拥有一个属于自己的作用域。例如第二个<li>--line-index的值为2,--time的计算值为200ms,换成第三个<li>后这两个值又会不同了。这就是变量的作用范围所致(在当前节点块作用域及其子节点块作用域下有效)。

calc(var(--line-index) * 200ms)就像一个JS函数,在当前节点的作用域上读取相应的变量,从而计算出具体数值并交由浏览器初始化。从中可得出一个技巧:List集合里具备与索引递增相关的属性值都可用变量与calc()结合使用生成出来

还记得小学时代学习圆周率的场景吗,曾经有学者将一个圆形划分为很多很小的矩形,若这些矩形划分得足够细,那么也可拼在一起变成一个圆形。

将圆形划分为360个小矩形且每个矩形相对于父容器绝对定位,声明transform-origincenter bottom将小矩形的变换基准变更为最底部最中间,每个小矩形按照递增角度顺时针旋转N度,就会形成一个圆形。此时按照递增角度调整小矩形的背景色相,就会看到意想不到的渐变效果了。

若将小矩形的尺寸和数量设置更细更多,整体的渐变效果就会更均匀。



添油加醋的伪元素

有时为了实现某个效果而往页面里反复添加标签变得很繁琐,添加太多标签反而不好处理而变得难以维护。此时会引入伪元素这个概念解决上述问题。正是伪元素能解决一些可不添加其他标签而起到占位作用,笔者才称伪元素“添油加醋”

上述选择器分类有提及伪元素,狭义上来说选择器除了伪元素,其他都是伪类伪元素伪类虽然都是选择器,但它们还是存在一丝丝的差别。

伪元素指页面里不存在的元素。伪元素在HTML代码里未声明却能正常显示,在页面渲染时看到这些本来不存在的元素发挥着重要作用。:before:after是两个很重要的伪元素,早在CSS2就出现了。

起初伪元素的前缀使用单冒号语法。随着CSS改革,伪元素的前缀被修改成双冒号语法:before/:after从此变成::before/::after,用来区分伪类,未提及的伪元素同理。若兼容低版本浏览器,还需使用:before:after

两者最主要的区别就是伪类使用单冒号语法伪元素使用双冒号语法。当然笔者还是提倡同学们使用单冒号语法标记伪类,使用双冒号语法标记伪元素,这样在代码形式上就能一眼区分出来。

::before::after的使用场景很多,也是笔者着重研究的技巧之一。::before/::after必须结合content使用,通常用作修饰节点,为节点插入一些多余的东西,但又不想内嵌一些其他标签。若插入2个以下(包含2个)的修饰,建议使用::before/::after

说时迟那时快,立马结合上述绘制三角形的原理绘制一个常用的气泡对话框,圆滚滚的身子带上一个三角形的尾巴。气泡对话框的身板就是一个圆角矩形,可用<div>直接绘制,小尾巴是一个三角形,可用::after占位并绘制。这样就无需在<div>里添加一个<i>绘制小尾巴了。



从中可得出一个技巧:若为节点做一些修饰却不想插入其他标签,可用::before和::after代替,但适用于2个占位以下。其实这个也不算什么特别技巧,只是很多同学都不会去注意这种用法,有需求都是直接添加标签。也许以下提及的障眼法内容插入会让同学们对伪元素另眼相看。

灵活多变的障眼法

上述使用::after简单地绘制气泡对话框的尾巴,然而复杂一点的带边框气泡对话框能否也使用伪元素绘制呢。看到这里先不要往下看代码,自行思考1分钟想想实现方法。



答案当然是可行的。以下是整个带边框气泡对话框的拆解,整体由三部分组成:带边框圆角矩形、黑色三角形、橙色三角形。先将两个三角形错位叠加生成一个箭头状的图形,再将该图形叠加到带边框圆角矩形的右边,最后将黑色三角形着色成白色,就能得到上图的带边框气泡对话框了。



整体实现思路就是一种障眼法,正确来说就是将图形错位叠加产生另一种效果,在平面设计中叫做占位叠加。有了这种设计思想,其实能使用CSS创造出很多意向不到的障眼法效果。

当你遇见心仪妹纸时,心里噗通噗通地跳动,此时此刻可用纯CSS描绘你的心情。使用单个<div>结合::before::after,通过错位叠加的方式生成一个心形。在叠加前看看以下图形,是不是发现很像米老鼠呢。





最后巧妙利用transform::before::after平移到相应位置产生叠加错觉。这时分别对::before::after着色,看看其中的奥秘。



在这个基础上来一个更高级的玩法,添加渐变效果让心形变得更么么哒。

整体渐变效果的重点在::after上,由于::after下半部叠加在<div>上,所以下半部颜色必须透明,上半部底部(中线位置)渐变着色必须与<div>顶部渐变着色的颜色一致,这样才能做到无缝衔接。通过Windows系统MacOS系统的测试,在Windows系统下的透明渐变位置需在51%的地方开始,这与屏幕设备的分辨率和广色域有关。

最后为了让渐变心形看起来更具立体感,给它绘制个阴影吧。若觉得这个渐变动感心形很美,可随手转发给女友哇!



意向不到的内容插入

上述提到::before/::after必须结合content使用,那么content就真的只能插入普通字符串吗?content何止这么简单,以下推广几种少见但强大的内容插入技巧。通过这几种技巧,就能很方便地将读取到的数据动态插入到::before::after中。

内容拼接

常规操作是content:"CSS",也可拼接多个字符串,有些同学可能第一时间想起content:"Hello "+"CSS"。拜托,这不是JS而是CSS,CSS字符串拼接当然有自己的规则。CSS字符串拼接既不能使用+相连也可不用空格间隔。

结合attr()使用

attr()是一个被忽略的选择器,它有着强大的属性捕获功能。有这么一个场景,一个数据集合需遍历到每个DOM上并把某个字段插入到其::after上。这该怎么办,好像95%的同学都不会使用JS获取节点的::before::after。这时attr()就派上用场了。

一行CSS代码搞掂,还用什么JS去获取节点的::after呢。当然contentattr()的使用场景不止那一点。

:hover作用于鼠标悬浮的节点,是一个很好用的选择器。在特定场景可代替mouseentermouseleave两个鼠标事件,加上transtion让节点的动画更丝滑。结合attr()有一个很好用的场景,就是鼠标悬浮在某个节点上显示提示浮层,提示浮层里包含着该动作的文本。



结合变量计数器使用

现在来玩高级一点的东西,先不做任何铺垫,接着往下看即可,反正就是content结合变量计数器的使用场景。

笔者想做一个实时显示进度的悬浮球,跟着笔者一起敲代码吧。先画一个绿油油的波波。



进度通常都是从底部往顶部逐渐提升,可用::before绘制一个圆形遮罩层,进度变化时将遮罩层一直往上提升产生障眼效果。提升过程可用绝对定位将遮罩层固定在底部,通过调整margin-bottom平移遮罩层。

为了方便演示,注释父容器的overflow:hidden,通过Chrome Devtools微调margin-bottom看看整体效果。后续记得将overflow:hidden声明回来。



为了让提升过程呈现动态效果,调整::before的背景颜色和圆角率并追加一个旋转动画。



为了让波浪呈现立体效果,追加::after占位并声明整体样式与::before一致,在背景颜色、圆角率和动画时延上略有差异即可。另外声明::aftermargin-bottom稍微比::before高一点,这样在旋转过程中能让波浪产生动态的立体效果。

在提升过程中,两个遮罩层位移距离应该是一致的,所以可用变量计算公式表示且::after::before10px。在这里有个值得注意的地方,若变量结合calc()使用,其结果必须带上单位,以这两条公式为例,其变量初始值必须为--offset:0px,不能为--offset:0



到此再优化一些细节,通过Chrome Devtools检查.wave得知其尺寸为134x134,每次往上平移两个伪元素只能1px那样递增。现在想将其平移100次就能填充整个球体,那么就需按照134/100这个比例改造变量计算公式。

--offset声明为--offset:0,取值区间在0~100而不是0px~100px



现在已把位移距离控制在0~100的比例了,那么剩下步骤就是追加一个<div>,使用其content存放在offset实时显示进度了。



可是发现无任何文本效果。情况是这样的,若变量是字符串类型可直接显示,若变量是数值类型则需借助counter()显示。而counter()还需使用counter-reset初始默认值,CSS计数器怎样用在这里就不讲解了,感兴趣的同学可自行百度。

整体改造工程就这样完成了,完整代码如下。最后通过JS操作变量--offset就能实时改变进度了。



无所不能的模拟点击事件

:checked作用于选项选中的表单节点,当<input>type设置成radiocheckbox时可用。很多同学都会使用input:checked + div {}input:checked ~ div {}的操作模拟鼠标点击事件。要让input:checked + div {}input:checked ~ div {}起效,其HTML结构必须像以下那样。

这样就无法分离结构与行为了,导致CSS必须跟着HTML走,只能使用绝对定位将<input>固定到指定位置。使用<label>绑定<input>可将<input>的鼠标选择事件转移到<label>上,由<label>控制选中状态。那么HTML结构可改为以下那样,此时的<input>可设置hidden隐藏起来,不参与任何排版。

<input>使用id<label>使用for关联起来,而hidden使<input>隐藏起来,不占用页面任何位置,此时<label>放置在页面任何位置都行。

有了这样的思路,就很易实现一个纯CSS标签导航了。



<div class="tab-navbar">
    <input id="tab1" type="radio" name="tabs" hidden checked>
    <input id="tab2" type="radio" name="tabs" hidden>
    <input id="tab3" type="radio" name="tabs" hidden>
    <input id="tab4" type="radio" name="tabs" hidden>
    <nav>
        <label for="tab1">标题1</label>
        <label for="tab2">标题2</label>
        <label for="tab3">标题3</label>
        <label for="tab4">标题4</label>
    </nav>
    <main>
        <ul>
            <li>内容1</li>
            <li>内容2</li>
            <li>内容3</li>
            <li>内容4</li>
        </ul>
    </main>
</div>
.active {
    background-color: #3c9;
    color: #fff;
}
.tab-navbar {
    display: flex;
    overflow: hidden;
    flex-direction: column-reverse;
    border-radius: 10px;
    width: 300px;
    height: 400px;
    input {
        &:nth-child(1):checked {
            & ~ nav label:nth-child(1) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #f66;
                transform: translate3d(0, 0, 0);
            }
        }
        &:nth-child(2):checked {
            & ~ nav label:nth-child(2) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #66f;
                transform: translate3d(-25%, 0, 0);
            }
        }
        &:nth-child(3):checked {
            & ~ nav label:nth-child(3) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #f90;
                transform: translate3d(-50%, 0, 0);
            }
        }
        &:nth-child(4):checked {
            & ~ nav label:nth-child(4) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #09f;
                transform: translate3d(-75%, 0, 0);
            }
        }
    }
    nav {
        display: flex;
        height: 40px;
        background-color: #f0f0f0;
        line-height: 40px;
        text-align: center;
        label {
            flex: 1;
            cursor: pointer;
            transition: all 300ms;
        }
    }
    main {
        flex: 1;
        ul {
            display: flex;
            flex-wrap: nowrap;
            width: 400%;
            height: 100%;
            transition: all 300ms;
        }
        li {
            display: flex;
            justify-content: center;
            align-items: center;
            flex: 1;
            font-weight: bold;
            font-size: 20px;
            color: #fff;
        }
    }
}

笔者曾经发表过一篇 《纯CSS免费让掘金社区拥有暗黑模式切换功能》,探讨了:checked+/~filter的玩法,详情请查看原文,在此就不啰嗦了。



总结

来不及分享的内容,就用文章叙述完,那天看直播的掘友们,让你们久等了。这几年花了很多时间钻研CSS,也许写完本文就要对CSS告一段落了。虽然花了很多时间钻研CSS,但也发布了几篇爆款CSS文章和一本CSS掘金小册,也算是留下了这几年的CSS学习成果了。

喜欢做的事情总不想留什么遗憾。接下来也要将钻研方向转移到JS上了,还是会像钻研CSS那样认真钻研JS的性能优化设计模式数据算法三大装逼套件。期望在2021年能有新的突破吧,也感谢掘金社区让我学习到别人的知识和别人学习到我的知识。

分享源码存放在笔者的 Github上,有需要的同学可拷贝一份。还有就是笔者向可爱漂亮的小册姐姐要了100份 玩转CSS的艺术之美六折优惠码WmOrR0hR,对该小册感兴趣的同学可了解一下哟!

CSS是一门天马行空的语言,说它简单也行说它困难也行。想了解更多纯CSS特效,可回看笔者往期文章,也可浏览笔者个人官网的 纯CSS特效专辑,保证满足你的眼球。

结语

❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作更多高质量文章

关注公众号IQ前端,一个专注于CSS/JS开发技巧的前端公众号,更多前端小干货等着你喔


代做工资流水公司咸阳贷款工资流水宁波签证银行流水 公司许昌制作企业对公流水衡阳贷款流水价格包头背调银行流水银行流水查询舟山银行流水账单打印宁波入职银行流水价格苏州房贷流水办理邯郸制作公司银行流水银川入职流水打印盐城办理企业贷流水肇庆开贷款工资流水无锡开离职证明柳州办签证流水贵阳代开贷款银行流水湖州个人工资流水 图片惠州打印工资流水单吉林办理公司银行流水威海办工作收入证明合肥工资银行流水制作成都办在职证明江门银行流水账打印扬州办自存银行流水德阳工资证明开具盐城制作企业对公流水泰安办银行流水修改上饶自存流水开具汕头企业对公流水样本商丘自存流水模板香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化