Record--순수 CSS는 단순하면서도 우아한 단계 표시줄을 구현합니다.

여기에서 내가 인터넷에서 요약한 지식 중 일부를 여러분과 공유할 것입니다. 모든 사람에게 도움이 되기를 바랍니다.

단계 표시줄은 사용자가 특정 프로세스에 따라 작업을 완료하도록 안내하는 탐색 표시줄이며 다양한 단계별 양식 상호 작용 시나리오에서 널리 사용됩니다. 몇 가지 주요 프런트 엔드 UI 프레임워크에서 단계 표시줄 구성 요소의 모양을 살펴보겠습니다.

스텝 바는 일반적으로 숫자, 이름, 안내선의 세 가지 기본 요소로 구성되어 있음을 알 수 있습니다. 이 기사에서 달성하려는 것은 위의 세 가지 기본 요소를 포함하는 간단한 단계 표시줄입니다.다음은 최종 렌더링입니다.

5_72dc53815f27dbf472423a1e97bfc238_940x96.gif@900-0-90-f.gif

구현 프로세스는 다음에 자세히 설명합니다.

구조 결정

단계 표시줄의 표시 순서의 목록 구조는 HTML 태그 선택에서 ul또는 ol의미를 보다 명확하게 할 수 있습니다. 여기서는 ol태그를 . HTML 코드는 다음과 같습니다.

<ol class="steps">
  <li>注册</li>
  <li>域认证</li>
  <li>身份校验</li>
  <li>风险等级评估</li>
  <li>开通账号</li>
</ol>

단계 항목을 가로로 정렬해야 하므로 CSS에서는 flex 레이아웃을 사용하며 코드는 다음과 같습니다.

.steps {
  display: flex;
  justify-content: space-between;  /* 按水平均匀分布,行首行尾两端靠齐 */
  margin: 0;
}

이제 "단계 표시줄"에 몇 가지 초기 의미가 있으므로 세부 사항으로 이동하겠습니다.

단계 번호 생성

단계 번호는 CSS의 기본 기능을 사용하여 자동으로 생성할 수 있습니다.이전 단계에서 ol레이블에 의해 생성된 번호는 보기 좋지 않습니다.여기서 우리는 ::before의사 원으로 표시된 숫자의 스타일을 실현합니다. 단계를 더 명확하게 보이게하십시오.

관심 있는 파트너는 "정렬된 목록을 달성하기 위한 CSS의 번호 매기기 방법에 대해 얼마나 알고 있습니까?" 문서 로 이동하여 관련 지식 포인트를 볼 수 있습니다.

.steps {
  display: flex;
  justify-content: space-between;
  padding: 0;
  margin: 0;
  counter-reset: order;  /* 定义CSS计数器 */
  list-style: none;
}
.steps > li {counter-increment: order;}
.steps > li::before {
  content: counter(order);  /* 编号 */
  display: inline-block;
  width: 1.4em;
  line-height: 1.4em;
  margin-right: .5em;
  vertical-align: middle;
  text-align: center;
  border-radius: 50%;
  border: 1px solid;
}

실현 효과는 아래 그림과 같습니다.

가이드 라인 구현

이제 단계 번호와 이름이 있으므로 단계 안내선을 구현해야 합니다.

가이드 라인은 각 단계 항목을 전체적으로 연결하여 프로세스를 시각적으로 방향성 있게 만드는데, 장식적인 요소이므로 HTML에서는 나타나지 않아야 합니다. 이전 단계 ::before는 이미 단계 번호로 사용되었으므로 ::after지침을 구현하기 위해 사용하기로 선택했습니다.

.steps > li::after {
  content: '';
  display: inline-block;
  width: 60px;
  vertical-align: middle;  /* 让引导线和文本垂直居中 */
  border-bottom: 1px solid #ccc;
}
결과는 아래와 같습니다.

 마지막 단계 항목에는 선행 줄이 필요하지 않으므로  :not 대신 의사 클래스 선택기로 필터링합니다.

.steps > li:not(:last-child)::after {
  ...
}
现在我们面临一个难题:怎样确定引导线的宽度呢?使用固定宽度显然行不通,因为这会有很大的局限性。理想的解决方案是引导线宽度能够自动适应,占据除编号和名称文本以外的剩余空间。这种宽度自适应的场景,我们会很自然想到用 flex 布局来解决:只需将每个步骤项 li 标签的布局属性改为 inline-flex 盒子即可。
.steps > li {
  flex: auto;  /* 弹性宽度(根据其内容来调整) */
  display: inline-flex;  /* 内联块级弹性伸缩盒子 */
  align-items: center;
  counter-increment: order;
}
​
.steps > li:not(:last-child)::after {
  content: '';
  flex: 1;  /* 占满 li 中的剩余宽度 */
  margin: 0 1em;
  border-bottom: 1px solid #ccc;
}

