现代 CSS 选择器的简单应用

因为业务需求,使得需要手写一个日期范围选择组件,组件要求可以展示用户所选择范围。

原本是定义了几个枚举,使用 JS 进行判断,然后根据枚举来逐个给样式。

const RangeStatus = {
  NOT_IN: 0,
  IS_START: 1 << 0,
  IN_RANGE: 1 << 1,
  IS_END: 1 << 2,
  IS_SELF: 1 << 3
} as const

const InRange =
  RangeStatus.IN_RANGE |
  RangeStatus.IS_START |
  RangeStatus.IS_END |
  RangeStatus.IS_SELF

但是其实可以不用这么麻烦,改成一个布尔值 inRange 就行,然后只需要 JS 判断日期是否在选择范围内即可。

剩下的,可以交给 CSS 来完成。

已知需求如下:

  1. 范围内的日期格子需要高亮背景色。
  2. 选择范围的首尾格子需要带有半圆边。
  3. 如果范围首尾是同一天(即只选择了一天),则显示为完整的圆形。

我们为所有日期格子赋予 .item 类名,激活状态使用 .active 类名。

第一条需求的 CSS 样式如下:

.item {
    &.active {
        background: skyblue;
    }
}

第二条和第三条需求的 CSS 样式如下:

.item {
  &.active {
    background: skyblue;
  }

  /** 
  最后一个 active 项
  自身是 .active, 且没有后面的 .active 项
  */
  &.active:not(:has(~ .active)) {
    &,
    &:before {
      border-top-right-radius: 2rem;
      border-bottom-right-radius: 2rem;
    }
  }

  /** 
  
  第一个 active 项
  自身不是 .active, 且后一个元素是 .active 项
  */
  &:not(.active) + .active {
    &,
    &:before {
      border-top-left-radius: 2rem;
      border-bottom-left-radius: 2rem;
    }
  }
  
  &.active:not(:has(~ .active)),
  &:not(.active) + .active {
    color: white;

    &:after {
      content: '';
      position: absolute;
      width: 1.5rem;
      height: 1.5rem;
      background: blue;
      border-radius: 2rem;
      z-index: 0;
    }
  }
}

通过这种方式,我们就仅用一个布尔状态 inRange 控制逻辑,JS 只负责计算选中范围,而复杂的首尾识别,半圆端点,单日圆点等效果都交由 CSS 自动判断完成。


现代 CSS 选择器的简单应用
https://www.inksha.com/archives/xian-dai-css-xuan-ze-qi-de-jian-dan-ying-yong
作者
inksha
发布于
2025年10月27日
许可协议