转载说明:原创不易,未经授权,谢绝任何形式的转载
很久以前,CSS就像一阵清新的气息,只需简单轻松地为页面添加样式。
它涉及设定规则,让浏览器自动处理。你可以改变边距、字体和大小,但这只是浅尝辄止,你懂的吗?
真正的亮点是那个"级联"的特性,允许样式继承和覆盖其他样式,创造出一些动态、酷炫的页面。快进到今天,CSS就像网页设计的瑞士军刀。它具备了使用弹性盒子和网格来实现动画、转换和适应布局的能力,使得网页变得响应式和酷炫。
从基本样式到复杂动画,CSS已经发展到了一个全新的层次。它不再只是简单的样式设置,而是让你的整个网页焕发生机。
让我们深入了解CSS是如何发展至今的(或者直接滚动到最后一节,展望未来…)。
CSS选择器就像标签游戏中的精确指令。它是一条规则,用于识别需要样式化的HTML元素。无论你是指向一个<div>、.class还是#id,选择器都是你的样式声明的信使,确保正确的元素被"标记"。让我带你回到CSS的早期时代。那是一个网页设计新鲜、原始,而且在很多方面都有限制的时代。还记得旧的HTML标签,比如font和center吗?我们使用它们是因为我们必须这样做,而不是因为我们想这样做。然后,就像90年代漫画书中的超级英雄一样,CSS出现了,它带来了选择器的力量。最初的CSS选择器和它们所应用的HTML一样基本:
h1 { color: blue;}
那时的选择器简单、有效,但非常有限。这就像用蜡笔绘制西斯廷教堂一样。
为了增加更多的灵活性,CSS2引入了新的选择器,比如子元素选择器(>)、相邻兄弟选择器(+)和属性选择器([attr=value])。这些选择器可以实现更精确的样式化:
/* Child Selector */div > p { color: red;}/* Adjacent Sibling Selector */h1 + p { margin-top: 20px;}/* Attribute Selector */input[type="text"] { width: 200px;}
这些选择器让我们能够表达元素之间更复杂的关系,使我们的样式表更高效和有组织。这是一个进步,但我们仍然需要更多。
然后出现了CSS3。它通过更强大的工具扩展了CSS选择器的能力,例如通用兄弟组合器(~)、:not()伪类以及一系列的属性选择器:
/* General Sibling Combinator */h1 ~ p { font-size: 1.2em;}/* :not() Pseudo-class */div:not(.highlighted) { opacity: 0.5;}/* Attribute Selectors */a[href*="google"] { background: url(/images/google-icon.png) no-repeat;}
我们不再只是对元素进行样式设置,而是与它们互动,探索它们的属性,它们之间的关系。我们开始打造复杂的设计,能够根据内容的结构和含义进行响应式布局。
CSS3带来了伪类,如:nth-child、:nth-of-type、:checked,以及伪元素::before和::after。我们的蜡笔已经变成了一个完整的艺术家调色板,而Web的画布也因此变得更加丰富多彩。
/* :nth-child Selector */li:nth-child(odd) { background: lightgray;}/* :checked Pseudo-class */input[type="checkbox"]:checked { border-color: green;}/* ::before and ::after Pseudo-elements */blockquote::before { content: "❝"; font-size: 3em;}blockquote::after { content: "❞"; font-size: 3em;}
还值得一提的选择器是伪类:is。它允许你将多个选择器组合在一条语句中,减少代码的重复性,提高可读性。如果你想深入了解,请查阅Steve的文章《Simpler CSS Selectors With :is()》。
最后还有一个提到的选择器是:where,它与:is类似。然而,关键的区别在于:where的特异性始终为0。
选择器为我们提供了在代码中表达创意愿景的工具。它们不断演进,推动着Web进入设计的更加令人兴奋的前沿。
级联是CSS的一个关键特性,当正确利用时,可以使你的样式表更高效、更易于维护。它指的是将不同的样式表结合起来,并解决适用于同一元素的不同CSS规则之间的冲突。
这里的特异性概念发挥了关键作用。ID选择器的特异性高于类选择器,类选择器的特异性高于类型选择器。
#header { color: blue; /* This will apply because ID selectors have the highest specificity */}.container .header { color: red; /* This won't apply to the element with id "header" */}header { color: green; /* This won't apply to the element with id "header" */}
了解如何与级联一起工作,而不是对抗它,将能够避免许多问题。使用特异性计算器等工具可以大有裨益。
媒体查询是CSS的一个关键优势,它提供了内置的响应式设计能力。媒体查询帮助你针对不同的设备或屏幕宽度应用不同的样式。这种灵活性使得你能够根据不同的设备特性和屏幕尺寸进行定制化的样式设置。
@media only screen and (max-width: 600px) { body { background-color: lightblue; }}
在这个例子中,当屏幕宽度小于或等于600px时,body的背景色会变成浅蓝色。这使得CSS在创建响应式设计中扮演着重要的角色。
让我们回顾一下CSS中的媒体查询是如何保持新鲜的:
现在:媒体查询在所有主要的浏览器中都得到支持,并成为响应式网页设计中的关键工具。
通过CSS3,动画和过渡已成为现代网页的重要组成部分,创造了动态的用户体验。你可以在一段时间内使CSS属性发生变化,控制过渡的速度,并创建基于关键帧的动画效果。
button { transition: background-color 0.5s ease;}button:hover { background-color: blue;}
在这段代码中,当你将鼠标悬停在按钮上时,它的背景色会在半秒钟的时间内过渡到蓝色。
自1997年成立以来,CSS工作组就意识到了对CSS变量的需求。到了2000年代末,开发人员已经创造了各种解决方案,如自定义PHP脚本和预处理器(如Less和Sass),以弥补这个缺陷。
意识到内置的解决方案将简化这个过程,该组在2012年发布了CSS变量模块的第一个草案。在2017年,它更名为层叠变量的CSS自定义属性,并得到了广泛的浏览器支持。
过去,更新CSS值是一项手动、耗时的工作,静态CSS的时代已经过去了。现在,我们的工具包中有了CSS变量,可以在整个样式表中存储和重用特定的值。这些变量确保一致性,并使更新变得轻而易举。
以下是CSS变量的一些示例:
:root { --brand-color: #32a852;}body { background-color: var(--brand-color);}/* On hovering over the body, the brand color changes */body:hover { --brand-color: #a83258;}
将鼠标悬停在页面上,瞧!你的网站样式完全变了个样。这就是CSS变量的威力!
多年来,CSS布局经历了许多变化。开发人员过去常常使用表格和浮动来创建布局,但这种方式难以维护,而且不太适应响应式设计。后来,媒体查询、弹性盒子和网格布局的引入彻底改变了开发人员创建布局的方式,使其更具响应性和易于维护。让我们深入了解一下。
摆脱基于表格的布局,转向CSS
进入21世纪初,基于表格的布局时代开始逐渐消退。还记得那些时光吗?当我们使用table、tr和td来安排页面上的一切,甚至连布局都是如此。啊,那些日子真是美好!
<table> <tr> <td>Header</td> </tr> <tr> <td>Main Content</td> <td>Sidebar</td> </tr> <tr> <td>Footer</td> </tr></table>
那是一个我们迫使HTML按照我们的意愿弯曲的时代,将其用于并非原本意图的用途——布局。但嘿,我们让它发挥作用了,对吧?但让我们真实一点,那是一种痛苦。代码难以维护,可访问性受到了影响,响应式设计也只是一个遥远的梦想。我们需要一种改变,而CSS就是那个改变!
啊,浮动布局的时代。亲爱的读者们,我几乎可以看到你们脸上的怀旧微笑和沮丧的表情。你们知道,在flexbox出现并让我们的生活变得轻松得多之前,我们一直被困在浮动布局的世界里。
最初作为围绕图片排列文本的简单方法(想象报纸的版面布局),浮动成为了创建整个网页布局的意外工具。
.column { float: left; width: 50%;}
就这样,我们就有了一个双列布局。听起来很简单,对吧?但问题出现在我们尝试在浮动元素下方添加更多元素时。突然间,我们的页脚就像自己闯荡一样,紧贴在DOM结构中更高的内容旁边。哦,这个混乱!
这是由于浮动元素的一个特殊特性导致的。它们在正常的文档流中被部分移除,这意味着在标记中跟随它们的元素会像浮动元素不存在一样行为。
为了解决这个问题,我们不得不求助于我们现在亲切(或不太亲切)称之为"clearfix黑科技"的方法。这个黑科技通过创建一个新的块级格式化上下文,强制容器展开以包含浮动元素。
这是著名的clearfix黑科技,它拯救了许多布局:
.group:after { content: ""; display: table; clear: both;}
通过在容器中添加一个伪元素:after,并给它设置display: table;和clear: both;,我们有效地清除了浮动。突然间,我们的页脚回到了它们应该在的位置,一切都恢复了正常。
尽管浮动具有一些古怪和意外的行为,但掌握浮动对于每个网页开发人员来说是一种成长的必经之路。它教会了我们理解CSS的盒子模型、文档流以及CSS可能表现出的奇妙和奇异的方式的重要性。这是一个具有挑战性的、有时让人抓狂的经历,但它是通向我们今天所熟悉和喜爱的CSS之路上的重要里程碑。
两个最重要的改变游戏规则的因素,极大地改进了网页开发,它们分别是:flexbox。这两个家伙完全颠覆了布局设计的常规。
首先是flexbox。在CSS3中引入的flexbox对于盒子的对齐、方向、顺序和大小的设置是一次彻底的革命。不再需要处理浮动和定位的困扰了,大家注意啦。flexbox使得创建灵活、响应式的布局变得简单,用更少的代码获得更多的控制。下面是一个简单的代码示例,向你展示如何使用它:
.container { display: flex; justify-content: space-between;}.item { flex: 1;}
在这个例子中,我们将容器设置为display: flex;,让其子元素知道它们处于flex上下文中。justify-content: space-between;让我们的项目之间保持良好的间距。然后我们使用flex: 1;给项目添加了相同的宽度,填满了整个容器的空间。简洁而简单。
然后是grid布局,下一个重大飞跃。Grid布局在2017年左右引入,将CSS布局提升到了一个全新的水平,同时让我们定义了列和行。CSS grid让我们能够创建复杂的二维布局,在之前是非常困难的。以下是一个简单示例:
.container { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px;}.item { grid-column: span 2;}
在这段代码中,.container是我们的网格容器。我们使用grid-template-columns: repeat(3, 1fr);定义了三个相等宽度的列,并使用grid-gap: 10px;设置它们之间的间距为10像素。然后对于我们的项目,我们使用grid-column: span 2;使项目跨越两列。那真是强大的功能!
如果你研究一下grid-template-areas属性,你就可以成为真正的CSS grid专家。
还记得居中元素时的困扰吗?不论是垂直居中还是水平居中,组合使用各种属性如margin、position、top、left和transform,足以让人头晕目眩。
.container { position: relative;}.element { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);}
快进到今天,flexbox让居中变得轻而易举:
.container { display: flex; justify-content: center; align-items: center;}
在过去,创建复杂布局通常意味着使用浮动元素,这可能会很棘手且难以管理。以下是使用浮动元素创建双列布局的简化示例:
.container::after { content: ""; display: table; clear: both;}.column { float: left; width: 50%;}
如今,借助CSS Grid,你可以用极少的代码创建复杂的布局,而无需头痛的困扰:
.container { display: grid; grid-template-columns: 1fr 1fr;}
CSS中有几个即将推出的功能和改进已经在网页设计和开发社区引起了极大的关注。你可以在Chrome团队的最新文章《CSS和UI的新特性》中找到详细的列表。
以下是我对其中一些功能感到兴奋的原因:
容器查询
目前尚未在Firefox和Safari中支持
容器查询使得能够对子元素进行样式设置,并在布局中进行布局控制。可以根据元素的可用空间来进行元素的改变,如下所示:
由于容器查询的存在,样式是动态的。改变视口的大小会根据每个元素的可用空间触发相应的变化。
语法与媒体查询有些相似,只是你只需定义在容器大小满足条件时所需的样式:
以下是实际应用的样子:
/* Create a containment context */.post { container-type: inline-size; /* size & normal are valid values as well */}/* Default heading styles for the card title */.card h2 { font-size: 1em;}/* If the container is larger than 700px */@container (min-width: 700px) { .card h2 { font-size: 2em; }}
样式查询
目前尚未在Firefox和Safari中支持
查询父容器的样式值:
<li class="card-container" style="--sunny: true;"> <div class="weather-card"> <div class="day">Saturday</div> <div class="date">February <span>12</span></div> <div class="temps"> <div class="high">High: <span>55</span></div>/ <div class="low">Low: <span>47</span></div> </div> <div class="features"> Clear skies, sun </div> </div></li><style>.card-container { container-name: weather;}/* In case the custom propery --sunny: true; change the child */@container style(--sunny: true) { .weather-card { background: linear-gradient(-30deg, yellow, orange); } .weather-card:after { content: url(<data-uri-for-demo-brevity>); background: gold; }}</style>
:has伪类
目前尚未在Firefox中支持。
根据后代元素来设置样式的一种方法。基本上,你可以根据子元素来应用样式,这意味着它可以作为一种理想的父选择器。然而,你也可以在父元素内部对子元素进行样式设置。
<article> <h1>Hello</h1> <h2>World</h2></article><style>/* style parent according to children */article:has(h1) { background: lightgray;}/* style child by parent content */article:has(h1) h2 { color: yellow;}/* style sibling by adjacent element */h1:has(+ h2) { color: hotpink;}</style>
text-wrap: balance
目前仅在Chromium中支持
这个新值,顾名思义,将允许你平衡文本,因此你不再需要使用JS来实现。将其应用于文本块将真正让你的设计师开心。
嵌套
目前尚未在Firefox中支持
最后,就像SASS和Less一样,嵌套和共同定位与选择器相关的样式:
.parent { color: blue; .child { color: red; }}
此外,你还可以嵌套媒体查询(和容器查询):
.card { display: flex; gap: 1rem; @media (width >= 480px) { display: grid; }}
另外,第一个例子也可以这样写:
.parent { color: blue; & .child { color: red; }}
子网格
在Firefox和Safari中得到支持,并在Chrome的标志下使用
子网格是完善网格布局的一部分,可以将网格布局应用于网格项的子元素,从而实现更一致和可维护的布局。通过添加grid-template-rows或grid-template-columns属性并设置为subgrid值来使用:
<div class="grid"> <div class="item"> <div class="subitem"></div> </div></div><style>/* some styles removed for brevity */.grid { display: grid; grid-template-columns: repeat(9, 1fr); grid-template-rows: repeat(4, minmax(100px, auto));}.item { display: grid; grid-column: 2 / 7; grid-row: 2 / 4; grid-template-columns: subgrid; grid-template-rows: subgrid; background-color: #ffd8a8;}.subitem { grid-column: 3 / 6; grid-row: 1 / 3; background-color: rgb(40, 240, 83); /* green */}</style>
Scoped CSS
仍处于工作草案阶段,指定特定样式适用的范围,从本质上为CSS创建本地的命名空间:
@scope (.card) { /* only affects a .title that is within a .card */ .title { font-weight: bold; }}
滚动驱动的动画
仍处于实验阶段
根据滚动容器的滚动位置控制动画的播放。再次减少了使用JavaScript创建视差滚动、阅读指示器等功能的复杂性。你可以在这里看到一些很棒的演示。
级联层(@layer)
现在得到了广泛支持,在存在多个级联层的情况下,定义了优先级的顺序。您可以根据重要性对样式表进行排序:
@layer base { a { font-weight: 800; color: red; /* ignored */ } .link { color: blue; /* ignored */ }}@layer typography { a { color: green; /* styles *all* links */ }}@layer utilities { .pink { color: hotpink; /* styles *all* .pink's */ }}
View transitions
(在Firefox和Safari中不受支持)
允许在单个步骤中更改DOM,同时在两个状态之间创建动画过渡。不再需要使用单页应用程序(SPA)来完成此操作。
这需要一些JavaScript:
function spaNavigate(data) { // Fallback for browsers that don't support this API: if (!document.startViewTransition) { updateTheDOMSomehow(data); return; } // With a transition: document.startViewTransition(() => updateTheDOMSomehow(data));}
然后 CSS 接管:
@keyframes slide-from-right { from { opacity: 0; transform: translateX(75px); }}@keyframes slide-to-left { to { opacity: 0; transform: translateX(-75px); }}::view-transition-old(root) { animation: 350ms both slide-to-left ease;}::view-transition-new(root) { animation: 350ms both slide-from-right ease;}
CSS的未来充满了巨大的潜力,可以简化复杂的任务,提升性能,并让开发者创建沉浸式的体验。
随着CSS的发展,我们可能会看到新的高级特性涌现,模糊了CSS和JavaScript之间的界限,为目前依赖于JavaScript库的任务提供了原生解决方案。
此外,可能会出现更全面的CSS框架,利用这些新功能。
保持对最新的CSS发展的了解非常重要,因为CSS在网页设计和开发中的重要性持续存在。关注CSS Working Group的更新、追随行业领导者,并探索浏览器预览中的新功能,将有助于您保持更新。
拥抱前方令人兴奋的可能性,不断学习,并积极参与塑造未来的网络。
由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。