样式继承 #

一、样式继承基础 #

1.1 继承 HTML 元素 #

使用 styled(HTMLElement) 创建基础样式:

jsx
import styled from 'styled-components';

const Button = styled.button`
  padding: 12px 24px;
  font-size: 16px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s;
`;

const PrimaryButton = styled(Button)`
  background: #667eea;
  color: white;
  border: none;

  &:hover {
    background: #5a6fd6;
  }
`;

const SecondaryButton = styled(Button)`
  background: transparent;
  color: #667eea;
  border: 2px solid #667eea;

  &:hover {
    background: #667eea;
    color: white;
  }
`;

1.2 继承流程 #

text
样式继承链
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  styled.button                                              │
│       │                                                     │
│       ▼                                                     │
│  ┌─────────────────────────────────────┐                   │
│  │  padding: 12px 24px                 │                   │
│  │  font-size: 16px                    │                   │
│  │  border-radius: 8px                 │                   │
│  └─────────────────────────────────────┘                   │
│       │                                                     │
│       ▼  styled(Button)                                     │
│  ┌─────────────────────────────────────┐                   │
│  │  继承基础样式                        │                   │
│  │  + background: #667eea              │                   │
│  │  + color: white                     │                   │
│  │  + border: none                     │                   │
│  └─────────────────────────────────────┘                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、继承 React 组件 #

2.1 继承第三方组件 #

jsx
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { Button as MuiButton } from '@mui/material';

const StyledLink = styled(Link)`
  text-decoration: none;
  color: #667eea;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 4px;
  transition: background 0.2s;

  &:hover {
    background: rgba(102, 126, 234, 0.1);
  }
`;

const CustomButton = styled(MuiButton)`
  text-transform: none;
  font-weight: 600;
  border-radius: 8px;
`;

2.2 继承自定义组件 #

jsx
import styled from 'styled-components';

const BaseCard = styled.div`
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  padding: 24px;
`;

const ProductCard = styled(BaseCard)`
  display: flex;
  flex-direction: column;
  gap: 16px;

  img {
    width: 100%;
    height: 200px;
    object-fit: cover;
    border-radius: 8px;
  }
`;

const UserCard = styled(BaseCard)`
  display: flex;
  align-items: center;
  gap: 16px;

  img {
    width: 64px;
    height: 64px;
    border-radius: 50%;
  }
`;

2.3 继承条件 #

被继承的组件必须接受 className prop:

jsx
import styled from 'styled-components';

function CustomComponent({ className, children }) {
  return (
    <div className={className}>
      {children}
    </div>
  );
}

const StyledCustom = styled(CustomComponent)`
  padding: 24px;
  background: #f5f5f5;
`;

三、样式覆盖 #

3.1 覆盖继承的样式 #

jsx
const Button = styled.button`
  padding: 12px 24px;
  background: #667eea;
  color: white;
  border-radius: 8px;
`;

const RoundedButton = styled(Button)`
  border-radius: 50px;
  padding: 16px 32px;
`;

const OutlineButton = styled(Button)`
  background: transparent;
  color: #667eea;
  border: 2px solid #667eea;

  &:hover {
    background: #667eea;
    color: white;
  }
`;

3.2 使用 !important(谨慎使用) #

jsx
const ImportantButton = styled(Button)`
  background: #ff4d4f !important;
  color: white !important;
`;

3.3 增强样式优先级 #

jsx
const Button = styled.button`
  padding: 12px 24px;
  background: #667eea;
  color: white;
`;

const EnhancedButton = styled(Button)`
  && {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  }
`;

四、样式扩展 #

4.1 添加新样式 #

jsx
const Card = styled.div`
  background: white;
  border-radius: 12px;
  padding: 24px;
`;

const InteractiveCard = styled(Card)`
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;

  &:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  }
`;

const AnimatedCard = styled(InteractiveCard)`
  animation: fadeIn 0.3s ease;

  @keyframes fadeIn {
    from {
      opacity: 0;
      transform: translateY(20px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
`;

4.2 条件扩展 #

