CSS助手函数 #

一、css 函数基础 #

1.1 基本语法 #

jsx
import styled, { css } from 'styled-components';

const flexCenter = css`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const Container = styled.div`
  ${flexCenter}
  width: 100%;
  height: 100vh;
`;

1.2 为什么使用 css 函数 #

text
普通插值 vs css 函数

普通插值(不推荐):
const mixin = 'color: red; font-size: 16px;';
const Text = styled.p`
  ${mixin}
`;

css 函数(推荐):
const mixin = css`
  color: red;
  font-size: 16px;
`;
const Text = styled.p`
  ${mixin}
`;

优势:
├── 语法高亮支持
├── 样式自动前缀
├── 嵌套选择器支持
└── 更好的 IDE 支持

二、样式复用 #

2.1 基础混入 #

jsx
import styled, { css } from 'styled-components';

const truncate = css`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`;

const cardShadow = css`
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

const smoothTransition = css`
  transition: all 0.3s ease;
`;

const Title = styled.h1`
  ${truncate}
  ${smoothTransition}
  font-size: 24px;
  max-width: 300px;
`;

const Card = styled.div`
  ${cardShadow}
  ${smoothTransition}
  padding: 24px;
  background: white;
  border-radius: 12px;
  
  &:hover {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  }
`;

2.2 布局混入 #

jsx
const flexCenter = css`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const flexBetween = css`
  display: flex;
  align-items: center;
  justify-content: space-between;
`;

const flexColumn = css`
  display: flex;
  flex-direction: column;
`;

const absoluteCenter = css`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
`;

const fullScreen = css`
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
`;

const Container = styled.div`
  ${flexCenter}
  width: 100%;
  min-height: 100vh;
`;

const Header = styled.header`
  ${flexBetween}
  padding: 16px 24px;
  background: white;
`;

const Sidebar = styled.aside`
  ${flexColumn}
  width: 280px;
  height: 100vh;
`;

const Modal = styled.div`
  ${fullScreen}
  ${flexCenter}
  background: rgba(0, 0, 0, 0.5);
`;

2.3 排版混入 #

jsx
const headingBase = css`
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  line-height: 1.2;
  color: #1a1a2e;
`;

const bodyText = css`
  font-family: 'Inter', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: #333333;
`;

const codeBlock = css`
  font-family: 'Fira Code', monospace;
  font-size: 14px;
  background: #f5f5f5;
  padding: 2px 6px;
  border-radius: 4px;
`;

const H1 = styled.h1`
  ${headingBase}
  font-size: 48px;
`;

const H2 = styled.h2`
  ${headingBase}
  font-size: 36px;
`;

const Paragraph = styled.p`
  ${bodyText}
  margin-bottom: 16px;
`;

const Code = styled.code`
  ${codeBlock}
`;

三、参数化混入 #

3.1 函数式混入 #

jsx
const padding = (size) => css`
  padding: ${size};
`;

const margin = (size) => css`
  margin: ${size};
`;

const borderRadius = (size) => css`
  border-radius: ${size};
`;

const Box = styled.div`
  ${padding('24px')}
  ${margin('16px')}
  ${borderRadius('12px')}
  background: white;
`;

3.2 配置对象 #

jsx
const card = ({ shadow = 'md', radius = 'lg', padding = '24px' } = {}) => css`
  background: white;
  border-radius: ${radius};
  padding: ${padding};
  
  ${shadow === 'sm' && css`
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
  `}
  
  ${shadow === 'md' && css`
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  `}
  
  ${shadow === 'lg' && css`
    box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
  `}
`;

const Card = styled.div`
  ${card({ shadow: 'lg', radius: '16px' })}
`;

const SmallCard = styled.div`
  ${card({ shadow: 'sm', padding: '16px' })}
`;

3.3 响应式混入 #

jsx
const breakpoints = {
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
};

const media = {
  sm: (...args) => css`
    @media (min-width: ${breakpoints.sm}) {
      ${css(...args)}
    }
  `,
  md: (...args) => css`
    @media (min-width: ${breakpoints.md}) {
      ${css(...args)}
    }
  `,
  lg: (...args) => css`
    @media (min-width: ${breakpoints.lg}) {
      ${css(...args)}
    }
  `,
  xl: (...args) => css`
    @media (min-width: ${breakpoints.xl}) {
      ${css(...args)}
    }
  `,
};

const Container = styled.div`
  padding: 16px;
  
  ${media.md`
    padding: 24px;
  `}
  
  ${media.lg`
    padding: 32px;
    max-width: 1200px;
    margin: 0 auto;
  `}
