h1 { color: blue; }那时的选择器简单、有效,但非常有限。这就像用蜡笔绘制西斯廷教堂一样。为了增加更多的灵活性,CSS2引入了新的选择器,比如子元素选择器(>)、相邻兄弟选择器(+)和属性选择器([attr=value])。这些选择器可以实现更精确的样式化:
/* 堆代码 duidaima.com */ /* 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; }我们不再只是对元素进行样式设置,而是与它们互动,探索它们的属性,它们之间的关系。我们开始打造复杂的设计,能够根据内容的结构和含义进行响应式布局。
/* :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()》。
#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" */ }了解如何与级联一起工作,而不是对抗它,将能够避免许多问题。使用特异性计算器等工具可以大有裨益。
@media only screen and (max-width: 600px) { body { background-color: lightblue; } }在这个例子中,当屏幕宽度小于或等于600px时,body的背景色会变成浅蓝色。这使得CSS在创建响应式设计中扮演着重要的角色。
button { transition: background-color 0.5s ease; } button:hover { background-color: blue; }在这段代码中,当你将鼠标悬停在按钮上时,它的背景色会在半秒钟的时间内过渡到蓝色。
: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变量的威力!
<table> <tr> <td>Header</td> </tr> <tr> <td>Main Content</td> <td>Sidebar</td> </tr> <tr> <td>Footer</td> </tr> </table>那是一个我们迫使HTML按照我们的意愿弯曲的时代,将其用于并非原本意图的用途——布局。但嘿,我们让它发挥作用了,对吧?但让我们真实一点,那是一种痛苦。代码难以维护,可访问性受到了影响,响应式设计也只是一个遥远的梦想。我们需要一种改变,而CSS就是那个改变!
.column { float: left; width: 50%; }就这样,我们就有了一个双列布局。听起来很简单,对吧?但问题出现在我们尝试在浮动元素下方添加更多元素时。突然间,我们的页脚就像自己闯荡一样,紧贴在DOM结构中更高的内容旁边。哦,这个混乱!
.group:after { content: ""; display: table; clear: both; }通过在容器中添加一个伪元素:after,并给它设置display: table;和clear: both;,我们有效地清除了浮动。突然间,我们的页脚回到了它们应该在的位置,一切都恢复了正常。尽管浮动具有一些古怪和意外的行为,但掌握浮动对于每个网页开发人员来说是一种成长的必经之路。它教会了我们理解CSS的盒子模型、文档流以及CSS可能表现出的奇妙和奇异的方式的重要性。这是一个具有挑战性的、有时让人抓狂的经历,但它是通向我们今天所熟悉和喜爱的CSS之路上的重要里程碑。
.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专家。
.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; }对未来的一瞥
/* 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; } }样式查询
<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伪类
<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
.parent { color: blue; .child { color: red; } }此外,你还可以嵌套媒体查询(和容器查询):
.card { display: flex; gap: 1rem; @media (width >= 480px) { display: grid; } }另外,第一个例子也可以这样写:
.parent { color: blue; & .child { color: red; } }子网格
<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
@scope (.card) { /* only affects a .title that is within a .card */ .title { font-weight: bold; } }滚动驱动的动画
级联层(@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
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; }结束