在 CSS 中制作加州的“我已投票”贴纸,以备选举日 2018

Avatar of Geoff Graham
Geoff Graham

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 价值 200 美元的免费积分!

嘿,明天(明天!)是美国的选举日。尽管我们在 CSS-Tricks 不参与政治背书或类似活动,但我们确实支持每个人行使他们的投票权。

两年前,我正是这样做的,并发布了 “我已投票”贴纸的 CSS 渲染,它附带我的加州邮寄选票。

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 我已投票贴纸

快进到今天,我收到了一个带有全新设计的选票贴纸。

致谢:洛杉矶杂志 (来源)

我有空闲时间,所以我要尝试用 CSS 重新创建这个贴纸,并在我制作过程中详细介绍我的思路。如果您想尝试,请随意跟随我一起进行!

分解元素

无论何时我拿到任何设计,我都会假装我的眼睛拥有透视能力,能够穿透设计,就好像它是一个骨架一样。这有助于我开始思考我在 HTML 中可能使用的元素数量。

好的,我认为我将从类似这样的内容开始

<!-- Main Circle -->
<div class="sticker">
  <div class="sticker__top">
    <!-- Will use ::before and ::after to create halves -->
    <h1>I Voted</h1>
  </div>
  <div class="sticker__bottom">
    <!-- The list of languages -->
    <ul>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
      <li>Item</li>
    </ul>
  </div>
</div>

我还将在 <body> 上添加一些基本样式,这样我就可以直接进入贴纸的其余部分。

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML

好的,到目前为止还没有什么花哨的东西。它看起来确实像一个无序列表,其中包含一个标题,并且内容和背景之间的对比度非常糟糕。

处理主贴纸容器

我认为我将设置容器,它就是主圆圈。我将使用固定宽度和高度,然后使用 border-radius 将其圆润并变成圆形。

哦,我应该处理一下深色文本,并在处理过程中添加边框,以便我可以看到自己的操作。

.sticker {
   border: 20px solid #fff;
   border-radius: 100%;
   color: #fff;
   height: 400px;
   width: 400px;
 }

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 2

对齐方式都错了。看起来这是一个放置 Flexbox 的好地方。这将允许我将元素水平居中。我认为使用单列布局将解决垂直对齐问题。

.sticker {
  display: flex;
  flex-flow: column;
  align-items: center;
  border: 20px solid #fff;
  border-radius: 100%;
  color: #fff;
  height: 400px;
  width: 400px;
}

是的,这有帮助。

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 3

我现在想对贴纸做的最后一件事是将其分成两半 - 上半部分和下半部分。好的,是的,我在 HTML 中有这些元素的显式元素 (.sticker__top.sticker__bottom)。我可以在每个元素上使用 background-color 来使上半部分为蓝色,下半部分为红色,但我实际上更喜欢使用 线性渐变,并在中间位置有一个硬停止。

.sticker {
  background-image:
    linear-gradient(
      to bottom,
       #080968,
       #080968 50%,
       #080968 50%,
       #F81616 50%
    );
  border: 20px solid #fff;
  border-radius: 100%;
  color: #fff;
  display: flex;
  flex-flow: column;
  align-items: center;
  height: 400px;
  width: 400px;
}

现在看起来更清晰了!

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 4

是时候处理上半部分了

上半部分和下半部分都占据了贴纸高度的 50%,因此可以选择器来同时选中它们。此外,我正在使用 Flexbox,因此我可以简单地灵活地使用这些项目。

.sticker__top,
.sticker-bottom {
  flex: 0 50%;
}

上半部分非常奇怪。在我看来,有两行:一行包含星条旗,另一行包含标题。我将再次使用 Flexbox 来绘制此布局。

.sticker__top {
  display: flex;
  flex-flow: row wrap;
  position: relative;
}

目前这不会改变太多,因为我还没有在 HTML 中定义星条旗的元素。我正在考虑在 .sticker__top 上使用 ::before::after 伪元素来制作它们。同样,它们可以组合在一起,因为它们共享一些通用属性和值。

.sticker__top::before,
.sticker__top::after {
  content: "";
  height: 45%; /* Had to play with this a bit */
  margin-top: 2em; /* Move away from the top edge of the sticker */
}

我将作弊并使用 SVG 来制作星星。我的意思是,这不算作弊,但感觉有点偏离了“纯粹”的 CSS 方式。好吧。

也就是说,条纹绝对可以用 CSS 制作,同样,使用与将贴纸分成蓝色和红色两半相同的线性渐变背景技术。

.sticker__top::before {
  background-image: 
    url("/path/to/star/image.svg");
  background-size: 35px; /* Magic number, depends on the image used. */
}

.sticker__top::after {
  background-image:
    linear-gradient(
      to bottom,
          #F81616,
          #F81616 14%,
      transparent 14%,
      transparent 28%,
          #F81616 28%,
          #F81616 42%,
      transparent 42%,
      transparent 56%,
          #F81616 56%,
          #F81616 70%,
      transparent 70%,
      transparent 84%,
          #F81616 84%,
          #F81616 98%,
      transparent 100%
    );
}

这很酷,但是,糟糕,东西都乱了。

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 5

我很感谢 Flexbox 有一个 order 属性。我将分别按 1、2 和 3 的顺序排列星星、条纹和标题。

.sticker__top::before {
  /* Same as before... */
  order: 1;
}

