能用CSS就不用JS!盘点15个让你直呼“哇塞”的CSS技巧

1,701 阅读7分钟

在前端开发的世界里,我们常常听到一句话:“这效果实现不了?上JS啊!” 于是,为了一个简单的Tabs切换、一个元素的显隐,我们可能就引入了一个库,或者手写了一段DOM操作。

但随着CSS语言的飞速发展,许多过去必须依赖JavaScript才能实现的交互和效果,如今仅用纯CSS就能优雅地完成。这不仅能让我们的代码更简洁、更易维护,通常也意味着更好的性能。

今天,我为你盘点了15个CSS技巧。它们将向你展示,作为一名现代Web开发者,我们能将CSS发挥到何种地步。


1. 交互式Tabs切换 (:has())

过去,纯CSS Tabs切换大多依赖“checkbox hack”,但现在,我们有了更优雅的选择::has() 伪类。

(注::has() 目前在主流浏览器中支持度很好,但仍需注意旧版本浏览器)

<div class="tabs">
  <div class="tab-nav">
    <a href="#content1" class="active">Tab 1</a>
    <a href="#content2">Tab 2</a>
    <a href="#content3">Tab 3</a>
  </div>
  <div class="tab-content">
    <div id="content1" class="tab-pane">内容一</div>
    <div id="content2" class="tab-pane">内容二</div>
    <div id="content3" class="tab-pane">内容三</div>
  </div>
</div>

(为实现纯CSS交互,我们将JS的点击切换改为<a>标签的锚点链接)

.tab-pane {
  display: none;
}
/* 当某个锚点被激活时,:has() 会找到对应的 tab-pane 并显示它 */
.tabs:has(#content1:target) #content1,
.tabs:has(#content2:target) #content2,
.tabs:has(#content3:target) #content3 {
  display: block;
}
/* 默认显示第一个 */
.tabs:not(:has(:target)) #content1 {
  display: block;
}
/* 也可以用 :has() 控制激活的导航样式,但更简单的方式是 :target 伪类本身 */

:has() 实现了“父级选择器”的能力,让我们可以根据后代元素的状态来改变父级或兄弟元素的样式,极大地扩展了CSS的交互可能性。

2. 手风琴/折叠面板 (<details> & <summary>)

这是一个原生HTML标签提供的、几乎被遗忘的宝藏。

<details class="accordion">
  <summary>点击展开第一节</summary>
  <p>这里是第一节的详细内容...</p>
</details>
<details class="accordion">
  <summary>点击展开第二节</summary>
  <p>这里是第二节的详细内容...</p>
</details>
.accordion {
  border: 1px solid #ccc;
  margin-bottom: 5px;
}
.accordion summary {
  padding: 10px;
  cursor: pointer;
  background: #f0f0f0;
}
/* 为展开状态加个小动画 */
.accordion[open] > p {
  padding: 10px;
  animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
}

零JS,自带语义和无障碍访问(ARIA)属性,还支持CSS动画,完美。

3. 跟随滚动的动画 (Scroll-driven Animations)

这是CSS最新的“黑魔法”之一,让元素可以根据滚动进度来播放动画。

<div class="scroll-container">
  <div class="progress-bar"></div>
  <div class="content">...大量内容...</div>
</div>
.scroll-container {
  height: 200px;
  overflow-y: scroll;
  border: 1px solid #ccc;
  /* 定义一个滚动进度时间线 */
  scroll-timeline: --my-scroll-timeline block;
}
.progress-bar {
  position: sticky;
  top: 0;
  height: 10px;
  background: linear-gradient(to right, lime, cyan);
  /* 将动画绑定到滚动时间线 */
  animation: progress auto linear;
  animation-timeline: --my-scroll-timeline;
}
@keyframes progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

将复杂的滚动监听逻辑,简化为几行CSS声明,性能比JS监听滚动事件好得多。

4. 响应式字体排版 (clamp())

告别复杂的媒体查询来设置字体大小,一个函数搞定。

h1 {
  /* 字体大小最小24px,最大48px,理想值为视口宽度的5% */
  font-size: clamp(24px, 5vw, 48px);
}

clamp(MIN, IDEAL, MAX) 提供了一个“区间锁”,让你的排版在不同屏幕尺寸下流畅缩放,代码极其简洁。

5. 不规则文字环绕 (shape-outside)

让文字不再局限于矩形盒子,可以围绕着圆形、多边形甚至图片的不规则轮廓进行排列。

<div class="shape-container">
  <div class="floated-shape"></div>
  <p>这里的文字会优雅地环绕着左侧的圆形进行排列,创造出杂志般的排版效果...</p>
</div>
.floated-shape {
  float: left;
  width: 150px;
  height: 150px;
  background: #61dafb;
  /* 定义环绕的形状为一个圆形 */
  shape-outside: circle(50%);
  clip-path: circle(50%); /* 让元素本身也变成圆形 */
}

轻松实现以往只有在专业排版软件中才能看到的图文混排效果。

6. 自定义光标下划线效果

<a href="#" class="fancy-link">Hover Me</a>
.fancy-link {
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 2px;
  transition: background-size .3s;
}
.fancy-link:hover {
  background-size: 100% 2px;
}

利用background-size的过渡动画,实现比text-decoration更酷炫、更可控的下划线效果。

7. 粘性定位 (Position Sticky)

实现侧边栏、导航栏在滚动到指定位置后固定的效果。

<div class="parent">
  <div class="sticky-element">粘性元素</div>
  </div>
.sticky-element {
  position: sticky;
  top: 10px; /* 当它滚动到距离视口顶部10px时,就会固定住 */
}

一个position属性就替代了过去需要监听滚动、计算offset、添加/移除class等一系列JS操作。

8. 优雅的表单控件 :focus-within

当父元素内的任意一个子元素获得焦点时,为父元素添加样式。

<div class="input-group">
  <label for="name">姓名:</label>
  <input type="text" id="name">
</div>
.input-group {
  border: 2px solid #ccc;
  transition: border-color .3s;
}
.input-group:focus-within {
  border-color: #61dafb;
}

无需JS判断,就能实现交互性极强的表单高亮效果,提升用户体验。

9. 滚动吸附效果 (Scroll Snapping)

让滚动在特定点自动“吸附”停止,常用于全屏滚动和图片画廊。

<div class="snap-container">
  <section class="snap-item">1</section>
  <section class="snap-item">2</section>
  <section class="snap-item">3</section>
</div>
.snap-container {
  height: 300px;
  overflow-y: scroll;
  /* 在父容器上开启y轴的强制吸附 */
  scroll-snap-type: y mandatory;
}
.snap-item {
  height: 300px;
  /* 定义子元素的吸附对齐点为顶部 */
  scroll-snap-align: start;
}

用几行CSS就实现了类似Swiper、fullPage.js的核心滚动效果。

10. 动态主题切换 (CSS Variables)

利用CSS自定义属性,轻松实现日间/夜间模式切换。

:root {
  --bg-color: #ffffff;
  --text-color: #333333;
}
body.dark-mode {
  --bg-color: #1a1a1a;
  --text-color: #f0f0f0;
}
body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background-color .3s, color .3s;
}

