Easy micro-interactions in CSS (Pt2): Multi-state button

2025-06-07

CSS 中的简单微交互(第二部分):多状态按钮

先简单介绍一下,这是我的 CSS 微交互文章(或者说微教程)的第二部分。我知道我花了很长时间才终于写到第二部分,但生活真是太疯狂了!

最后一部分专门介绍所有响应式网站和网络应用程序的明星——汉堡图标

如果您对汉堡图标不是特别感兴趣,让我们来回顾一下微交互是什么(有点像诗歌,嗯,差不多):

微交互是一种克制的练习,用尽可能少的资源做尽可能多的事情。拥抱这些限制,专注于做好一件事。——丹·萨弗

你可能已经从标题猜到了,本部分将讨论按钮——任何网站或应用都离不开它。按钮也是UI中最古老的元素之一,多年来经历了许多视觉变革,从最初的简单方形和小阴影,到3D阶段、扁平化设计时代,再到现在的Material Design外观。现代框架也允许使用按钮作为状态传达器,这正是我们将要探讨的用例。

提醒一下,我正在使用 Slim 和 SCSS,但您始终可以从 codepen 示例中编译并获取 HTML 和 CSS!

多状态按钮

发送按钮交互

由于实现这样的按钮需要更多精力,而且其他用例在状态切换方面基本上都类似(例如,下载 -> 下载中 -> 完成,或者像 Netflix 那样跳过:禁用 -> 加载中 -> 跳过),所以我们只介绍一个例子。在本例中,我们主要关注消息或电子邮件的发送按钮。

首先,我们将三种可能状态的文本值添加到 DOM 中,然后调整它们的可见性和位置。大多数情况下,你还需要第四种状态来表示错误,但为了简化本例,我不会这样做。

那么让我们仔细看看我们需要做什么。

  1. 添加图标元素
  2. 添加 3 个文本值
  3. 为按钮背景颜色提供 3 种样式
  4. 根据状态显示单独的图标、切换文本值和背景

按钮的结构如下:

  button.button.button--default
    .button__icon-wrapper
      .button__icon
    .button__text-wrapper
      .button__text.button__text--default Send
      .button__text.button__text--process Cancel
      .button__text.button__text--success Sent!
Enter fullscreen mode Exit fullscreen mode

基本样式(您可以在这里查找颜色名称):