jsx
const Button = styled.button`
  padding: 12px 24px;
  border-radius: 8px;
  font-size: 16px;
`;

const VariantButton = styled(Button)`
  ${props => props.variant === 'primary' && `
    background: #667eea;
    color: white;
    border: none;
  `}

  ${props => props.variant === 'secondary' && `
    background: transparent;
    color: #667eea;
    border: 2px solid #667eea;
  `}

  ${props => props.variant === 'danger' && `
    background: #ff4d4f;
    color: white;
    border: none;
  `}
`;

4.3 组合扩展 #

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

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

const baseBorder = css`
  border: 1px solid #e0e0e0;
  border-radius: 8px;
`;

const baseShadow = css`
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;

const Card = styled.div`
  ${basePadding}
  ${baseBorder}
  ${baseShadow}
  background: white;
`;

const ElevatedCard = styled(Card)`
  ${baseShadow}
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  transform: translateY(-4px);
`;

五、多级继承 #

5.1 继承链 #

jsx
const Element = styled.button`
  font-family: inherit;
  font-size: 16px;
`;

const Button = styled(Element)`
  padding: 12px 24px;
  border-radius: 8px;
  cursor: pointer;
  border: none;
`;

const PrimaryButton = styled(Button)`
  background: #667eea;
  color: white;

  &:hover {
    background: #5a6fd6;
  }
`;

const LargePrimaryButton = styled(PrimaryButton)`
  padding: 16px 32px;
  font-size: 18px;
`;

5.2 继承深度控制 #

jsx
const Base = styled.div`
  padding: 16px;
`;

const Level1 = styled(Base)`
  background: #f0f0f0;
`;

const Level2 = styled(Level1)`
  border-radius: 8px;
`;

const Level3 = styled(Level2)`
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

const Level4 = styled(Level3)`
  border: 1px solid #e0e0e0;
`;

六、混合继承 #

6.1 使用 css 函数 #

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

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

const cardBase = css`
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

const Card = styled.div`
  ${cardBase}
  padding: 24px;
`;

const FlexCard = styled.div`
  ${cardBase}
  ${flexCenter}
  min-height: 200px;
`;

6.2 条件混合 #

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

const elevated = css`
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  transform: translateY(-4px);
`;

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

const bordered = css`
  border: 2px solid #667eea;
`;

const Card = styled.div`
  padding: 24px;
  background: white;
  border-radius: 8px;
  
  ${props => props.elevated && elevated}
  ${props => props.rounded && rounded}
  ${props => props.bordered && bordered}
`;

function App() {
  return (
    <>
      <Card elevated rounded>Elevated & Rounded</Card>
      <Card bordered>Bordered</Card>
      <Card elevated rounded bordered>All styles</Card>
    </>
  );
}

6.3 样式组合函数 #

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

const withPadding = (size = 'md') => css`
  padding: ${size === 'sm' ? '8px' : size === 'lg' ? '24px' : '16px'};
`;

const withMargin = (size = 'md') => css`
  margin: ${size === 'sm' ? '4px' : size === 'lg' ? '16px' : '8px'};
`;

const withShadow = (level = 'low') => css`
  box-shadow: ${level === 'high' 
    ? '0 8px 24px rgba(0, 0, 0, 0.15)' 
    : '0 2px 8px rgba(0, 0, 0, 0.1)'};
`;

const Box = styled.div`
  ${props => withPadding(props.p)}
  ${props => withMargin(props.m)}
  ${props => withShadow(props.shadow)}
  background: white;
  border-radius: 8px;
`;

function App() {
  return (
    <>
      <Box p="lg" m="md" shadow="high">Large padding, medium margin, high shadow</Box>
      <Box p="sm" m="lg" shadow="low">Small padding, large margin, low shadow</Box>
    </>
  );
}

七、Props 继承 #

7.1 继承 Props 类型 #

tsx
import styled from 'styled-components';

interface ButtonProps {
  $primary?: boolean;
  $size?: 'small' | 'medium' | 'large';
}

const Button = styled.button<ButtonProps>`
  padding: ${props => 
    props.$size === 'small' ? '8px 16px' :
    props.$size === 'large' ? '16px 32px' :
    '12px 24px'
  };
  background: ${props => props.$primary ? '#667eea' : '#fff'};
  color: ${props => props.$primary ? '#fff' : '#667eea'};