`;

const Grid = styled.div`
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  
  ${media.sm`
    grid-template-columns: repeat(2, 1fr);
  `}
  
  ${media.md`
    grid-template-columns: repeat(3, 1fr);
  `}
  
  ${media.lg`
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
  `}
`;

四、条件样式 #

4.1 基于 Props 的条件 #

jsx
const buttonVariants = {
  primary: css`
    background: #667eea;
    color: white;
    border: none;
    
    &:hover {
      background: #5a6fd6;
    }
  `,
  
  secondary: css`
    background: transparent;
    color: #667eea;
    border: 2px solid #667eea;
    
    &:hover {
      background: #667eea;
      color: white;
    }
  `,
  
  danger: css`
    background: #ff4d4f;
    color: white;
    border: none;
    
    &:hover {
      background: #ff7875;
    }
  `,
};

const Button = styled.button`
  padding: 12px 24px;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.2s;
  
  ${props => buttonVariants[props.$variant] || buttonVariants.primary}
`;

4.2 复杂条件 #

jsx
const sizes = {
  small: css`
    padding: 8px 16px;
    font-size: 14px;
  `,
  medium: css`
    padding: 12px 24px;
    font-size: 16px;
  `,
  large: css`
    padding: 16px 32px;
    font-size: 18px;
  `,
};

const Button = styled.button`
  ${props => sizes[props.$size] || sizes.medium}
  ${props => buttonVariants[props.$variant] || buttonVariants.primary}
  
  ${props => props.$fullWidth && css`
    width: 100%;
  `}
  
  ${props => props.$disabled && css`
    opacity: 0.6;
    cursor: not-allowed;
    pointer-events: none;
  `}
  
  ${props => props.$loading && css`
    position: relative;
    color: transparent;
    
    &::after {
      content: '';
      position: absolute;
      width: 16px;
      height: 16px;
      border: 2px solid white;
      border-top-color: transparent;
      border-radius: 50%;
      animation: spin 0.8s linear infinite;
    }
  `}
`;

4.3 状态样式 #

jsx
const inputStates = {
  error: css`
    border-color: #ff4d4f;
    
    &:focus {
      border-color: #ff4d4f;
      box-shadow: 0 0 0 3px rgba(255, 77, 79, 0.2);
    }
  `,
  
  success: css`
    border-color: #22c55e;
    
    &:focus {
      border-color: #22c55e;
      box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.2);
    }
  `,
  
  warning: css`
    border-color: #f59e0b;
    
    &:focus {
      border-color: #f59e0b;
      box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
    }
  `,
};

const Input = styled.input`
  padding: 12px 16px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 16px;
  
  &:focus {
    border-color: #667eea;
    outline: none;
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
  }
  
  ${props => props.$state && inputStates[props.$state]}
  
  ${props => props.$disabled && css`
    background: #f5f5f5;
    cursor: not-allowed;
  `}
`;

五、样式组合 #

5.1 组合多个混入 #

jsx
const baseButton = css`
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
`;

const rounded = css`
  border-radius: 9999px;
`;

const elevated = css`
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  
  &:hover {
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
  }
`;

const outlined = css`
  background: transparent;
  border: 2px solid currentColor;
`;

const Button = styled.button`
  ${baseButton}
  ${props => props.$rounded && rounded}
  ${props => props.$elevated && elevated}
  ${props => props.$outlined && outlined}
  
  padding: 12px 24px;
  background: #667eea;
  color: white;
  border: none;
`;

function App() {
  return (
    <>
      <Button>Default</Button>
      <Button $rounded>Rounded</Button>
      <Button $elevated>Elevated</Button>
      <Button $outlined $rounded>Outlined Rounded</Button>
    </>
  );
}

5.2 样式集合 #

jsx
const mixins = {
  flex: {
    center: css`
      display: flex;
      align-items: center;
      justify-content: center;
    `,
    between: css`
      display: flex;
      align-items: center;
      justify-content: space-between;
    `,
    column: css`
      display: flex;
      flex-direction: column;
    `,
  },
  
  text: {
    truncate: css`
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    `,
    center: css`
      text-align: center;
    `,
  },
  
  effects: {
    smoothTransition: css`
      transition: all 0.3s ease;
    `,
    hoverLift: css`
      &:hover {
        transform: translateY(-4px);
      }
    `,
  },
};

const Card = styled.div`
  ${mixins.flex.column}
  ${mixins.effects.smoothTransition}
  ${mixins.effects.hoverLift}
  padding: 24px;
  background: white;
  border-radius: 12px;
