Stylus 自定义函数 #

函数基础 #

函数与混入类似,但函数主要用于计算和返回值,而不是直接输出样式。

定义函数 #

stylus
// 定义函数
add(a, b)
  a + b

// 使用函数
.element
  width add(100px, 50px)  // 150px
  height add(50px, 50px)  // 100px

函数 vs 混入 #

stylus
// 混入:输出样式
border-radius(radius)
  -webkit-border-radius radius
  border-radius radius

.box
  border-radius(5px)  // 直接输出样式

// 函数:返回值
calculate-rem(px)
  (px / 16) * 1rem

body
  font-size calculate-rem(16)  // 返回 1rem

参数 #

基本参数 #

stylus
// 多参数函数
spacing(multiplier, base = 8px)
  base * multiplier

.element
  padding spacing(2)      // 16px
  margin spacing(3, 10px) // 30px

默认参数 #

stylus
// 默认参数
font-size(size = 16px)
  size

// 使用默认值
body
  font-size()  // 16px

h1
  font-size(32px)  // 32px

命名参数 #

stylus
// 命名参数
gradient(direction, start-color, end-color)
  linear-gradient(direction, start-color, end-color)

// 使用命名参数
.hero
  background gradient(start-color: #3498db, end-color: #2ecc71, direction: to right)

剩余参数 #

stylus
// 收集剩余参数
sum(numbers...)
  total = 0
  for n in numbers
    total = total + n
  total

.element
  width sum(10px, 20px, 30px)  // 60px

返回值 #

基本返回 #

stylus
// 返回计算值
double(value)
  value * 2

.element
  width double(50px)  // 100px

条件返回 #

stylus
// 根据条件返回不同值
text-color(bg-color)
  if lightness(bg-color) > 50%
    #333
  else
    #fff

.button
  background-color #3498db
  color text-color(#3498db)  // #fff

.card
  background-color #f5f5f5
  color text-color(#f5f5f5)  // #333

多值返回 #

stylus
// 返回列表
sizes(base)
  (base base * 1.25 base * 1.5)

.element
  font-size sizes(16px)[0]   // 16px
  line-height sizes(16px)[1] // 20px

// 返回对象
theme-colors()
  (primary: #3498db, secondary: #2ecc71, danger: #e74c3c)

colors = theme-colors()
.button
  background-color colors.primary

实用函数示例 #

1. 单位转换 #

stylus
// px 转 rem
px-to-rem(px, base = 16)
  (px / base) * 1rem

// px 转 em
px-to-em(px, base = 16)
  (px / base) * 1em

// rem 转 px
rem-to-px(rem, base = 16)
  unit(rem * base, 'px')

// 使用
body
  font-size px-to-rem(16)  // 1rem

h1
  font-size px-to-rem(32)  // 2rem

.element
  padding px-to-em(16, 14)  // 1.1428em

2. 颜色函数 #

stylus
// 生成对比色
contrast-color(color)
  if lightness(color) > 50%
    darken(color, 80%)
  else
    lighten(color, 80%)

// 生成悬停色
hover-color(color, amount = 10%)
  if lightness(color) > 50%
    darken(color, amount)
  else
    lighten(color, amount)

// 生成活跃色
active-color(color, amount = 20%)
  if lightness(color) > 50%
    darken(color, amount)
  else
    lighten(color, amount)

// 使用
.button
  background-color #3498db
  
  &:hover
    background-color hover-color(#3498db)  // #2980b9
    
  &:active
    background-color active-color(#3498db)  // #1f6dad

3. 数学函数 #

stylus
// 百分比计算
percentage(value, total)
  (value / total) * 100%

// 网格宽度
grid-width(columns, total-columns = 12, gutter = 30px, container = 1200px)
  (container - (total-columns - 1) * gutter) / total-columns * columns + (columns - 1) * gutter

// 使用
.col-6
  width percentage(6, 12) + '%'  // 50%

.sidebar
  width grid-width(3)  // 277.5px

4. 字符串函数 #

stylus
// 拼接类名
class-name(prefix, name)
  '.' + prefix + '-' + name

// 生成选择器
bem-selector(block, element = null, modifier = null)
  selector = '.' + block
  if element
    selector = selector + '__' + element
  if modifier
    selector = selector + '--' + modifier
  selector

// 使用
{bem-selector('card', 'header')}
  padding 15px

{bem-selector('card', 'body')}
  padding 20px

{bem-selector('card', null, 'featured')}
  border-color #3498db

5. 列表函数 #

stylus
// 获取列表第一个元素
first(list)
  list[0]

// 获取列表最后一个元素
last(list)
  list[-1]

// 列表长度
list-length(list)
  length(list)

// 列表是否包含某值
contains(list, value)
  for item in list
    if item == value
      return true
  false

// 使用
colors = #3498db #2ecc71 #e74c3c

.primary
  color first(colors)  // #3498db

.danger
  color last(colors)   // #e74c3c

6. 对象函数 #

stylus
// 获取对象键
keys(obj)
  result = ()
  for key in obj
    push(result, key)
  result

// 获取对象值
values(obj)
  result = ()
  for key, value in obj
    push(result, value)
  result

// 深度合并对象
merge-objects(obj1, obj2)
  result = {}
  for key, value in obj1
    result[key] = value
  for key, value in obj2
    if typeof(value) == 'object' and typeof(result[key]) == 'object'
      result[key] = merge-objects(result[key], value)
    else
      result[key] = value
  result

// 使用
theme = {
  primary: #3498db,
  secondary: #2ecc71
}

theme-keys = keys(theme)  // (primary secondary)
theme-values = values(theme)  // (#3498db #2ecc71)

7. 响应式函数 #

stylus
// 断点检查
breakpoints = {
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
}

// 获取断点值
get-breakpoint(name)
  breakpoints[name]

// 计算响应式字体
responsive-font(min-size, max-size, min-width = 320px, max-width = 1200px)
  "calc(%s + %s * ((100vw - %s) / %s))" % (min-size (max-size - min-size) min-width (max-width - min-width))

// 使用
.container
  +media-up(get-breakpoint('md'))
    max-width 720px

.title
  font-size responsive-font(16px, 32px)

8. 验证函数 #

stylus
// 检查是否为有效颜色
is-valid-color(value)
  if typeof(value) == 'rgba' or typeof(value) == 'color'
    true
  else
    false

// 检查是否为正数
is-positive(value)
  value > 0

// 检查是否在范围内
in-range(value, min, max)
  value >= min and value <= max

// 使用
safe-color(color, fallback = #333)
  if is-valid-color(color)
    color
  else
    fallback

.element
  color safe-color(#3498db)  // #3498db
  background-color safe-color(invalid, #fff)  // #fff

高级函数技巧 #

递归函数 #

stylus
// 阶乘
factorial(n)
  if n <= 1
    1
  else
    n * factorial(n - 1)

// 斐波那契数列
fibonacci(n)
  if n <= 1
    n
  else
    fibonacci(n - 1) + fibonacci(n - 2)

// 使用
.element
  z-index factorial(5)  // 120

函数缓存 #

stylus
// 使用变量缓存计算结果
_cache = {}

cached-calculation(key, fn)
  if key in _cache
    _cache[key]
  else
    result = fn()
    _cache[key] = result
    result

函数组合 #

stylus
// 组合多个函数
compose(fn1, fn2)
  (x) => fn1(fn2(x))

// 使用
double(x) = x * 2
add-one(x) = x + 1

double-then-add = compose(add-one, double)

.element
  width double-then-add(10px)  // 21px

函数最佳实践 #

1. 单一职责 #

stylus
// 推荐:每个函数只做一件事
px-to-rem(px)
  (px / 16) * 1rem

px-to-em(px, base)
  (px / base) * 1em

// 不推荐:函数做太多事
convert-unit(value, unit, base = 16)
  // 太多逻辑...

2. 有意义的命名 #

stylus
// 推荐:描述性命名
calculate-grid-width(columns)
contrast-text-color(bg-color)

// 不推荐:无意义命名
calc1(c)
helper(x)

3. 提供默认值 #

stylus
// 推荐:常用参数有默认值
spacing(multiplier, base = 8px)
  base * multiplier

// 不推荐:无默认值
spacing(multiplier, base)
  base * multiplier

下一步 #

掌握自定义函数后,继续学习 条件语句 了解如何在样式中使用条件判断!

最后更新:2026-03-28