如果你和我一样老,你可能还记得在老式电视上观看《让我们做一笔交易》。这档节目现在似乎已经以新的形式继续播出,但最初的版本总是因为一件简单的事情而让我印象深刻:揭晓。
不知道窗帘后面是什么,这本身就令人兴奋,这也是《让我们做一笔交易》的全部意义所在。参赛者可以选择三扇门,任何一扇门打开后都会露出奖品。
太刺激了!
这种窗帘滑开,露出宝藏(即使是 Bob's Big Boy 礼品券)的技术,是一个很巧妙的小技巧,我们可以通过一些 CSS 代码来实现它。这是最终的演示
查看 CodePen 上 Geoff Graham (@geoffgraham) 的示例 OXJMmY。
HTML 代码
这基本上可以归结为三个元素
- 窗帘包装器
- 左侧窗帘面板
- 右侧窗帘面板
我们可以通过图表来可视化我们正在做的事情

…当窗帘面板滑开时,它们将露出奖品作为第四个元素

让我们用它作为我们 HTML 代码的蓝图。
<!-- The parent component -->
<div class="curtain">
<!-- The component wrapper -->
<div class="curtain__wrapper">
<!-- The left curtain panel -->
<div class="curtain__panel curtain__panel--left">
</div> <!-- curtain__panel -->
<!-- The prize behind the curtain panels -->
<div class="curtain__prize">
</div> <!-- curtain__prize -->
<!-- The right curtain panel -->
<div class="curtain__panel curtain__panel--right">
</div> <!-- curtain__panel -->
</div> <!-- curtain__wrapper -->
</div> <!-- curtain -->
CSS 布局
现在我们已经在 HTML 代码中定义了元素,我们可以开始使用 CSS 来定位它们。
我们的第一个目标是定位窗帘面板,使其不仅并排排列,而且还在奖品本身的前面。
.curtain {
width: 100%; /* Ensures the component is the full screen width */
height: 100vh; /* We're using this for demo purposes */
overflow: hidden; /* Allows us to slide the panels outside the container without them showing */
}
.curtain__wrapper {
width: 100%;
height: 100%;
}
.curtain__panel {
background: orange;
width: 50%; /* Each panel takes up half the container */
height: 100vh; /* Used for demo purposes */
float: left; /* Makes sure panels are side-by-side */
position: relative; /* Needed to define the z-index */
z-index: 2; /* Places the panels in front of the prize */
}
.curtain__panel--left {
/* Styles for sliding the left panel */
}
.curtain__panel--right {
/* Styles for sliding the right panel */
}
.curtain__prize {
background: #333;
position: absolute; /* Forces the prize position into the container start */
z-index: 1; /* Places the prize behind the panels, which are z-index 2 */
width: 100%;
height: 100%;
}
如果我们现在就停止并检查我们的工作,看起来我们似乎什么都没做。实际上,我们只是看到了一个橙色的块。
查看 CodePen 上 Geoff Graham (@geoffgraham) 的示例 wWvJaO。
这是好事!我们实际上是在看两个窗帘面板占据了整个窗帘容器,而奖品面板则隐藏在幕后。
复选框技巧
我不能不提我们要在这里实践复选框技巧。如果你不熟悉复选框技巧,它是一种方法,我们可以根据一个简单表单复选框的已知状态来改变元素的呈现方式。如果你想更深入地了解其工作原理,我们可以 查看有关该方法的文章。
使用复选框技巧的第一条规则是,我们必须在标记中添加一个复选框。让我们把它添加到 HTML 代码中
<!-- The parent component -->
<div class="curtain">
<!-- The component wrapper -->
<div class="curtain__wrapper">
<!-- The checkbox hack! -->
<input type="checkbox" checked>
<!-- The left curtain panel -->
<div class="curtain__panel curtain__panel--left">
</div> <!-- curtain__panel -->
<!-- The prize behind the curtain panels -->
<div class="curtain__prize">
</div> <!-- curtain__prize -->
<!-- The right curtain panel -->
<div class="curtain__panel curtain__panel--right">
</div> <!-- curtain__panel -->
</div> <!-- curtain__wrapper -->
</div> <!-- curtain -->
首先,让我们确保我们的复选框既不可见,又占据了整个窗帘组件的空间。我们希望整个窗帘都是可点击的,这将使我们能够做到这一点。
input[type=checkbox] {
position: absolute; /* Force the checkbox at the start of the container */
cursor: pointer; /* Indicate the curtain is clickable */
width: 100%; /* The checkbox is as wide as the component */
height: 100%; /* The checkbox is as tall as the component */
z-index: 100; /* Make sure the checkbox is on top of everything else */
opacity: 0; /* Hide the checkbox */
}
注意,复选框在我们的 HTML 代码中的默认状态是 checked
。这使我们能够根据 :checked
状态 来设置元素的样式。
/* When the checkbox is checked... */
/* Slide the first panel in */
input[type=checkbox]:checked ~ div.curtain__panel--left {
transform: translateX(0);
}
/* Slide the second panel in */
input[type=checkbox]:checked ~ div.curtain__panel--right {
transform: translateX(0);
}
这也意味着我们可以更新我们的窗帘面板,使它们在复选框未选中时从容器中滑出。
/* Slide the panel to the left out of the container */
.curtain__panel--left {
transform: translateX(-100%);
}
/* Slide the panel to the right out of the container */
.curtain__panel--right {
transform: translateX(100%);
}
现在我们有了进展!点击窗帘组件会将面板移出屏幕,并露出奖品面板。
查看 CodePen 上 Geoff Graham (@geoffgraham) 的示例 xOxqOL。
动画化更改
接下来,我们需要在复选框的状态在点击后发生更改时动画化面板的过渡。否则,你可能已经注意到,更改看起来不像滑动门,更像是眨眼。
让我们在 .curtain__panel
类中添加一个 transition
.curtain__panel {
background: orange;
width: 50%; /* Each panel takes up half the container */
height: 100vh; /* Used for demo purposes */
float: left; /* Makes sure panels are side-by-side */
position: relative; /* Needed to define the z-index */
z-index: 2; /* Places the panels in front of the prize */
transition: all 1s ease-out; /* Animates the sliding transition */
}
我们太酷了!
查看 CodePen 上 Geoff Graham (@geoffgraham) 的示例 aZbJBw。
将所有部分整合在一起
现在我们已经将所有工作元素都放在了适当的位置,我们可以开始进行微调,向窗帘面板和奖品面板添加内容。
查看 CodePen 上 Geoff Graham (@geoffgraham) 的示例 OXJMmY。
感谢这篇文章,以及漂亮的视觉效果。只是想提醒你一下:它默认情况下在 Firefox 中无法使用,因为复选框出于某种原因被定位在画布之外。添加
top: 0
和left: 0
到其样式中解决了这个问题。我也有同样的发现。:)
太棒了,感谢提醒!
复选框技巧的另一种用途!我以为会涉及一些 JavaScript 代码;但事实并非如此。我得记住这一点——找到那些需要鼠标点击处理程序的地方,但可以使用复选框来代替。
这种技术在平板电脑/手机上是否有效(即,轻触而不是点击)?
当然——复选框会在轻触时触发,就像在点击时一样。:)
非常感谢!我从未想过复选框可以用作在不使用 JavaScript 的情况下进行点击事件的方法!
它打开了无限的可能性,不是吗?!
似乎可以通过将容器设为标签并使用伪元素作为窗帘面板来简化很多。你真正需要的标记只有
这正是我所想的。只是标签中不允许使用块级元素。但可以通过获取不同的元素来轻松解决这个问题。
事实上,窗帘甚至可以用伪元素 :before 和 :after 来创建,使其更具语义性。窗帘上的文本可以通过使用 HTML 代码中的数据属性在 CSS 中填充内容来轻松实现,使其更加动态。
不错!是的,伪元素肯定会让标记更加简洁。
它也会自动触发复选框,无论其位置如何,你只需要在复选框上设置
{ visibility: hidden; }
或{ opacity: 0; }
。内容本身甚至不需要用<div>
包裹(只要复选框得到{ position: absolute; }
并且不移动内容,它就可以放在<label>
中)。我喜欢这个!你的版本比我的功能更丰富。几年前,我做了一个类似的单个元素示例。
http://codepen.io/WebRuin/pen/kEbGH
但是,正如我之前提到的,你的版本更贴近现实,我可能会用它。:p
这真的太棒了!我喜欢它设置为悬停,并且更像门的感觉。
酷!也许在选择后使用 `display: none` 隐藏输入?如果你要显示一个折扣码或类似的东西,用户就无法选择文本!
没错,说得有道理!
使用 `display: none` 的问题是,它将阻止你关闭窗帘。根据你想要做什么,这可能不是什么大问题,但绝对需要考虑。
真的很干净
我可能还会建议在复选框未选中时将其设置为不接受指针事件,以防止窗帘关闭(这并不总是适用,但如果你在包含交互式内容的任何容器上使用此效果,这很重要)。它很简单
非常棒!
我可能错了 -
但是我遇到过类似的事情,就是在点击时显示文本。我不知道复选框的技巧,由于某种原因 `:hover` 状态不起作用,我只是在对象包装器上添加了一个 `:focus` 状态。因此它在点击时显示。
现在我的问题是 - 这不是更好吗,因为它使用的是适当的事件状态而不是解决方法?
这确实很方便!
我会试一试!