普通视图

发现新文章,点击刷新页面。
昨天以前首页

用 Stylus 写 CSS 有多爽?从响应式面板案例看透它的优雅

2025年10月29日 17:06

作为前端开发者,你是否也曾被 CSS 的冗余语法、重复代码折磨过?写一个嵌套结构要反复敲选择器,改一个样式要全局搜半天?今天要聊的 Stylus,可能会让你重新爱上写样式 —— 它用极简的语法、强大的编程特性,把 CSS 变成了一门 "可编写" 的语言。

本文不会空谈理论,而是通过一个「响应式图片面板」案例,带你沉浸式体验 Stylus 的优雅:从安装到实战,从布局到交互,看完就能上手。

一、初识 Stylus:比 CSS 更懂开发者的预处理器

Stylus 是三大 CSS 预处理器(Sass、Less、Stylus)中最 "叛逆" 的一个 —— 它彻底抛弃了 CSS 的冗余语法,括号、分号、冒号都成了 "可选品"。这种极简主义,让写样式变得像写伪代码一样流畅。

1. 先装起来,跑通流程

全局安装 Stylus(需要 Node 环境):

bash

npm i -g stylus

新建style.styl文件,写完后编译成浏览器能识别的 CSS:

bash

# 单次编译:将style.styl编译为style.css
stylus style.styl -o style.css

# 实时编译:边写边更,开发必备
stylus style.styl -o style.css -w

2. 语法对比:Stylus vs 原生 CSS

同样一段样式,感受下差异:

原生 CSS

css

.card {
  width: 50px;
  height: 45px;
  background: #fff;
}
.card .title {
  font-size: 16px;
  color: #333;
}
.card.active {
  border: 1px solid #f00;
}

Stylus

stylus

.card
  width 50px
  height 45px
  background #fff
  .title
    font-size 16px
    color #333
  &.active
    border 1px solid #f00

是不是瞬间清爽了?没有括号、分号,嵌套直接用缩进(像 Python 一样),&还能轻松表示父元素自身的状态 —— 这只是 Stylus 的冰山一角。

二、实战:用 Stylus 实现响应式图片面板

我们要做的效果是:一个横向排列的图片面板,点击任意面板会展开放大,其他面板收缩;在手机端自动隐藏部分面板,适配小屏幕。

先看最终效果框架:

  • 桌面端:5 个面板横向排列,点击展开
  • 移动端(≤480px):只显示前 3 个面板,占满屏幕宽度

1. HTML 结构:极简骨架

html

预览

<div class="container">
  <div class="panel active" style="background-image: url('图片1')">
    <h3>Explore The World</h3>
  </div>
  <div class="panel" style="background-image: url('图片2')">
    <h3>Wild Forest</h3>
  </div>
  <!-- 共5个面板,省略后3个 -->
</div>

2. JavaScript 交互:点击切换激活状态

用排他思想实现 "点击谁,谁放大":

javascript

运行

const panels = document.querySelectorAll('.panel');

panels.forEach(panel => {
  panel.addEventListener('click', () => {
    // 移除其他面板的active类
    document.querySelector('.active')?.classList.remove('active');
    // 给当前面板添加active类
    panel.classList.add('active');
  });
});

3. Stylus 样式:核心代码拆解

这部分是重点,我们一步步解析 Stylus 如何用更少的代码实现复杂布局和交互。

(1)基础重置与全局布局

stylus

*
  margin 0
  padding 0

body
  display flex
  flex-direction row
  justify-content center
  align-items center
  height 100vh
  overflow hidden
  • * 选择器重置默认边距,Stylus 中直接写*+ 缩进即可
  • display flex 替代display: flex;,少写冒号和分号
  • 100vh让 body 占满全屏,overflow hidden隐藏滚动条

(2)容器与面板布局:嵌套语法的妙用

stylus