.button {
  font-size: 1.2em;
  text-align: left;
  padding: 0.8em 1.4em;
  border-radius: 2em;
  cursor: pointer;
  font-family: 'Montserrat', sans-serif;
  font-weight: 600;
  border: 0;
  color: WHITE;
  line-height: 1.6em;
  transition: background-color 300ms ease-in-out;
  &:focus {
    outline: 0;
  }
  &--default {
    background-color: CORNFLOWERBLUE;
  }
  &--process {
    background-color: MEDIUMSLATEBLUE; 
  }
  &--success {
    background-color: DARKTURQUOISE;   
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,让我们添加一个简单的脚本来在 onClick 事件中切换类。在实际应用中,你可能希望类的切换事件由其他事件触发,而且很可能以完全不同的方式触发,但目前我们只使用setTimeout()

const button = document.querySelector('.button');
button.addEventListener('click', function(){
  button.classList.remove('button--default');
  button.classList.add('button--process');
  setTimeout(function() {
    button.classList.remove('button--process');
    button.classList.add('button--success');
  }, 2000);
  setTimeout(function() {
    button.classList.remove('button--success');
    button.classList.add('button--default');
  }, 4500);
})

Enter fullscreen mode Exit fullscreen mode

此时,您应该有一个带有垂直堆叠文本的按钮,它将onClick开始改变颜色(和类别):

带有堆叠文本的按钮

现在是时候操作文本切换了,我们将为每个元素设置绝对定位.button__text__wrapper,并根据当前活动的类切换它们的不透明度和变换。
默认值是opacity: 0;、 和transform: translateY(20px);,这将为我们带来漂亮的从底部淡入淡出的动画效果(参见下一段)。

  &__text-wrapper {
    position: relative;
    display: inline-block;
    width: 120px;
    height: 1.6em;
    vertical-align: top;
  }

  &__text {
    position: absolute;
    opacity: 0;
    transform: translateY(20px);
    transition: all 250ms ease-in-out;
  }
Enter fullscreen mode Exit fullscreen mode

现在是时候根据 中的活动类应用转换了.button,我们需要将所需的文本转换为transform: translateY(0);并设置opacity: 1;,仅此一项就能提供足够漂亮的淡入效果。但如果之前的文本能够淡出,并赋予我们额外的维度感,那就更好了。我们将通过定位之前的类并将其淡出来实现这一点。您始终可以使用选择器或 JavaScripttransform: translateY(-20px);来定位这些类,但为了简单起见,我更喜欢使用类。nth

  &--default {
    background-color: CORNFLOWERBLUE;
    .button__text--default {
      opacity: 1;
      transform: translateY(0);
    }
    .button__text--success {
      transform: translateY(-20px);
    }
  }
  &--process {
    background-color: MEDIUMSLATEBLUE; 
    .button__text--process {
      opacity: 1;
      transform: translateY(0);
    }
    .button__text--default {
      transform: translateY(-20px);
    }
  }
  &--success {
    background-color: DARKTURQUOISE;   
    .button__text--success {
      opacity: 1;
      transform: translateY(0);
    }
    .button__text--process {
      transform: translateY(-20px);
    }
  }

Enter fullscreen mode Exit fullscreen mode

在这个阶段,你应该已经有一个良好的互动

图标前的按钮

为了完善我们超酷的发送按钮,我们来添加一个变形图标。我们将使用纯 CSS 的方式,但你也可以使用 SVG。

首先,我们将设计我们的.button__icon-wrapper和首字母.button__icon(嵌套在我们的.button

  &__icon-wrapper {
    width: 1.6em;
    height: 1.6em;
    margin-right: 1em;
    display: inline-block;
    vertical-align: top;
  }
  &__icon {
    transition: all 300ms ease-in-out;
    display: block;
    box-sizing: border-box;
  }

Enter fullscreen mode Exit fullscreen mode

基础准备好后,我们就开始为每个图标添加样式。首先是一个简单的插入符号,我们将它添加到&--default类中。我们只需创建一个正方形元素,添加顶部和右侧边框,然后旋转它即可。

   .button__icon {
      width: 1em;
      height: 1em;
      margin: 0.3em 0.5em 0.3em 0;
      border-right: 3px solid white;
      border-top: 3px solid white;
      transform: rotate(45deg);
    }

Enter fullscreen mode Exit fullscreen mode

对于&--process,事情会变得稍微棘手一些,因为我们需要创建一个简单的加载图标。我们将利用 来实现。您可以在这里clip-path阅读更多相关信息。然后,我们将使用关键帧为整个元素添加动画效果,使其旋转并营造出旋转的视觉效果。

    .button__icon {
      width: 1.2em;
      height: 1.2em;
      margin: 0.2em 0.5em 0.2em 0;
      border-radius: 100px;
      border: 3px solid white;
      animation: loading 1s infinite ease;
      clip-path: polygon(100% 0, 50% 50%, 100% 100%);
    }

Enter fullscreen mode Exit fullscreen mode

关键帧:

@keyframes loading {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,让我们创建成功图标,一个简单的勾选标记,类似于我们创建角度图标的方式。不过,我们再旋转一下,360deg让它更平滑地过渡回默认状态,并应用使用 的显示动画clip-path,本质上它会先显示底部边框,然后移动到 100% 的高度。
您可以使用clippyclip-path进行调整。一旦我们应用旋转,它就会沿着勾选标记线显示图标。 如果没有旋转,很难实现从之前的图标平滑过渡。

在里面&--success我们添加:

    .button__icon {
      margin: 0 0.3em 0.3em 0.1em;
      height: 1.2em;
      width: 0.9em;
      border-radius: 0;
      border-right: 3px solid white;
      border-bottom: 3px solid white;
      transform: rotate(405deg);
      animation: reveal 500ms ease-in;
    }
Enter fullscreen mode Exit fullscreen mode

关键帧(我们还将添加轻微的不透明度过渡):

@keyframes reveal {
  0% {
    opacity: 0;
    clip-path: polygon(0 85%, 0 85%, 0 100%, 0 100%);
  }
  40% {
    opacity: 0;
  }
  50% {
    opacity: 1;
    clip-path: polygon(0 85%, 100% 85%, 100% 100%, 0 100%);
  }
  100% {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  }
}
Enter fullscreen mode Exit fullscreen mode

我们的多状态按钮已经准备好了!

当然,在实际生产环境中使用它时,你应该确保类的切换和处理方式万无一失!你还想看看其他微交互吗?如果有,请告诉我,我的下一篇文章可能就是关于这个的!

文章来源:https://dev.to/saintasia/easy-micro-interactions-in-css-pt2-multi-state-button-1kpi
PREV
Build and Deploy a Rest API Using Serverless, Express, and Nodejs What is Aws Lambda? How to Monitor and Track your Lamda Invocations?
NEXT
一些按钮可以送货…… 字面意义上的按钮 送货卡车 #1 - Codepen 无人机送货进行中 - Codepen 送货卡车 #2 按钮 - Codepen 电子邮件注册表单按钮 - Codepen 引人注目的 CTA 按钮 - Codepen 让按钮发光 - Codepen 按钮到完整表单 - Codepen 有趣的卡通按钮,适合不太严肃的人 - Codepen