现在的布局效果已经非常接近目标了:

 如果我们看得仔细一些,就会发现在最后一个步骤项的右边出现了一段空白,实际中我们希望它能够和右边对齐。

这个空白的产生和步骤项 li 标签的 flex: auto 这个 CSS 属性有关,该属性会根据当前容器的可用宽度来分配父容器宽度,当分配后还有剩余宽度时,前几个步骤项会有 CSS 属性为 flex: 1 的引导线来填补剩余宽度,但最后一个步骤项没有引导线,因此会出现空白。在了解根因后,我们只需要调整最后一个步骤项即可解决这个问题:
.steps > li:last-child {
  flex: none;
}

同时我们也意识到,当步骤项容器宽度不够时,作为 flex 子元素的圆形编号可能会被挤压变形:

 解决方案也很简单,禁止 flex 子元素收缩:

.steps > li::before {
  ...
  flex-shrink: 0;  /* 布局宽度不够时禁止收缩 */
}

步骤条状态

在调教好布局结构之后,我们来为步骤条增加状态。通常情况下,步骤条状态包括“已完成”、“进行中”和“未开始”三种,对应的装饰样式如下表所示:

状态 步骤编号 步骤名称 步骤引导线
已完成 无背景色,边框和文本高亮色 文本高亮色 高亮色
进行中 背景和边框高亮色,文本反色 文本高亮色 普通色
未开始 无背景色,边框和文本普通色 文本普通色 普通色

对此我们定义普通色和高亮色这2个颜色变量,以方便代码维护和扩展。

.steps {
  --normal-color: #666;  /* 普通色 */
  --active-color: #06e;  /* 高亮色 */
​
  ...
}

然后将所有步骤项默认以普通色呈现:

.steps > li {
  ...
  color: var(--normal-color);
}

引导线的颜色则默认自动继承字体颜色,同时为了避免引导线喧宾夺主,我们给它加了个透明度控制下颜色深度:

.steps > li:not(:last-child)::after {
  ...
  border-bottom: 1px solid;  /* 不指定颜色,则自动继承自身color或父级color */
  opacity: .6;
}

接下来是“已完成”和“进行中”的样式定义,需要注意“进行中”后面的引导线不能高亮。

.steps > .done,
.steps > .active {
  color: var(--active-color);
}
.steps > .active::before {
  color: #fff;
  background: var(--active-color);
  border-color: var(--active-color);
}
.steps > .active::after {
  color: var(--normal-color);  /* “进行中”后面的引导线按普通色显示 */
}

然后在 HTML 中调用对应的样式钩子:

<ol class="steps">
  <li class="done">注册</li>
  <li class="done">域认证</li>
  <li class="done">身份校验</li>
  <li class="active">风险等级评估</li>
  <li>开通账号</li>
</ol>

实现效果如下图所示:

最终方案

就显示效果而言,现在可以收工了,但对于将优雅奉为圭臬的程序猿来说,这个步骤条还差点意思——用 done 和 active 样式钩子来分别标记“已完成”和“进行中”的状态——这并不优雅。

<ol class="steps">
  <li class="done">注册</li>  <!-- 已完成 -->
  <li class="done">域认证</li>  <!-- 已完成 -->
  <li class="done">身份校验</li>  <!-- 已完成 -->
  <li class="active">风险等级评估</li>  <!-- 进行中 -->
  <li>开通账号</li>
</ol>
如果回想一下我们在前端 UI 框架中使用的步骤条,就会发现它只要关心当前进展到了哪一步,而“已完成”和“未完成”都是被组件内部自行处理的。那么,对于我们现在所做的步骤条,是否可以仅标记“进行中”,也就是只使用 active 样式钩子就可以了呢?就像下面这样:
<ol class="steps">
  <li>注册</li>
  <li>域认证</li>
  <li>身份校验</li>
  <li class="active">风险等级评估</li>  <!-- 进行中 -->
  <li>开通账号</li>
</ol>

对于这样的 HTML 结构,active 这个钩子可继续沿用之前的 CSS 代码,实现当前步骤项的高亮效果,然后可以根据 active 这个类名匹配它前面的兄弟步骤项,实现与 done 这个类一样的效果。不过我们很快就会被现实打脸:CSS 中根本没有“前兄弟选择器”这种东西,因此无法根据 active 向前匹配。

