我如何制作这个逼真的红色开关(纯 CSS)

2025-05-28

我如何制作这个逼真的红色开关(纯 CSS)

上周我在 Dribble 上偶然发现了这个3D 红色开关设计,于是就创作了这支笔。从那以后,它就火了起来(比我预想的要火得多!),还有几个人请我写一个教程来介绍它的制作方法。

我在制作过程中运用了多种 CSS 技术,包括渐变、3D 变换、动画和过渡。在本教程中,我将深入讲解其中的一些技术。

模拟一个国家

这大概是书中最古老的技巧了。开关有两种状态——开和关,但 CSS 无法维护这种状态。

为了解决这个问题,我们可以使用原生 HTML 元素。由于我们只需要维护两种状态,因此复选框元素是一个不错的选择。我们可以使用:checkedCSS 选择器,根据复选框是否选中来应用 CSS。

我们将整个内容包装在 a 中,<label/>以将整个元素的点击事件链接到复选框,然后使用 CSS 隐藏复选框本身。

<label class="switch">
  <input type="checkbox" checked/>
</label>
Enter fullscreen mode Exit fullscreen mode
.switch {
  input {
    display: none;
  }
}
Enter fullscreen mode Exit fullscreen mode

这样做的一个问题是,我们无法<label/>根据复选框的状态将 CSS 应用于其自身,因为 CSS 中没有“祖先选择器”。因此,我将所有 switch 元素放在复选框之后,并使用相邻的兄弟选择器 ( +) 将 CSS 应用于它们。

<label class="switch">
  <input type="checkbox" checked/>
  <div class="button"></div>