`;

const PrimaryButton = styled(Button)`
  border: none;
  font-weight: 600;
`;

const LargePrimaryButton = styled(PrimaryButton)`
  font-size: 18px;
`;

7.2 扩展 Props #

tsx
import styled from 'styled-components';

interface BaseCardProps {
  $elevated?: boolean;
}

interface ProductCardProps extends BaseCardProps {
  $inStock?: boolean;
}

const BaseCard = styled.div<BaseCardProps>`
  padding: 24px;
  background: white;
  border-radius: 12px;
  box-shadow: ${props => props.$elevated && '0 8px 24px rgba(0, 0, 0, 0.15)'};
`;

const ProductCard = styled(BaseCard)<ProductCardProps>`
  border: ${props => props.$inStock ? '2px solid #52c41a' : '2px solid #ff4d4f'};
`;

八、组件包装模式 #

8.1 包装器模式 #

jsx
import styled from 'styled-components';

const withCard = (Component) => styled(Component)`
  padding: 24px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

const Content = styled.div`
  color: #333;
`;

const CardContent = withCard(Content);

function App() {
  return (
    <CardContent>
      This content is wrapped in a card.
    </CardContent>
  );
}

8.2 高阶组件模式 #

jsx
import styled from 'styled-components';

function withStyledWrapper(styles) {
  return (Component) => styled(Component)`
    ${styles}
  `;
}

const Card = withStyledWrapper(`
  padding: 24px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`)(styled.div);

const Button = withStyledWrapper(`
  padding: 12px 24px;
  background: #667eea;
  color: white;
  border-radius: 8px;
`)(styled.button);

九、继承最佳实践 #

9.1 设计基础组件 #

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

const baseStyles = css`
  font-family: inherit;
  line-height: 1.5;
  transition: all 0.2s;
`;

const BaseButton = styled.button`
  ${baseStyles}
  padding: 12px 24px;
  border-radius: 8px;
  cursor: pointer;
  border: none;
  font-size: 16px;
`;

const BaseInput = styled.input`
  ${baseStyles}
  padding: 12px 16px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 16px;

  &:focus {
    border-color: #667eea;
    outline: none;
  }
`;

const BaseCard = styled.div`
  ${baseStyles}
  padding: 24px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;

9.2 创建变体组件 #

jsx
const Button = {
  Primary: styled(BaseButton)`
    background: #667eea;
    color: white;

    &:hover {
      background: #5a6fd6;
    }
  `,
  
  Secondary: styled(BaseButton)`
    background: transparent;
    color: #667eea;
    border: 2px solid #667eea;

    &:hover {
      background: #667eea;
      color: white;
    }
  `,
  
  Danger: styled(BaseButton)`
    background: #ff4d4f;
    color: white;

    &:hover {
      background: #ff7875;
    }
  `,
};

function App() {
  return (
    <>
      <Button.Primary>Primary</Button.Primary>
      <Button.Secondary>Secondary</Button.Secondary>
      <Button.Danger>Danger</Button.Danger>
    </>
  );
}

9.3 继承层次控制 #

jsx
const Base = styled.button`
  padding: 12px 24px;
  border-radius: 8px;
`;

const Variant = styled(Base)`
  background: #667eea;
  color: white;
`;

const Size = styled(Variant)`
  padding: 16px 32px;
  font-size: 18px;
`;

const State = styled(Size)`
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
`;

十、总结 #

样式继承技巧速查表:

技巧 示例
继承元素 styled(Button)\…``
继承组件 styled(CustomComponent)\…``
覆盖样式 直接重写属性
扩展样式 添加新属性
css 函数 const mixin = css\…``
条件混合 ${props => props.active && activeStyle}
transient props $ 前缀避免 DOM 传递

下一步:学习 属性传递 掌握 attrs 方法的高级用法。

最后更新:2026-03-28