于是我们需要调整思路,逆向思考:既然无法匹配 active 前面的元素,那为什么不匹配其后面的元素呢?毕竟 CSS 中是有兄弟选择器的呀,至于 active 前面的元素,或许我们可以通过其父级来控制样式?

现在思路清晰了许多。我们先把所有步骤项都默认设置为“已完成”状态的高亮样式:

.steps > li {
  ...
  color: var(--active-color);  /* 改为“已完成”,之前的值是 var(--normal-color) */
}
此时步骤条变成了这样:

 然后加上 active 的样式,假设当前是第4步,则效果如下:

다음 단계는  active  다음 단계 항목을 형제 선택기로 쉽게 수행할 수 있는 "시작되지 않은" 스타일로 변경하는 것입니다.
.steps > .active ~ li {
  color: var(--normal-color);
}

마지막으로 전반적인 효과를 테스트해 보겠습니다.

16_685afd9fd12b2449feba44a68e955dcc_943x324.gif@900-0-90-f.gif

최종 완성된 CSS 코드는 다음과 같습니다.

.steps {
  --normal-color: #666;
  --active-color: #06e;
​
  display: flex;
  justify-content: space-between;
  padding: 0;
  margin: 0;
  counter-reset: order;
}
​
/* 步骤项 */
.steps > li {
  flex: auto;
  display: inline-flex;
  align-items: center;
  counter-increment: order;
  color: var(--active-color);
}
.steps > li:last-child {flex: none;}
​
/* 步骤编号(带圈数字) */
.steps > li::before {
  content: counter(order);
  flex-shrink: 0;
  width: 1.4em;
  line-height: 1.4em;
  margin-right: .5em;
  text-align: center;
  border-radius: 50%;
  border: 1px solid;
}
​
/* 步骤项引导线 */
.steps > li:not(:last-child)::after {
  content: '';
  flex: 1;
  margin: 0 1em;
  border-bottom: 1px solid;
  opacity: .6;
}
​
/* 步骤状态 */
.steps > .active {color: var(--active-color);}
.steps > .active::before {
  color: #fff;
  background: var(--active-color);
  border-color: var(--active-color);
}
.steps > .active::after,
.steps > .active ~ li {color: var(--normal-color);}

전체 코드의 데모는 이 기사의 첨부 파일에 제공되며 관심 있는 파트너는 당사에 연락하여 기존 기반에서 사용자 지정 및 확장할 수 있는 코드를 얻을 수 있습니다. 일회용품은 다음과 같습니다.

지식 포인트 요약

  • 플렉스 컨테이너는 디스플레이 방향에 따라 자식 요소를 고르게 분산 justify-content: space-between;시킬 수 있으며 두 끝이 흩어져 정렬되어 집으로 여행하는 데 꼭 필요한 인공물입니다.
  • inline-flex상자는 플렉스 컨테이너와 같은 하위 요소의 레이아웃을 쉽게 처리할 수 있을 뿐만 아니라 인라인 블록 요소만큼 접근하기 쉽습니다.
  • CSS 카운터 세척, 절단 및 불기 원스톱: counter-reset, counter-increment, counter(xxx);
  • flex: <number>너비(또는 높이)가 차지할 수 있는 한, 내 것이 되어야 할 것이 내 것이고, 조금이라도 남으면 나는 잃을 것이다.
  • flex: auto자신의 실제 상황에서 시작하여 모든 것을 가져 가야합니다. 모두 함께 번영하는 것이 좋지 않습니까?
  • flex-shrinkflex-basis플렉스 요소의 압축 가능한 기반을 설정하는 데 사용되며 확장 가능한 기반을 설정하는 데 사용되는 대응 요소입니다 .
  • IE는 죽었고, CSS 변수는 자유롭게 사용하세요.
  • 강력한 CSS 의사 클래스 선택기는 코드를 보다 간소화할 수 있으며 펀치 조합을 재생할 수도 있습니다. li:not(:last-child)::after;
  • 결정적인 순간에 플레이하고 저항할 수 있는 눈에 띄지 않는 형제 선택자: .active ~ li.

이 기사는 다음에서 재생산됩니다.

https://juejin.cn/post/7226910005144043580

도움이 되셨다면 많은 관심 부탁드립니다.기술 문서를 정기적으로 업데이트하고 함께 논의하고 배우며 함께 발전해 나가겠습니다.

 

추천

출처blog.csdn.net/qq_40716795/article/details/131099522