</label>
Enter fullscreen mode Exit fullscreen mode
.switch {
  input {
    display: none;

    &:checked + .button {
      // Apply some CSS to .button when the checkbox is checked
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

如果需要模拟具有两种以上状态的元素,可以使用其他 HTML 元素,例如单选按钮( <input type="radio"/>)。有些人将这项技术提升到一个新的高度,仅使用 CSS 创建了一个完整的游戏!在 CodePen 上查看这个纯 CSS 游戏合集,获取一些灵感。

制作黑色框架

使用 CSS box-shadow 制作黑色边框

我用它来box-shadow模拟按钮的框架。box-shadow是一个非常强大的 CSS 属性,因为它允许您堆叠以逗号分隔的多个阴影效果。

我使用了一组 5 种阴影效果来创建框架,并使用一个border-radius属性使阴影在角落处变圆。具体细节如下:

.switch {
  border-radius: 5px;
  box-shadow: 
    0 0 10px 2px rgba(black, 0.2), // The surrounding shadow (first layer)
    0 0 1px 2px black, // The surrounding shadow (second layer)
    inset 0 2px 2px -2px white, // The top white "shine"
    inset 0 0 2px 15px #47434c, // The light gray frame
    inset 0 0 2px 22px black; // The internal black shadow
}
Enter fullscreen mode Exit fullscreen mode

制作 3D 按钮形状

我使用 CSS 变换和过渡使按钮呈现三维效果。

按钮本身由 3 个 div(准确地说是 1 个 div 和 2 个伪元素)组成,它们彼此垂直,如下所示:

使用 CSS 制作 3D 红色开关

.button {
  &::before {
    height: 50px;
    width: 100%;
    transform: rotateX(-90deg);
  }
  &::after {
    height: 50px;
    width: 100%;
    transform: translateY(50px) rotateX(-90deg);
  }
}
Enter fullscreen mode Exit fullscreen mode

然后,我将整个按钮旋转 25 度,并将transform-origin枢轴点设置为远离 div,以使按钮看起来好像围绕按钮内部更深的某个点旋转,而不是围绕 div:

使用 CSS 制作 3D 红色开关

.switch {
  perspective: 700px;

  .button {
    $rotation: 25deg;
    $pivot-distance: 20px;
    transform-origin: center center -#{$pivot-distance};
     transform: translateZ($pivot-distance) rotateX(-$rotation);
    transform-style: preserve-3d;
  }
}
Enter fullscreen mode Exit fullscreen mode

制作动画

我使用 CSS 的 transitions 来来回回旋转开关。我希望过渡效果看起来更逼真,开始缓慢,结束迅速。我可以使用原生的缓动函数,比如ease-in,但这无法产生正确的动画效果,所以我改用了一个自定义的cubic-bezier()缓动函数:

transition: all 0.3s cubic-bezier(1, 0, 1, 1);
Enter fullscreen mode Exit fullscreen mode

Chrome DevTools 过渡三次贝塞尔曲线缓和

这条曲线意味着过渡开始缓慢,结束迅速,就像一个真正的开关,慢慢转动直到“咔哒”一声到达终点。

制作 I/O 字符

使用 CSS 渐变制作 I/O 字符

我本来可以用很多技巧来创建 I/O 字符。我可以使用真实的字母并为其添加样式,或者使用特殊的字体。但由于这些字符绘制起来相当简单,所以我决定使用渐变来制作它们。

CSS 渐变令人惊叹,但直到我偶然发现这篇关于CSS 绘图的精彩文章,我才知道它们有多么强大。

渐变的真正威力来自于 CSS 将它们视为“图像”,因此可以从该background属性的强大功能中受益。CSS 中的背景不仅可以堆叠(如阴影),还可以具有自定义位置和大小!

这意味着你几乎可以用 CSS 渐变来实现所有功能。如果你想了解它的潜力,请访问https://a.singlediv.com/(该网站上的每件艺术作品都由一个 div 组成)。

语法非常简单:

background: <image> <position> / <size>
Enter fullscreen mode Exit fullscreen mode

您可以使用逗号堆叠多个渐变,并添加background-repeat: no-repeat以防止渐变重复:

.image {
  background:
    <image> <position> / <size>,
    <image> <position> / <size>,
    <image> <position> / <size>;
  background-repeat: no-repeat;
}
Enter fullscreen mode Exit fullscreen mode

我使用带有两种渐变的背景来制作字符。
对于“I”字符,我使用了全白的背景linear-gradient(),并将其设计得又窄又长。对于“O”字符,我使用了radial-gradient()带有四个色标的背景,从透明到白色,再回到透明。

background:
  linear-gradient(white, white) 50% 20% / 5% 20%, // White vertical line ("I")
  radial-gradient(circle, transparent 50%, white 52%, white 70%, transparent 72%) 50% 80% / 33% 25%; // White circle ("O")
Enter fullscreen mode Exit fullscreen mode

如果你看一下,你会注意到每个颜色停止点之间radial-gradient()都有一个间隙:2%

radial-gradient(
  transparent 50%, 
  white 52%, 
  white 70%, 
  transparent 72%
)
Enter fullscreen mode Exit fullscreen mode

这使得不同的颜色混合在一起,而不是清晰的像素化过渡。为了说明这一点,请看下面的图片:

CSS 渐变 - 在颜色停止点之间混合颜色

这是 CSS 固有的渐变行为 - 当颜色停止之间存在间隙时,它会在颜色之间创建平滑的混合。

制作“LED”渐变

使用 CSS 渐变和动画制作 LED 灯

如上图所示,我堆叠了 2 个渐变,以实现 LED 灯泡隐藏在半透明红色塑料后面且上面有小圆形凸起的外观。

我必须使用两个元素,每个渐变一个,因为第一个渐变必须是不重复的,而第二个渐变必须是重复的。此外,我想让灯光“闪烁”,所以我必须将它们分开。

第一个元素是.light元素,其中我用了radial-gradient()来表示一个红色的LED灯,其中心比较亮(中心是橙色,而周围是红色)。

.light {
  background-image: radial-gradient(
    adjust-hue(lighten($color, 20%), 35), // Orange
    $color 40%, // Red
    transparent 70%
  );
}
Enter fullscreen mode Exit fullscreen mode

别被 和 吓到adjust-hue()lighten()我会在下一部分讲解。现在,先把它们当成十六进制颜色。

第二个元素是.dots元素,我使用具有透明中心的重复radial-gradient()来创建圆形凸起的矩阵。

.dots {
  background-image: 
    radial-gradient(transparent 30%, rgba(darken($color, 35%), 0.7) 70%);
    background-size: 10px 10px;
}
Enter fullscreen mode Exit fullscreen mode

最后,我使用动画来创建闪烁效果:

替代文本

.light {
  animation: flicker 0.2s infinite 0.3s;
}

@keyframes flicker {
  0% {opacity: 1}
  80% {opacity: 0.8}
  100% {opacity: 1}
}
Enter fullscreen mode Exit fullscreen mode

通过变量控制颜色

随着这支笔越来越受欢迎,有些人想看看它的不同颜色。最初,我在整个 CSS 中都硬编码了颜色,所以我将它们改为 SASS 变量,以便于配置。

但是,我希望主色易于配置,所以多个颜色变量不够好。我需要通过一个变量来控制所有颜色和阴影。

为了实现这一点,我使用了 SASS 的内置颜色函数:lighten()darken()adjust-hue()SassMe是一个很好的工具,可以可视化这些函数的输出)。

lighten()和 的darken()含义一目了然。它们根据给定的百分比使给定颜色变亮或变暗。例如,lighten(black, 50%)将黑色与 50% 的白色混合,产生灰色。

使用 SASS lighten() 使颜色变浅,可视化效果见 https://sassme.jim-nielsen.com/

然而,对于LED灯来说,lighten()darken()还不够,因为灯光中心是橙色,而周围是红色。这并非色调不同,而是完全不同的颜色。

这时候adjust-hue()就派上用场了。它能让你以给定的程度改变颜色的色调属性。

颜色的色调是颜色在色轮上的位置,可以用单个数值表示,通常以度数 (0 - 360) 为单位。

色调尺度

因此我习惯adjust-hue()将颜色的色调属性向右“旋转” 35 度:

adjust-hue($color, 35)
Enter fullscreen mode Exit fullscreen mode

制作这个:

使用 SASS Adjust-hue() 调整颜色的色调属性,可视化效果见 https://sassme.jim-nielsen.com/

所以,如果颜色是红色,旋转后的颜色会变成橙色。但如果颜色是绿色,旋转后的颜色就会变成蓝色!

使用 SASS Adjust-hue() 调整颜色的色调属性,可视化效果见 https://sassme.jim-nielsen.com/

现在,您可以通过单个变量控制开关中的所有颜色$color

更改开关主颜色

概括

这篇教程比我预想的要长一些,乍一看,你可能会觉得在切换过程中用到的各种技巧和窍门有点让人眼花缭乱。但当你把它分解成基本要素后,这些技巧其实很容易理解。

我希望我能够对开发过程提供一些见解,并且希望您学到一些新的 CSS 技术。

文章来源:https://dev.to/ykadosh/how-i-made-this-realistic-red-switch-pure-css-49g2
PREV
[JavaScript] 7 OOP fundamentals you will need!
NEXT
Vue.js 的全面介绍🔥🚀