`;

六、主题混入 #

6.1 访问主题 #

jsx
const themed = (property) => css`
  ${property}: ${props => props.theme[property]};
`;

const ThemedButton = styled.button`
  ${themed('background')}
  ${themed('color')}
  padding: 12px 24px;
`;

6.2 颜色混入 #

jsx
const color = (colorName, shade = 'main') => css`
  color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;

const backgroundColor = (colorName, shade = 'main') => css`
  background-color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;

const borderColor = (colorName, shade = 'main') => css`
  border-color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;

const Button = styled.button`
  ${backgroundColor('primary')}
  ${color('neutral', 'white')}
  padding: 12px 24px;
  border-radius: 8px;
  
  &:hover {
    ${backgroundColor('primary', 'dark')}
  }
`;

6.3 间距混入 #

jsx
const spacing = (size) => css`
  ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;

const padding = (size) => css`
  padding: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;

const margin = (size) => css`
  margin: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;

const gap = (size) => css`
  gap: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;

const Card = styled.div`
  ${padding(6)}
  ${margin(4)}
  ${gap(3)}
  background: white;
  border-radius: 12px;
`;

七、高级模式 #

7.1 链式混入 #

jsx
const styledMixin = (styles) => {
  const chain = {
    styles: css`${styles}`,
    and: (moreStyles) => styledMixin(css`${chain.styles}${moreStyles}`),
  };
  return chain;
};

const base = styledMixin`
  padding: 12px;
  border-radius: 8px;
`;

const withShadow = base.and`
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

const withHover = withShadow.and`
  &:hover {
    transform: translateY(-2px);
  }
`;

const Card = styled.div`
  ${withHover.styles}
  background: white;
`;

7.2 工厂函数 #

jsx
const createVariant = (variants) => (props) => {
  const variant = variants[props.$variant] || variants.default;
  return css`${variant}`;
};

const buttonVariant = createVariant({
  default: css`
    background: #667eea;
    color: white;
  `,
  secondary: css`
    background: transparent;
    color: #667eea;
    border: 2px solid #667eea;
  `,
  danger: css`
    background: #ff4d4f;
    color: white;
  `,
});

const Button = styled.button`
  ${buttonVariant}
  padding: 12px 24px;
  border-radius: 8px;
`;

7.3 样式构建器 #

jsx
const StyleBuilder = {
  styles: [],
  
  add(cssInput) {
    this.styles.push(cssInput);
    return this;
  },
  
  padding(value) {
    this.styles.push(css`padding: ${value};`);
    return this;
  },
  
  margin(value) {
    this.styles.push(css`margin: ${value};`);
    return this;
  },
  
  background(value) {
    this.styles.push(css`background: ${value};`);
    return this;
  },
  
  borderRadius(value) {
    this.styles.push(css`border-radius: ${value};`);
    return this;
  },
  
  build() {
    return css`${this.styles}`;
  },
};

const cardStyles = StyleBuilder
  .padding('24px')
  .background('white')
  .borderRadius('12px')
  .add(css`box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);`)
  .build();

const Card = styled.div`
  ${cardStyles}
`;

八、性能考虑 #

8.1 避免内联创建 #

jsx
const BadComponent = styled.div`
  ${css`
    padding: 16px;
  `}
`;

const paddingMixin = css`
  padding: 16px;
`;

const GoodComponent = styled.div`
  ${paddingMixin}
`;

8.2 缓存复杂计算 #

jsx
import { useMemo } from 'react';

const useDynamicStyles = (variant) => {
  return useMemo(() => css`
    ${variants[variant]}
  `, [variant]);
};

const DynamicComponent = styled.div`
  ${props => props.$dynamicStyles}
`;

function App() {
  const dynamicStyles = useDynamicStyles('primary');
  return <DynamicComponent $dynamicStyles={dynamicStyles} />;
}

九、总结 #

css 函数使用技巧速查表:

用法 示例
基础混入 const mixin = css\color: red;``
参数化 const pad = (s) => css\padding: ${s};``
条件样式 ${props => props.active && activeStyle}
组合 ${mixin1}${mixin2}
主题访问 ${props => props.theme.colors.primary}

下一步:学习 样式对象 掌握对象样式定义方式。

最后更新:2026-03-28