.container
  display flex
  width 90vw  // 桌面端占视口90%宽度

  .panel
    height 80vh
    border-radius 50px
    color #fff
    cursor pointer
    flex 0.5  // 未激活时占比0.5
    margin 10px
    position relative
    background-size cover
    background-position center
    background-repeat no-repeat
    transition all 700ms ease-in  // 过渡动画:所有属性变化用700ms完成

    h3
      font-size 24px
      position absolute
      left 20px
      bottom 20px
      margin 0
      opacity 0  // 初始隐藏标题
      transition opacity 700ms ease-in 400ms  // 标题延迟400ms显示

    &.active  // 激活状态(&代表父元素.panel)
      flex 5  // 激活时占比5(挤压其他面板)
      h3
        opacity 1  // 显示标题

这段代码的优雅之处:

  • 嵌套层级清晰.container包含.panel.panel包含h3,结构和 HTML 一一对应,不用反复写父选择器
  • & 符号的灵活使用&.active直接表示.panel.active,比 CSS 中重复写.panel简洁太多
  • 过渡动画简写transition all 700ms ease-in 替代冗长的transition: all 700ms ease-in;

(3)响应式适配:媒体查询的极简写法

stylus

@media (max-width 480px)
  .container
    width 100vw  // 移动端占满屏幕

  .panel:nth-of-type(4),
  .panel:nth-of-type(5)
    display none  // 隐藏第4、5个面板

对比原生 CSS 的媒体查询:

css

@media (max-width: 480px) {
  .container {
    width: 100vw;
  }
  .panel:nth-of-type(4), .panel:nth-of-type(5) {
    display: none;
  }
}

Stylus 直接省略了括号和分号,甚至连媒体查询的大括号都省了,缩进即层级 —— 写响应式布局像写普通样式一样自然。

三、Stylus 的其他 "爽点":不止于简洁

案例中用到的只是 Stylus 的基础功能,它真正强大的地方在于 "编程特性":

1. 变量:一次定义,多处复用

stylus

// 定义主题变量
primary-color = #3498db
panel-height = 80vh
border-radius = 50px

// 使用变量
.panel
  height panel-height
  border-radius border-radius
  &.active
    border 2px solid primary-color

改样式时只需改变量,不用全局搜索替换,适合大型项目。

2. 混合(Mixins):复用代码块

stylus

// 定义一个"弹性居中"的混合
flex-center()
  display flex
  justify-content center
  align-items center

// 复用混合
.container
  flex-center()  // 直接调用

.btn-group
  flex-center()  // 再次复用

减少重复代码,尤其适合封装常用布局模式(如清除浮动、响应式断点)。

3. 自动前缀:无需手动写 - webkit-

配合stylus-mixin等工具,Stylus 能自动为 CSS3 属性添加浏览器前缀:

stylus

// 写一次
transform scale(1.1)

// 编译后自动生成
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
transform: scale(1.1);

四、为什么推荐用 Stylus?

从案例和特性来看,Stylus 的核心优势在于:

  1. 极简语法:少写 80% 的冗余符号,专注逻辑而非格式
  2. 嵌套清晰:HTML 结构和 CSS 样式一一对应,降低维护成本
  3. 编程能力:变量、混合、函数等特性,让 CSS 具备 "可复用、可扩展" 能力
  4. 无缝过渡:完全兼容 CSS 语法,不会 CSS 也能快速上手

五、最后:从案例到生产

本文的案例代码可以直接运行,你可以:

  1. 替换图片 URL 为自己的资源
  2. 调整flex值和transition时间改变动画效果
  3. 新增媒体查询断点适配更多设备

如果要在生产环境使用,建议结合构建工具(如 Webpack、Vite)配置 Stylus-loader,实现自动编译和压缩。

Stylus 不是银弹,但它绝对是提升 CSS 开发效率的 "利器"。如果你受够了写冗余的 CSS,不妨从这个响应式面板案例开始,感受 Stylus 带来的优雅 —— 毕竟,谁不想用更少的代码,做更多的事呢?

用 CSS3 造一场星际穿越:前端导演的《星球大战》片场手记

2025年10月28日 15:56

