用CSS创建有方向感的3D按钮

218 阅读4分钟

我不太清楚我是如何偶然发现这个问题的。但有些东西让我看到了这条推文

有谁用CSS做了这个方向性的灯光光标互动?pic.twitter.com/zLL7Sk6kW5

- Jed Bridges (@JedBridges)2020年7月1日

而且,对我来说,这是个挑战。

按钮的设计很整齐。但我不想做一个直接的复制。相反,我们决定做一个 "Twitter "按钮。这个想法是,我们创建一个几乎透明的按钮,上面有一个社交图标。然后,这个社交图标在下面投下一个阴影。在按钮上移动我们的鼠标,就会在它上面照出一道光。按下按钮就会把它推到表面。下面是最终的结果

定向照明 3D CSS Twitter 按钮 🐦

👉t.co/qpfzEwUMeyvia@CodePen pic.twitter.com/zWfwtPaixo

- Jhey 🐻🛠(@jh3yy)2021年1月30

在这篇文章中,我们将看一下你如何也能做出来。最酷的是,你可以把图标换成你想要的任何东西。

标记

在创建这样的东西时,我首先采取的方法是建立标记的支架。在第一次检查时,我们需要复制所使用的社交图标。做到这一点的一个很好的方法是使用Pug和利用混合器。

mixin icon()
  svg.button__icon(role='img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24')
    title Twitter icon
    path(d='M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')

在这里,我们已经创建了一个混合器,用于渲染Twitter图标的SVG。如果我们像这样调用它,这将呈现出Twitter的图标。

+icon()

这样做会给我们一个大的Twitter图标。

因为社交图标集往往使用相同的 "0 0 24 24 "viewBox ,我们可以把标题和路径作为参数。

mixin icon(title, path)
  svg.button__icon(role='img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24')
    title= title
    path(d=path)

那么我们的Twitter图标就变成了

+icon('Twitter Icon', 'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')

但是,我们可以传给它一个键--如果我们有很多想要使用或重复使用的图标,可以将路径存储在一个对象中。

mixin icon(key)
  -
    const PATH_MAP = {
      Twitter: "M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"
    }
  svg.button__icon(role='img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24')
    title= `${key} Icon`
    path(d=PATH_MAP[key])

+icon('Twitter')

这可以是一种创建图标混合器以重复使用的巧妙方式。对于我们的例子来说,这有点矫枉过正,但还是值得注意的。

现在,我们需要为我们的按钮做一些标记。

.scene
  button.button
    span.button__shadow
      +icon('Twitter')
    span.button__content
      +icon('Twitter')
      span.button__shine

注意无障碍性总是好的。我们可以通过检查浏览器的开发工具中的访问性面板来检查我们的按钮发出的信号。

在我们的按钮文本中加入span ,并用aria-hidden 来隐藏图标,这可能是一个好主意。我们也可以隐藏span ,同时让屏幕阅读器可以使用它。

.scene
  button.button
    span.button__shadow
      +icon('Twitter')
    span.button__content
      span.button__text Twitter
      +icon('Twitter')
      span.button__shine

我们有不同的选项来应用这些aria-hidden 属性。我们将使用的方法是改变mixin的代码来应用aria-hidden

mixin icon(key)
  -
    const PATH_MAP = {
      Twitter: "...path code"
    }
  svg.button__icon(role='img' aria-hidden="true" xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24')
    title= `${key} Icon`
    path(d=PATH_MAP[key])

Pug的另一个巧妙的方法是将所有的属性传递给一个混合器。这在我们只想传递某些属性的情况下很有用。

mixin icon(key)
  -
    const PATH_MAP = {
      Twitter: "...path code"
    }
  svg.button__icon(role='img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24')&attributes(attributes)
    title= `${key} Icon`
    path(d=PATH_MAP[key])

如果我们再检查一下辅助功能面板,我们的按钮只显示 "Twitter"。而这正是我们想要的!

样式

下面是你要找的部分--我们如何设计这个东西。首先,我们把这个放进去。

* {
  transform-style: preserve-3d;
}

这允许我们为我们的按钮创建所需的三维变换。试着在最后的演示中关掉它,你会发现一切都会被打破。

让我们把跨度文本从我们的眼前隐藏起来。我们可以用很多方法来做到这一点。一个推荐的方法是使用这些样式来隐藏一个元素,使其不被我们的眼睛看到,但不被屏幕阅读器看到。

.button__text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

在我们开始处理我们的按钮之前,我们要将场景倾斜。我们可以用一个transform 。在这里,我们把transform ,让它进入我们想要的位置。我在这里花了一点时间在直播中修补数值,以使其接近于原始状态。

.scene {
  height: var(--size);
  position: relative;
  width: var(--size);
  transform: rotateX(-40deg) rotateY(18deg) rotateX(90deg);
}

你会注意到那里也有一个size 变量。我们要用CSS变量来驱动我们的按钮的某些东西。这将使我们能够方便地对数值和效果进行调整。通常情况下,我们会把这些放在它们需要的范围内。但是,对于像这样的演示,把它们放在我们文件顶部的:root ,可以让我们更容易地进行操作。

:root {
  --blur: 8px;
  --shine-blur: calc(var(--blur) * 4);
  --size: 25vmin;
  --transition: 0.1s;
  --depth: 3vmin;
  --icon-size: 75%;
  --radius: 24%;
  --shine: rgba(255,255,255,0.85);
  --button-bg: rgba(0,0,0,0.025);
  --shadow-bg: rgba(0,0,0,0.115);
  --shadow-icon: rgba(0,0,0,0.35);
  --bg: #e8f4fd;
}

这些是我们正在使用的变量,当我们建立起我们的按钮时,它们将变得有意义。