.sticker__top::after {
  /* Same as before... */
  order: 2;
}

.sticker__top h1 {
  order: 3;
}

如果我在这里停止,星星和条纹的形状将全部出错,标题字体也会很糟糕。

border-radius 仍然是使星星和条纹遵循与贴纸相同的圆形路径的好方法。问题在于它们的底部必须保持平坦的边缘。由于 border-radius 是一个简写属性,因此我将在星星上添加 border-top-left-radius,并在条纹上添加 border-top-right-radius

还值得注意的是,条纹比星星略宽。可能是 55-45 分割?我不知道。我将使用它,并在条纹上使用相对定位,以便我可以将它们稍微推到右边,以在它们和星星之间添加间隔。

.sticker__top::before {
  /* Same as before... */
  flex: 45%;
}
  
.sticker__top::after {
  /* Same as before... */
  flex: 55%;
  position: relative;
  left: 10px;
}

星星和条纹应该随着标题的尺寸和宽度而灵活变化。我不得不尝试调整字体系列、字号、字母间距和文本转换,才能获得看起来不错的效果。如果你想知道,我最终使用了 Raleway 作为字体。它并不精确,但足够接近……至少对于我这个没有受过训练的排版爱好者来说。

.sticker__top h1 {
  font-family: 'Raleway', sans-serif;
  font-size: 4em;
  letter-spacing: 3px;
  line-height: 0;
  text-transform: uppercase;
  order: 3;
}

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 6

好吧,现在下半部分让我感到毛骨悚然。我必须解决它。

调整下半部分的样式

已经完成了许多工作。下半部分的元素已经在 HTML 中,并且大小和位置都已设置好。我认为删除列表项的项目符号,并从无序列表中删除左侧填充将使事情变得干净很多。

.sticker__bottom ul {
  list-style: none;
  padding: 0;
  width: 100%; /* Gotta take up the all of the bottom half */
}

但是,这还不能完全解决问题。我希望该列表水平排列、换行,并允许列表项占用开放空间。是的,这听起来像是 Flexbox 的功能。

.sticker__bottom ul {
  display: flex;
  flex-flow: row wrap;
  align-items: flex-start;
  justify-content: flex-start;
  /* same as before... */
}

.sticker__bottom li {
  flex: auto; /* Flex as much as you need, guys */
  margin: .75em; /* A liiiiitle breathing room between items */
}

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 7

现在我必须对 .sticker__bottom 进行一些调整。具体来说,我将使其更窄(贴纸全宽的 80%),以便将其移出贴纸边缘,然后对其边缘进行圆角……尽管实际上可能不需要圆角,因为内容不会溢出。

.sticker__bottom {
  border-bottom-right-radius: 100%;
  border-bottom-left-radius: 100%;
  width: 80%;
}

然后,将文本居中。我认为这可以在父元素 .sticker 上进行,因为贴纸上的任何内容在技术上都没有左对齐。

.sticker {
  /* same as before... */
  text-align: center;
}

最后,我将尽力用“我已投票”的翻译替换虚拟内容。让我去查一下。

(转到 Google 翻译。)

嗯,我找不到我需要的一切。我确定这是我缺乏耐心,但我最终使用了一些替代方案。

<ul>
  <li>Yo voté</li>
  <li>我投票</li>
  <li>나는 투표했다</li>
  <li>Bumoto ako</li>
  <li>Я проголосував</li>
  <li>मैने मतदान किया</li>
  <li>أنا صوتت</li>
  <li>Ik stemde</li>
  <li>Szavaztam</li>
  <li>ฉันโหวตแล้ว</li>
  <li>Anigu waxaan codsaday</li>
  <li>Tôi đã bầu chọn</li>
</ul>

我将不得不调整字号,以获得与 IRL 贴纸相同的对齐方式,IRL 贴纸的行数为:4 个项目、3 个项目、3 个项目、1 个项目、1 个项目。

这是我最终的结果。

.sticker__bottom ul {
  display: flex;
  flex-flow: row wrap;
  font-size: .75em;
  align-items: flex-start;
  justify-content: flex-start;
  list-style: none;
  padding: 0;
  width: 100%;
}

为了使最后两个项目在同一行上,我将使用 :last-child() 单独选中倒数第二个项目,以便它们始终以 100% 的比例灵活变化。

.sticker__bottom li:nth-child(11) {
  flex: 100%;
}

最后,我将把贴纸周围的白色边框从白色更改为蓝色。它给出了我们想要的伪填充效果。

查看 CodePen 上 Geoff Graham (@geoffgraham) 的 “我已投票”贴纸 HTML 8

叮!准备好了!

我要称这个为“烤好了”。我知道,我知道。我应该进行跨浏览器测试。寻找不支持 flexbox 的旧浏览器的优雅回退也是明智之举。而且,一些响应式设计会很不错。也许有人愿意接手并分享一下。😉

这是制作贴纸的最佳方法吗?可能不是。例如,我敢肯定,可以使用 clip-path 做一些有趣的事情,而不是我笨拙地使用背景渐变的方式。而且,如果让我重新来过,我甚至可能会考虑在父元素上使用 CSS 网格布局,因为显然有在两个方向而不是一个方向上工作的机会。

但这就是 CSS 的魅力所在。有 不止一种方法 可以完成某件事。

朋友们,选举日快乐。🇺🇸