本文作者:IMWeb zzbozheng 原文出处:IMWeb社区 未经同意,禁止转载
用css实现一个todo应用程序,但不是TodoMVC那样的设计,它不使用JavaScript,而是所有的交互都是由CSS驱动的。
他是怎样实现的?简单来说:它使用预渲染HTML,CSS兄弟组合器(~),CSS计数器和:checked,:target和所需的伪选择器的组合。 这篇文章的其余部分将会更详细的介绍。
为了实现应用程序可交互,我们需要一些方法来存储和修改状态,然后在CSS中做出反应。 但通常情况下,该状态将保存在HTML中,但是没有JavaScript,我们无法修改DOM结构。
为了解决这个问题,我们可以使用复选框表单字段来存储状态,然后使用:checked 伪类选择器访问该状态。
Toggle content: <input type="checkbox"></input>
<div id="content">
Hello world!
</div>
<style>
#content {
display: none;
}
input:checked ~ #content {
display: block;
}
</style>
以上代码也使用了CSS通用兄弟选择器:~。 它匹配我们检查输入的所有以下兄弟姐妹 - 在这种情况下,我们要显示或隐藏的div。这也意味着CSS可以用于控制所有的item显隐状态。
我们知道HTML标签label的属性,允许我们定位和切换与复选框本身无关的按钮。再来看一段代码:
<input type="checkbox" id="toggle-box"></input>
<label for="toggle-box">Toggle!</label>
<div id="content">
Hello world!
</div>
现在我们有办法存储状态了,每个待办事项都有三个复选框来存储状态:
可能会给你一个线索如何应用程序将工作。 没有JavaScript,我们无法修改DOM。 这意味着所有的todo item都必须是初始页HTML的一部分。 如果您查看页面的源码,您会发现它已经包含50个预渲染的待办事项。
.todo#todo-1
input.created-checkbox
.todo#todo-2
input.created-checkbox
.todo#todo-3
...
以下是应用的部分html截图
个人待办事项如下所示:
我们来看看如何实现删除功能。 首先我们有一个复选框来存储删除的状态:
<input type="checkbox" class="deleted-checkbox" id="deleted-checkbox-3">
需要一个删除按钮
<label for="deleted-checkbox-3" class="deleted-checkbox-label">×</label>
If the checkbox is :checked we want to hide all parts of that item. But since each todo item contains all following todo items we have make sure to keep the next .todo visible. 如果该复选框是:checked,我们要隐藏该项目的所有部分。 但是由于每个待办事项包含其他的item,那我们还需要确保保持下一个.todo是可见的。
.deleted-checkbox:checked ~ :not(.todo) {
display: none !important;
}
为了相对简单一些,复选框首先位于item的DOM中。因此,所有可见的UI可以通过~选择器来匹配。
TodoMVC可以让您选择只查看已完成或未完成的待办事项。我们也可以使用复选框来实现这一点,但是使用URL哈希更简洁些。
<a class="filter-active" href="#/active">Active</a>
When you click on the link the browser will scroll to the element with the id /active 当你点击该链接后,页面会滚动定位到id为/active
的元素上。但更重要的是,此时该元素已经匹配了伪类:target
。
<div id="/completed" class="completed-filter">
<!-- Todo items -->
</div>
我们可以匹配未完成的子项,并将其隐藏。
.completed-filter:target
.created-checkbox:checked
~ .done-checkbox:not(:checked)
~ .todo-input {
display: none !important;
}
所以,除了复选框,我们还可以在URL中存储和访问状态!
将最后一个未完成的item目移动到列表的顶部,其位置为:absolute,并显示“添加”按钮。
CSS有一个可爱的功能,称为计数器。我们可以通过他来计算出与CSS选择器匹配的item数量。我们可以用它来显示剩下几个todos。
body {
counter-reset: items-left;
}
.created-checkbox:checked
~ .deleted-checkbox:not(:checked)
~ .done-checkbox:not(:checked)
~ .items-left-counter-helper {
counter-increment: items-left;
}
#items-left:before {
content: counter(items-left);
}
我们可以统计:
为什么我们是统计.items-left-counter-helper的数量,而不是计算.mark-undone-checkbox-label? 之前有尝试过,但是CSS计数器不计算被隐藏的元素,所以当筛选出已完成的item时(因为所有未完成的项目都不可见),会看到未完成的item总数量值为0。
这里我们用到一个伪类选择器:required! HTML具有基本的表单验证功能。 例如,我们可以给一个文本输入框标记为必填:
<input required type="text" value="" class="todo-input">`
然后,我们可以使用CSS来检查该字段是否已被填写,是否是有效值:
input:not(:valid) ~ .created-checkbox-label {
pointer-events: none;
}
使用pointer-events,我们可以禁用鼠标交互,例如单击或悬停。
尽管这个应用远达到不完美,但对于CSS的伪类的灵活运用值得我们学习。