嘿,明天(明天!)是美国的选举日。尽管我们在 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 的魅力所在。有 不止一种方法 可以完成某件事。
朋友们,选举日快乐。🇺🇸
我真的很喜欢你的努力。我认为做得很好,只是对我来说太大了,白色边框,但这只是一行代码的修改。干杯,祝你 CSS 写作愉快
没错!有一个细的白色边框,然后围绕它有一个更粗的蓝色边框,这样就可以实现我想要的那种可以剥离的贴纸效果。说得对!
我在智能手机上阅读了这篇文章,我可以告诉你,结果在移动设备上看起来并不好。不过文章很棒!
哈哈,当然!我在结尾部分做了说明。:)
您的 CodePen 似乎缺少字体声明,包含它与缺少它之间的差异真的很大。Raleway 字体,重量为 900,然后将底部部分的字体加粗,重量为 600,并删除白色边框,这些都真正地完善了设计,使其看起来更接近原始设计。