专栏首页前端达人使用 CSS Checkbox Hack 技术纯手工撸一个手风琴组件

使用 CSS Checkbox Hack 技术纯手工撸一个手风琴组件

在本篇文章里,我们将一起学习下如何使用 CSS checkbox hack 技术纯手工撸一个响应式的手风琴组件,这个组件完全基于CSS,没有JavaScript脚本,同时又基于窗口大小进行水平和垂直之间进行样式切换。为了让大家更好理解本案例,我将和大家一起一步步的完成。

手风琴样式效果:

下图是我们要制作的手风琴效果动态图:

本示例需要你具备一些关于 flexbox 弹性盒子布局的相关知识。

首先,我们先了解下什么是 CSS Checkbox Hack ?

CSS Checkbox Hack 允许你通过复选框(Checkbox 或单选按钮radio buttons)是否选中来控制某些特定的样式。这里运用的是:checked 伪类选择器,其意思就是“如果选中了表单(复选框、单选按钮),则应用相关样式规则”

我们通常隐藏表单控件,然后结合<lable>标签来控制复选框或单选框的选择,制作一些特殊的效果,因此用户无法感知复选框表单的存在。

这是我的最爱,不仅可以完成本文的例子,还会制作一些更有趣例子。

1、创建 HTML 基本结构

在本练习中,我们从维基百科中找一些四种不同类型的内容介绍:动物、植物、空间和河流。然后我们创建相应的单选表单按钮,并为其分配 Value 相关的内容关键词:

建立无序列表

接下来,我们设置一个包含4行的无序列表,每行列表<li>包含了分类标题选项卡:<lable>标签和内容介绍项:<div>标签:

  1. 首先我们的分类标题选型卡外层被<label> 标签包裹在内,这里的关键所在就是这个标签,尤其是 for 这属性,指向对应表单的id的属性。<label> 标签不会向用户呈现任何特殊效果。不过,它为鼠标用户改进了可用性。如果您在 label 元素内点击文本,就会触发此对应的表单控件。就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。这就是这个案例的关键所在,让我们能在选项卡直接进行切换。
  2. <li>标签里包含的<div>内容,我们用来定义选项卡里标题对应的内容。

基于以上的思路,整理后的无序列表内容如下:

2、定义相关样式

准备好上述的HTML基本结构后,我们来定义相关的样式,首先我们需要隐藏上述的几个单选按钮表单,我们可以使用 left 属性,将其移除屏幕显示区域,示例代码如下:

接下来我们来定义手风琴整体外观样式布局,让其具有响应式,用到了弹性盒子布局,设置 display:flex, 同时又应用到了CSS的自定义变量的新属性,方便我们进行统一设置和修改,示例代码如下:

然后我们定义无序列表<li>标签的样式,也设置其为弹性盒子布局,示例代码如下:

为了区分每个<li> 选型,让其有分层的感觉,我们来定义其边框属性,示例代码如下:

每个选项卡容器,让标题默认在纵轴上进行布局(列布局),然后设置标题选项卡的宽度为70px,以及定义鼠标经过的外观样式,示例代码如下:

由于宽度有限,我们需要旋转标题文字的方向,让其由下往上垂直显示,示例代码如下:

最后我们来定义选项卡内容文本的内容样式,我们应该默认第一个选项卡的内容处于展示状态,其它选项卡隐藏,这里我们先让所有的选项卡默认隐藏,后面我们会使用 Checkbox Hack 技巧让选中的选项卡内容处于显示状态,示例代码如下:

3、Checkbox Hack: 切换选项内容

这部分代码就如同变魔法一般,当我们点击每个标题选项卡时就会显示对应相关的内容,这里我们使用了 :checked 伪类,以及结合 CSS的后续同胞选择器(~)以及紧邻同胞选择器(+)进行联合选择。

接下来我们来动手实践吧,为了让对应选中的选项卡内容可见,我们使用 display: flex 让其可见,并使用 align-items: center 属性让文本内容垂直居中。同时为了让用户区分选中了哪个选项卡,我们需要定义处理选项卡处于选中状态时对应的标题颜色。

最后定义一个可选的外观样式(非必须样式,可选),当每个单选按钮获取焦点时,我们为lable标签定义outline属性,这个细节帮助我们增强组件的可访问性。(accessibility)

以下是完成后的CSS代码内容:

4、响应式处理

接下来我们来处理下,在小屏或可视窗口低于 650px 的情况,横向无法完整展示的样式问题。幸亏我们使用了弹性盒子布局,在这种情况下,我们让手风琴垂直显示,也就是每个选项卡纵向分布(列布局),每个选项卡的标题内容横向分布(行布局),示意图效果如下:

对应的代码如何实现呢?这里我们用到了 @mdeia 媒体查询处理响应式的问题,首先我们需要更改无序列表让其为纵向分布(列布局),flex-direction: column;然后更改选项卡的标题区域布局为横向分布(行布局),flex-direction: row,示意代码如下:

5、处理内容有限的情况

在我们的案例中,每个选项卡的内容都很多,看起来很漂亮。但是为了确保没有足够内容支撑时,手风琴效果不走样,我们需要进行一些样式上的特殊处理,效果如下图所示:

  • 我们需要在每个当前选中状态的选项卡里添加 flex-grow: 1 属性,并不是所有的选项卡都添加这个属性,只是让当前选中的选项卡占据所有剩余宽度。这里我们需要做一个小的改动,我们需要在<li>标签上增加用户自定义属性(data-radio)方便我们来定义样式。
  • 接下来我们需要在选项卡的内容部分添加 flex-grow: 1 的规则,让选项卡的内容在比较少的情况下也能占满整个父元素容器的宽度。
  • 最后为选项卡的内容定添加内水平容居中的属性,示意代码如下:justify-content: center

基于以上思路,我们调整后的 html 代码如下,只是在<li>标签上增加了自定义属性(data-radio),代码如下:

CSS修部分的代码如下:

最终完成的代码

最终完成的效果,大家可以点击 阅读原文 进行查看,具体的代码如下

1、HTML代码部分:

<input type="radio" id="animal" name="wiki" value="Animal" checked>
<input type="radio" id="plant" name="wiki" value="Plant">
<input type="radio" id="space" name="wiki" value="Space">
<input type="radio" id="river" name="wiki" value="River">
<ul class="accordion">
    <li data-radio="animal">
        <label for="animal" class="accordion-title">
            <span>01</span>
            <span class="accordion-heading">Animal</span>
        </label>
        <div class="accordion-content">Animals are multicellular eukaryotic organisms that form thebiological kingdom Animalia. With few exceptions...</div>
    </li>
    <li data-radio="plant">
        <label for="plant" class="accordion-title">
            <span>02</span>
            <span class="accordion-heading">Plant</span>
        </label>
        <div class="accordion-content">MPlants are mainly multicellular,predominantly photosynthetic eukaryotes of the kingdom Plantae...</div>
    </li>
    <li data-radio="space">
        <label for="space" class="accordion-title">
            <span>03</span>
            <span class="accordion-heading">Space</span>
        </label>
        <div class="accordion-content">Space is the boundlessthree-dimensional extent in which objects and events haverelative position and direction. Physical space is often...</div>
    </li>
    <li data-radio="river">
        <label for="river" class="accordion-title">
            <span>04</span>
            <span class="accordion-heading">River</span>
        </label>
        <div class="accordion-content">A river is a natural flowingwatercourse, usually freshwater, flowing towards an ocean, sea,lake or another river. In some cases a river flows into the ground...</div>
    </li>
</ul>

2、CSS代码部分:

:root {
    --accordion-color: #282828;
    --title-color: #191919;
    --active-color: #3e86d2;
    --separator-color: #292c2d;
    --white: #9b9b9b;
    --red: #e74c3c;
    --black: #000;
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
label {
    cursor: pointer;
}
ul {
    list-style: none;
}
a {
    text-decoration: none;
    color: inherit;
}
input[type="radio"] {
    position: absolute;
    left: -9999px;
}
body {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 100vh;
    padding: 50px 0;
    font: 1rem/1.5 'Muli', sans-serif;
}
/* ACCORDION
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.accordion {
    position: relative;
    width: calc(100% - 20px);
    max-width: 800px;
    min-height: 380px;
    margin: 0 auto;
    background: var(--accordion-color);
    color: var(--white);
}
.accordion label {
    text-align: center;
}
.accordion,
.accordion li,
.accordion .accordion-title {
    display: flex;
}
.accordion li:not(:last-child) {
    border: 1px solid var(--separator-color);
}
.accordion .accordion-title {
    flex-direction: column;
    justify-content: space-between;
    width: 70px;
    font-size: 1.4rem;
    font-weight: bold;
    line-height: normal;
    padding: 20px 10px;
    background: var(--title-color);
    transition: color 0.1s;
}
.accordion .accordion-title:hover {
    color: var(--active-color);
}
.accordion .accordion-heading {
    display: inline-block;
    white-space: nowrap;
    transform-origin: bottom;
    transform: rotate(-90deg) translate(50%, 50%);
}
.accordion .accordion-content {
    display: none;
    align-items: center;
    justify-content: center;
    flex-grow: 1;
    padding: 20px;
}
[value="Animal"]:checked ~ .accordion [data-radio="animal"],
[value="Plant"]:checked ~ .accordion [data-radio="plant"],
[value="Space"]:checked ~ .accordion [data-radio="space"],
[value="River"]:checked ~ .accordion [data-radio="river"] {
    flex-grow: 1;
}
[value="Animal"]:checked ~ .accordion [for="animal"] + .accordion-content,
[value="Plant"]:checked ~ .accordion [for="plant"] + .accordion-content,
[value="Space"]:checked ~ .accordion [for="space"] + .accordion-content,
[value="River"]:checked ~ .accordion [for="river"] + .accordion-content {
    display: flex;
}
[value="Animal"]:checked ~ .accordion [for="animal"],
[value="Plant"]:checked ~ .accordion [for="plant"],
[value="Space"]:checked ~ .accordion [for="space"],
[value="River"]:checked ~ .accordion [for="river"] {
    color: var(--active-color);
}
/*[value="Animal"]:focus ~ .accordion [for="animal"],
[value="Plant"]:focus ~ .accordion [for="plant"],
[value="Space"]:focus ~ .accordion [for="space"],
[value="River"]:focus ~ .accordion [for="river"] {
  outline: 1px solid var(--active-color);
}*/
/* MQ
–––––––––––––––––––––––––––––––––––––––––––––––––– */
@media screen and (max-width: 650px) {
    .accordion {
        min-height: 0;
    }
    .accordion,
    .accordion li {
        flex-direction: column;
    }
    .accordion .accordion-title {
        flex-direction: row;
        width: auto;
    }
    .accordion .accordion-heading {
        transform: none;
    }
    .accordion .accordion-title,
    .accordion .accordion-content {
        padding: 20px;
    }
}

小节

今天的案例就和大家分享到这里,感谢你的阅读。通过本文,我们一起学习了如何使用 CSS checkbox hack 技术纯手工撸一个手风琴组件, CSS checkbox hack 不仅能做手风琴效果,还有完成更多有趣的效果,比如实现常见的导航切换、点击按钮弹出层的效果,不用写一行JS代码,是不是觉得CSS很神奇呢,在接下来的文章,我将会给大家继续分享 CSS checkbox hack 的案例,敬请期待。

原文作者:George Martsoukos 翻译:阿森(非直译) 原文链接:https://webdesign.tutsplus.com/tutorials/accordion-component-with-css-checkbox-hack--cms-34105

专注分享当下最实用的前端技术。关注前端达人,与达人一起学习进步!

本文分享自微信公众号 - 前端达人(frontend84)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flex入坑指南

    弹性布局flex是一个几年前的CSS属性了,说它解放了一部分生产力不为过。至少解放了不少CSS布局相关的面试题 :) 之前网上流行的各种XX布局,什么posti...

    贾顺名
  • css动画是可以暂停的

    css动画大家都不陌生,但是你知道css动画是可暂停的吗?如果你不知道就来看看吧。

    用户4962466
  • 反击爬虫,前端工程师的脑洞可以有多大?

    对于一张网页,我们往往希望它是结构良好,内容清晰的,这样搜索引擎才能准确地认知它。 而反过来,又有一些情景,我们不希望内容能被轻易获取,比方说电商网站的交易额,...

    IMWeb前端团队
  • vscode语言插件设置

    1.语言设置 Windows、Linux 快捷键是:ctrl+shift+p macOS 快捷键是:command + shift + p 搜索:Configo...

    似水的流年
  • 前段:可能是最全的 “文本溢出截断省略” 方案合集

    在我们的日常开发工作中,文本溢出截断省略是很常见的一种需考虑的业务场景细节。看上去 “稀松平常” ,但在实现上却有不同的区分,是单行截断还是多行截断?多行的截断...

    用户4962466
  • 动画菜鸡的自我救赎之企鹅辅导品牌页开发总结

    一般来说,品牌介绍页都是少不了各种动画的。这里我列出了辅导品牌页的三个主要的动画,后面我会讲我的实现

    IMWeb前端团队
  • CSS3 object-fit和object-position

    最近一直忙于将JavaScript学习的笔记整理成电子书,也没什么空闲时间写新的文章。趁着今天有点空闲,决定再来折腾一下CSS3中的两个属性:object-fi...

    IMWeb前端团队
  • 【英文】Node.js Streams: Everything you need to know //转载

    Node.js streams have a reputation for being hard to work with, and even harder t...

    Jean
  • [jQuery笔记] jQuery选择器

    jquery选择器允许对html中的元素组合单个元素进行操作,jquery的选择器和css的选择器几乎大同小异,大致分为元素选择器、id选择器和类选择器。jqu...

    行 者
  • 如何把HTML中的图片地址源设置为Base64编码数据

    前言:将图片转换成base64编码的,在web网上一般用于小图片上,不仅可以减少图片的请求数量(集合到js、css代码中),还可以防止因为一些相对路径等问题导致...

    Sindsun

扫码关注云+社区

领取腾讯云代金券