在今天的教程中,我们将学习如何构建一个纯 css 的过滤组件,如果你认为它需要 javascript,这是可以原谅的。我们将使用一些简单的标记、一些表单控件和一些您以前可能没有使用过的非常有趣的 CSS 选择器。
我们正在努力的方向
Tuts+ 的每位讲师都有自己的存档页面。我们将使用我们自己的标记重新创建这样的教程列表。然后,我们将实现一个组件,该组件将根据帖子所属的类别过滤帖子。
这是我们的最终项目:
See the Pen Build a Filtering Component in Pure CSS by Envato Tuts+ (@tutsplus) on CodePen.
让我们开始建设吧!
1. 从 html 标记开始
我们首先确定组件中的过滤器类别。在本例中,我们将使用七个过滤器:
All
CSS
Slider
fullPage.js
为此,我们首先定义了七个单选按钮,我们将它们分组在categories 关键字下。默认情况下,第一个单选按钮被选中:
<input type="radio" id="All" name="categories" value="All" checked>
<input type="radio" id="CSS" name="categories" value="CSS">
<input type="radio" id="javaScript" name="categories" value="JavaScript">
<input type="radio" id="jQuery" name="categories" value="jQuery">
<input type="radio" id="WordPress" name="categories" value="WordPress">
<input type="radio" id="Slider" name="categories" value="Slider">
<input type="radio" id="fullPage.js" name="categories" value="fullPage.js">
然后我们创建一个有序列表,其中包含与上述单选按钮相关的标签。
请记住,我们通过将单选按钮的id值设置为标签的for值来将单选按钮与标签相关联:
<ol class="filters">
<li>
<label for="All">All</label>
</li>
<li>
<label for="CSS">CSS</label>
</li>
<li>
<label for="JavaScript">JavaScript</label>
</li>
<li>
<label for="jQuery">jQuery</label>
</li>
<li>
<label for="WordPress">WordPress</label>
</li>
<li>
<label for="Slider">Slider</label>
</li>
<li>
<label for="fullPage.js">fullPage.js</label>
</li>
</ol>
接下来我们设置另一个有序列表,其中包括我们要过滤的元素(我们的卡片)。每个过滤后的元素都有一个自定义data-category 属性,其值是以空格分隔的过滤器列表:
<ol class="posts">
<li class="post" data-category="CSS JavaScript">...</li>
<li class="post" data-category="CSS JavaScript">...</li>
<!-- 10 more list items here -->
</ol>
在我们的例子中,过滤后的元素将是帖子。因此,我们将用来描述帖子及其元(标题、图像、类别)的标记如下所示:
<article>
<figure>
<a href="" target="_blank">
<img src="IMG_SRC" alt="">
</a>
<figcaption>
<ol class="post-categories">
<li>
<a href="">...</a>
<li>
<!-- possibly more list items here -->
</ol>
<h2 class="post-title">
<a href="" target="_blank">...</a>
</h2>
</figcaption>
</figure>
</article>
准备好标记后,让我们将注意力转向所需的样式。
2. 定义样式
我们首先在视觉上隐藏单选按钮:
input[type="radio"] {
position: absolute;
left: -9999px;
}
然后我们为过滤器添加一些样式:
:root {
--black: #1a1a1a;
--white: #fff;
--green: #49b293;
}
.filters {
text-align: center;
margin-bottom: 2rem;
}
.filters * {
display: inline-block;
}
.filters label {
padding: 0.5rem 1rem;
margin-bottom: 0.25rem;
border-radius: 2rem;
min-width: 50px;
line-height: normal;
cursor: pointer;
transition: all 0.1s;
}
.filters label:hover {
background: var(--green);
color: var(--white);
}
CSS 网格布局
我们继续为过滤后的元素指定一些样式。最重要的是,我们使用 CSS Grid 根据屏幕大小对它们进行不同的布局:
:root {
--black: #1a1a1a;
--white: #fff;
--green: #49b293;
}
.posts {
display: grid;
grid-gap: 1.5rem;
grid-template-columns: repeat(4, 1fr);
}
.posts .post {
background: #fafafa;
border: 1px solid rgba(0, 0, 0, 0.1);
}
.posts .post-title {
font-size: 1.3rem;
}
.posts .post-title:hover {
text-decoration: underline;
}
.posts figcaption {
padding: 1rem;
}
.posts .post-categories {
margin-bottom: 0.75rem;
font-size: .75rem;
}
.posts .post-categories * {
display: inline-block;
}
.posts .post-categories li {
margin-bottom: 0.2rem;
}
.posts .post-categories a {
padding: 0.2rem 0.5rem;
border-radius: 1rem;
border: 1px solid;
line-height: normal;
background: all 0.1s;
}
.posts .post-categories a:hover {
background: var(--green);
color: var(--white);
}
@media screen and (max-width: 900px) {
.posts {
grid-template-columns: repeat(3, 1fr);
}
}
@media screen and (max-width: 650px) {
.posts {
grid-template-columns: repeat(2, 1fr);
}
}
注意:出于可读性的原因,在我们的 CSS 中,我们没有对常见的 CSS 规则进行分组。
添加过滤样式
这里的想法非常简单。每次我们点击过滤器时,只会出现相应的过滤元素(帖子)。为了实现该功能,我们将使用以下 CSS 好东西的组合:
伪类:checked
否定伪类 ( :not())
属性选择器
通用兄弟组合子( ~) 在 CSS4 中重命名为“subsequent-sibling selector”
当我们点击All过滤器时,所有具有data-category 属性的帖子都会出现:
[value="All"]:checked ~ .posts [data-category] {
display: block;
}
当我们点击任何其他过滤器类别时,只有目标帖子可见:
[value="CSS"]:checked ~ .posts .post:not([data-category~="CSS"]),
[value="JavaScript"]:checked ~ .posts .post:not([data-category~="JavaScript"]),
[value="jQuery"]:checked ~ .posts .post:not([data-category~="jQuery"]),
[value="WordPress"]:checked ~ .posts .post:not([data-category~="WordPress"]),
[value="Slider"]:checked ~ .posts .post:not([data-category~="Slider"]),
[value="fullPage.js"]:checked ~ .posts .post:not([data-category~="fullPage.js"]) {
display: none;
}
例如只要我们点击Slider 过滤类别,只有属于该Slider 类别的帖子才会可见。
值得一提的是,在我们上面的样式而不是 [att~=val] 语法中,我们同样可以使用 [att*=val] 语法。以下是这种微妙变化的样子:
[value="CSS"]:checked ~ .posts .post:not([data-category*="CSS"]),
[value="JavaScript"]:checked ~ .posts .post:not([data-category*="JavaScript"]),
[value="jQuery"]:checked ~ .posts .post:not([data-category*="jQuery"]),
[value="WordPress"]:checked ~ .posts .post:not([data-category*="WordPress"]),
[value="Slider"]:checked ~ .posts .post:not([data-category*="Slider"]),
[value="fullPage.js"]:checked ~ .posts .post:not([data-category*="fullPage.js"]) {
display: none;
}
快速 CSS 选择器说明
这个选择器到底在说什么?
第一位[value="CSS"]:checked查找具有特定值的选中单选按钮(在本例中为“CSS”)。
之后,波浪号 (~) 就是我们现在所说的“后续兄弟选择器”。它选择与前一个元素具有相同父级的元素,即使它们没有立即跟随在标记中。所以~ .posts .post寻找.posts .post与检查的无线电输入共享相同父元素的元素。
更具体地说,:not([data-category~="CSS"]) 将我们的选择器细化为仅那些不具有包含 空格分隔列表中某处的值的属性的.post元素。data-categoryCSS
然后它将 a 应用于display: none;与这些条件匹配的任何元素。
这是一个相当复杂的选择器,尽管它完全合乎逻辑。用人类语言术语,您可以将其描述为:
“当检查具有“ CSS”值的广播时,请在其数据类别列表中找到任何不包含“ CSS”的兄弟姐妹元素,然后隐藏它们。”
最后一点造型
作为最后一步,我们添加一个突出显示活动过滤器类别的规则:
:root {
--black: #1a1a1a;
--white: #fff;
--green: #49b293;
}
[value="All"]:checked ~ .filters [for="All"],
[value="CSS"]:checked ~ .filters [for="CSS"],
[value="JavaScript"]:checked ~ .filters [for="JavaScript"],
[value="jQuery"]:checked ~ .filters [for="jQuery"],
[value="WordPress"]:checked ~ .filters [for="WordPress"],
[value="Slider"]:checked ~ .filters [for="Slider"],
[value="fullPage.js"]:checked ~ .filters [for="fullPage.js"] {
background: var(--green);
color: var(--white);
}
3. 可访问性
默认情况下可以很好地访问此过滤;由于单选按钮和标签的原生方式工作,我们可以使用键盘按键过滤我们的项目。首先按Tab键将焦点移至选中的单选按钮。接下来按箭头键将焦点和选择移动到其他单选按钮。自己试试:
See the Pen Build a Filtering Component in Pure CSS by Envato Tuts+ (@tutsplus) on CodePen.
也就是说,我们并没有真正关注可访问性,因此很可能还有其他 a11y 方面需要改进。
结论
就是这样的人!仅通过一些 CSS 规则和一些结构化标记,我们就设法构建了一个功能齐全的过滤组件。
我希望你喜欢这个练习,并且它帮助你扩展了对 CSS 选择器的理解。一如既往,感谢您的阅读!
- 我们正在努力的方向
- CSS 网格布局
- 添加过滤样式
- 快速 CSS 选择器说明
- 最后一点造型