前端工程师从来都不只是 "切图仔"。如果把网页比作一部电影,HTML 是剧本框架,JavaScript 是剧情逻辑,那 CSS 就是掌控光影、调度镜头的导演 —— 尤其是 CSS3 带来的 transform、animation 等特性,让我们能用代码拍出《星球大战》级别的视觉盛宴。

一、先搭个星际片场:HTML 的语义化布景

拍电影得先搭布景,写 CSS 动画的第一步是搭好 HTML 结构。星球大战最经典的开场是 "星空 + 滚动字幕",我们用语义化标签搭建这个场景:

html

预览

<!-- 整个场景容器 -->
<section class="star-wars">
  <!-- 星空背景 -->
  <div class="stars"></div>
  <!-- 电影标题 -->
  <h2 class="title">STAR WARS</h2>
  <!-- 滚动字幕 -->
  <div class="crawl">
    <p>很久很久以前,在一个遥远的星系...</p>
    <p>反抗军同盟与邪恶的帝国展开了殊死搏斗...</p>
  </div>
</section>

这里的标签选择藏着 "导演思维":

  • section 作为场景容器,像电影里的摄影棚,界定了整个动画的范围;

  • h2 承载标题,符合 "电影标题" 的语义,比 div 更有叙事感;

  • 星星呢?可以用 13 个 span(材料里提到的 span*13)作为星点,用循环生成更高效:

    html

    预览

    <div class="stars">
      <!-- 用JS生成13颗星星,或直接写13个span -->
      <span></span><span></span>...<span></span>
    </div>
    

好的布景不需要冗余标签,每个元素都该像电影里的道具 —— 有明确的 "戏份"。

二、定位:给每个元素找对 "站位"

拍群像戏时,演员的站位决定画面层次感。CSS 的position就是给元素 "站位" 的核心工具,在星球大战场景里,每个元素的定位都有讲究:

1. 星空背景:fixed 定位让宇宙 "固定不动"

星空需要铺满整个屏幕,且不随滚动变化,position: fixed是最佳选择:

css

.stars {
  position: fixed; /* 相对于视口定位,不随页面滚动 */
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: #000;
}

fixed会让元素脱离文档流,像电影里的背景幕布,永远停在镜头里。

2. 星星:absolute 定位让星光 "散落在宇宙"

13 颗星星需要随机分布在星空上,position: absolute能让它们相对于最近的非 static 父元素(这里是.stars)定位:

css

.stars span {
  position: absolute; /* 脱离文档流,自由定位 */
  width: 2px;
  height: 2px;
  background: #fff;
  border-radius: 50%;
}

/* 给每颗星星设置不同位置(可通过nth-child实现) */
.stars span:nth-child(1) { top: 20%; left: 30%; }
.stars span:nth-child(2) { top: 50%; left: 70%; }
/* ... 其余星星 */

如果父元素没设置position: relative,absolute 会一直往上找,直到 body—— 就像演员找不到站位参考时,只能看舞台边缘。

3. 滚动字幕:relative 定位做 "运动参考点"

字幕需要从下往上滚动,给容器加position: relative,既能保持在文档流中,又能成为内部元素的定位参考:

css

.crawl {
  position: relative; /* 不脱离文档流,但可作为子元素的定位基准 */
  width: 80%;
  margin: 0 auto; /* 水平居中 */
}

relative的妙处在于 "占着坑位移动"—— 元素原来的位置会保留,就像演员在自己的站位范围内小幅度移动。

三、transform:给画面加 "镜头特效"

如果说 position 是站位,那 transform 就是镜头运动。星球大战的视觉冲击力,很多来自于透视和运动感,这些都能用 transform 实现。

1. 星星闪烁:scale+opacity 营造 "星光忽明忽暗"

真实的星星不会一直亮着,用scale()缩放和透明度变化模拟闪烁:

css

.stars span {
  animation: twinkle 3s infinite;
}

@keyframes twinkle {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(0.5); opacity: 0.5; } /* 缩小+变暗 */
  100% { transform: scale(1); opacity: 1; }
}