只需要一行JS切换bodyclass (document.body.classList.toggle('dark-mode');),剩下的颜色变化全部由CSS自动完成,逻辑分离,非常优雅。

11. 锥形渐变做饼图 (conic-gradient)

<div class="pie-chart"></div>
.pie-chart {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: conic-gradient(
    #ff6347 0% 30%,      /* 红色部分 30% */
    #4682b4 30% 75%,      /* 蓝色部分 45% */
    #32cd32 75% 100%     /* 绿色部分 25% */
  );
}

告别复杂的SVG或Canvas,一个background属性就能搞定数据可视化饼图。

12. 毛玻璃效果 (backdrop-filter)

让元素背后的内容变得模糊,常用于弹窗蒙层和导航栏。

.frosted-glass {
  background: rgba(255, 255, 255, 0.3);
  /* 关键属性:对元素背后的内容应用模糊滤镜 */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px); /* 兼容 Safari */
}

轻松实现iOS风格的毛玻璃UI,质感瞬间提升。

13. 自定义列表标记 (::marker)

终于可以轻松地修改列表项前面那个小圆点或数字的样式了。

ul li::marker {
  color: #ff6347;
  font-size: 1.5em;
  content: "🚀 "; /* 甚至可以用任意字符或图片替换 */
}

解决了多年来前端开发者需要用各种hack方式才能自定义列表标记的痛点。

14. 文本溢出显示省略号 (多行)

单行很简单,但多行呢?CSS也可以!

.multiline-ellipsis {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3; /* 你希望显示的行数 */
  overflow: hidden;
  text-overflow: ellipsis;
}

虽然需要使用私有前缀,但这依然是目前最简洁、最有效的多行文本截断方案。

15. 比较函数 (min(), max())

clamp()类似,它们提供了更灵活的动态计算能力。

.element {
  /* 宽度为视口宽度的80%或最大不超过800px */
  width: min(80vw, 800px);

  /* 内边距至少为15px,或视口宽度的4% */
  padding: max(15px, 4vw);
}

让布局和尺寸的响应式处理更加语义化,代码可读性更高。


🙂

CSS的世界日新月异,曾经那些看似不可能的任务,如今都变成了现实。掌握这些“技巧”,不仅能让我们写出更高效、更优雅的代码,更重要的是,它能拓宽我们的解题思路,不用js 也可以写出页面特效。

📌 你可以继续看我的系列文章