给不同星星设置不同动画延迟,就能避免 "集体闪烁" 的尴尬:

css

.stars span:nth-child(odd) { animation-delay: 1s; }

2. 标题透视:3D 变换复刻 "星球大战片头"

星球大战的标题会有仰角,像从远处飞来,这需要 3D 变换:

css

.title {
  /* 开启3D空间 */
  transform-style: preserve-3d;
  /* 透视效果:值越小,立体感越强 */
  perspective: 500px;
  /* 旋转+平移营造仰角 */
  transform: rotateX(30deg) translateZ(0);
}

rotateX(30deg)让标题沿水平轴向上仰,perspective模拟人眼视角 —— 就像摄影师调整镜头焦距,让远处的物体有 "近大远小" 的深度。

3. 字幕滚动:translate3D 实现 "星际穿梭感"

字幕从屏幕底部滚向远方,需要结合 Y 轴平移和 Z 轴深度:

css

.crawl p {
  animation: crawl 30s linear infinite;
}

@keyframes crawl {
  0% {
    transform: translate3d(0, 100vh, 0); /* 开始在屏幕下方 */
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  100% {
    transform: translate3d(0, -200vh, -500px); /* 向上+向远处移动 */
    opacity: 0;
  }
}

translate3d(x,y,z)里的 Z 轴负值让文字 "远去",配合 Y 轴上移,完美复刻电影里字幕驶向星海的效果。

四、animation:让星际场景 "动起来"

动画是电影的灵魂,CSS 的animation属性就是给场景 "注入灵魂" 的工具。它由两部分组成:@keyframes定义关键帧,animation属性控制播放参数。

1. 关键帧:定义 "剧情转折点"

@keyframes就像分镜脚本,规定动画在不同时间点的状态。比如星星的闪烁,我们定义了 0%(初始)、50%(中途)、100%(结束)三个关键帧;字幕滚动则需要更细腻的控制 —— 从隐藏到显示,再到消失。

2. 动画属性:控制 "播放节奏"

把关键帧应用到元素上时,需要设置播放规则:

css

/* 完整写法 */
.crawl p {
  animation-name: crawl; /* 关联关键帧 */
  animation-duration: 30s; /* 播放时长 */
  animation-timing-function: linear; /* 速度曲线:匀速 */
  animation-iteration-count: infinite; /* 无限循环 */
}

/* 简写 */
.crawl p {
  animation: crawl 30s linear infinite;
}

不同元素需要不同的 "演技":星星的闪烁用ease-in-out(缓进缓出)更自然,字幕滚动用linear(匀速)更符合 "星际穿梭" 的稳定感。

五、从代码到电影:前端导演的核心思维

用 CSS 实现星球大战效果,本质是用代码模拟现实世界的视觉规律:

  • 星星的闪烁遵循 "随机节奏"—— 通过不同动画延迟实现;
  • 字幕的滚动符合 "透视原理"—— 近快远慢,Z 轴深度改变大小;
  • 整个场景的层次依赖 "定位逻辑"——fixed 背景、absolute 星星、relative 容器,各司其职。

现在的 CSS 早已不是简单的 "美化工具":transform 能模拟镜头运动,animation 能控制时间节奏,position 能调度元素站位。前端工程师完全可以像导演一样,用代码在浏览器里 "拍电影"。

最后,给你的星际片场加个小彩蛋:用 CSS4 的backdrop-filter给星空加层朦胧感,让整个场景更有电影质感:

css

.stars {
  backdrop-filter: blur(1px);
}

结语:每个前端都是造梦师

当你用position规划元素站位,用transform设计镜头运动,用animation控制时间流转时,你就不是在写代码 —— 而是在创造一个世界。

《星球大战》的导演乔治・卢卡斯说:"电影是视觉的艺术。" 对前端工程师来说,CSS 就是我们的摄影棚、摄像机和剪辑台。下次再写 CSS 时,不妨把自己当成导演 —— 毕竟,能用代码让文字飞向星海的人,都在创造属于自己的传奇。

❌
❌