hamburger组件_一个侧边栏导航组件实现思路

翻译:布兰
作者:Adam Argyle
来源:https://web.dev/building-a-sidenav-component/

在这篇文章中,我想和大家分享我是如何为 web 原型化一个 Sidenav 组件的,这个组件是响应式的,有状态的,支持键盘导航,可以使用和不使用 Javascript,并且可以跨浏览器工作。

构建一个响应式导航系统是很困难的。有些用户使用键盘,有些用户使用强大的台式机,还有一些用户使用小型移动设备访问。每个访问者都应该能够打开和关闭菜单。

80035fb2c04e056d322eedd2119752f7.gif
桌面到移动设备响应式布局演示

用了哪些技术

在这次组件探索中,我很高兴地结合了一些关键的网络平台特性:

  • 伪类
  • CSS Grid
  • transforms
  • 媒体查询和用户偏好 CSS
  • 用户增强体验

我的解决方案只有一个侧边栏,只有在“移动”视口为540px 或更小时才能切换。540px 将是我们在移动交互式布局和静态桌面布局之间切换的断点。

伪类

一个 链接将 url 散列设置为 #sidenav-open,另一个设置为 empty('')。最后,一个元素具有匹配散列的 id:

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu">a>
<aside id="sidenav-open">aside>
98ac4c2614efabb87580366fe8fdb284.gif

点击这些链接会改变我们网页 URL 的散列状态,然后用一个伪类来显示和隐藏 Sidenav:

@media (max-width: 540px) {
    #sidenav-open {
        visibility: hidden;
    }
    
    #sidenav-open:target {
        visibility: visible;
    }
}

CSS Grid

在过去,我只使用绝对或固定位置 Sidenav 布局和组件。不过,使用网格区域语法,可以为同一行或列分配多个元素。

Stacks

主要的布局元素 #sidenav-container 是一个网格,它创建了 1 行和 2 列,其中 1 列被命名为 stack。当空间受到限制时,CSS 会将所有 元素的子元素赋给同一个网格名称,将所有元素放在同一个空间中,创建一个堆栈。

#sidenav-container {
    display: grid;
    grid: [stack] 1fr / min-content [stack] 1fr;
    min-height: 100vh;
}

@media (max-width: 540px) {
    #sidenav-container > * {
        grid-area: stack;
    }
}

菜单背景

是包含侧边导航的动画元素。它有两个子元素: 导航容器 命名为 [nav] ,背景幕布 命名为 [escape],用于关闭菜单。

#sidenav-open {
    display: grid;
    grid-template-columns: [nav] 2fr [escape] 1fr;
}

调整 2fr1fr,找到你喜欢的菜单覆盖和负空间关闭按钮的比例。

5f329a436ed232618775440ba95034fd.gif

3D transforms

我们的布局现在是堆叠在一个移动视口大小。除非我添加一些新的样式,否则它将默认覆盖我们的文章。下面是一些我正在努力实现的用户体验:

  • 动画打开和关闭;
  • 只有在用户同意的情况下才使用动画;
  • 键盘焦点不会进入屏幕以外的元素;

当我开始实现动作动画的时候,我想先从可访问性开始。

无障碍运动

不是每个人都想要幻灯片移动的体验。在我们的解决方案中,这个首选项是通过调整媒体查询中的 -- duration CSS 变量来实现的。此媒体查询值表示用户的操作系统对移动的偏好(如果可用)。

#sidenav-open {
    --duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
    #sidenav-open {
        --duration: 1ms;
    }
}
62f7da3e33c65d5234e882696e60a5a1.gif

现在,当我们的 sidenav 滑动打开和关闭,如果用户喜欢减少运动,我立即移动元素进入视图,保持没有运动的状态。

Transition, transform, translate

Sidenav 默认是退出状态的。为了将移动设备上 Sidenav 的默认状态设置为屏幕外状态,我将元素的位置设置为:

transform: translateX (- 110vw);

注意,我在典型的屏幕外代码 -100vw 中添加了10vw,以确保当 sidenav 隐藏时,它的盒子阴影不会窥视主视图。

@media (max-width: 540px) {
    #sidenav-open {
        visibility: hidden;
        transform: translateX(-110vw);
        will-change: transform;
        transition: 
            transform var(--duration) var(--easeOutExpo),
            visibility 0s linear var(--duration);
    }
}

#sidenav 元素匹配为 :target 时,将 translateX() 位置设置为 0。当 URL 哈希值变化的时候,观察到元素会从 -110vw 的位置滑动到 0 的位置。

@media (max-width: 540px) {
    #sidenav-open:target {
        visibility: visible;
        transform: translateX(0);
        transition: transform var(--duration) var(--easeOutExpo);
    }
}

过渡时期的可见性

现在的目标是屏幕阅读器看不到菜单,这样系统就不会把焦点放在屏幕外的菜单上。我通过在: 目标更改时设置可见性转换来实现这一点。

  • 进入时,请勿过渡可见性;立刻可见,因此我可以看到元素滑入并接受焦点。
  • 退出时,给他加一个延迟到过渡效果;

可访问性 UX 增强

链接

此解决方案依赖于更改 URL 以便管理状态。当然,这里应该使用 元素,它可以免费获得一些很好的可访问性特性。让我们用清楚表达意图的标签来装饰我们的交互式元素。

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu">a>
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
    <svg>...svg>
a>

现在我们的主要交互按钮清楚地表明了鼠标和键盘的意图。

:is(:hover, :focus)

这个方便的 CSS 函数式伪选择器可以让我们通过分享焦点快速地包容我们的悬停样式。

.hamburger:is(:hover, :focus) svg > line {
    stroke: hsl(var(--brandHSL));
}

加上点 JS

键盘上的 Escape 键应该关闭菜单,对吗? 让我们把它实现:

const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
    if (event.code === 'Escape') document.location.hash = '';
});

下一个代码片段帮助我们将注意力集中在打开或关闭按钮上。我想让切换变得简单。

sidenav.addEventListener('transitionend', e => {
    const isOpen = document.location.hash === '#sidenav-open';
    isOpen
        ? document.querySelector('#sidenav-close').focus()
        : document.querySelector('#sidenav-button').focus();
})

当 Sidenav 打开时,集中关闭按钮。当 Sidenav 关闭时,集中打开按钮。我通过在 JS 中的元素上调用 focus() 来实现这一点。

5492f78de6359a7dc7f984b5bb830347.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/442954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos php mysql 5.6 安装_centos7安装nginx、php5.5、mysql5.6

一、nginx1、安装yum install nginx2、启动systemctl start nginx关闭&#xff1a;systemctl stop nginx 重启&#xff1a;systemctl restart nginx 检查状态&#xff1a;systemctl status nginx3、测试浏览器直接访问http://ip,应该会看到以下界面&#xff1a;4、支持php打开/…

myeclipse怎么导入mysql驱动_myeclipse sql导入数据库驱动包

如何配置strutshibernate&#xff0c;基本使用方法不少童鞋在自学SSH框架的时候&#xff0c;难在创建第一个项目&#xff0c;如何搭建好这些框架&#xff0c;很多书上只是给出了代码但是没有教如何使用&#xff0c;所以在本次博客中将会图文结合来说一下如何使用struts结合hibe…

mysql 报表统计sql使用实例_mysql 案例~mysql元数据的sql统计

一 简介:今天我们来收集下提取元数据的sql二 前沿: information_schema 引擎 memory 元数据收集表三 sql语句:1#没有使用索引的表统计SELECT t.TABLE_SCHEMA,t.TABLE_NAME,t.TABLE_ROWS FROM information_schema.tables AS t LEFT JOIN (SELECT DISTINCT table_schema, table_…

创建或更改表 tablename 失败_mysql 创建用户

一. 创建用户命令:CREATE USER usernamehost IDENTIFIED BY password;说明&#xff1a;username&#xff1a;你将创建的用户名host&#xff1a;指定该用户在哪个主机上可以登陆&#xff0c;如果是本地用户可用localhost&#xff0c;如果想让该用户可以从任意远程主机登陆&#…

linux忘记mysql登录用户密码_linux中忘记mysql用户root密码解决方案

1.vim /etc/my.cnf[mysqld]skip-grant-tables ##追加此行&#xff0c;跳过权限表&#xff0c;2.重启mysqlsystemctl restart mysqld3.mysql 登陆mysqlmysql> use mysql;mysql> UPDATE user SET Password password ( ‘zha123456‘ ) WHERE User ‘root‘ ;mysql> fl…

sql2000 mysql 兼容_SQL Server2000如何恢复数据库

以里诺仓库管理软件(SQL网络版)为例&#xff0c;如果您因电脑操作系统重装&#xff0c;需要把以前备份的数据库恢复过来&#xff0c;请您按如下操作来。首先&#xff0c;您需要安装MS SQL Server2000。1. 以Windowns XP为例&#xff0c;SQL Server个人版安装完成后&#xff0c;…

suse下删除mysql_每日MySQL之005:SUSE linux下卸載MySQL

卸載這里的卸載&#xff0c;對應於之前的安裝停止MySQL服務&#xff1a;db2a:~ #service mysql stop找到所有的MySQL包&#xff1a;db2a:~ #rpm -qa | grep -i mysqlmysql-community-server-5.7.19-1.sles11mysql-community-common-5.7.19-1.sles11libqt4-sql-mysql-4.6.3-5.34…

java中br.readline_Java:java中BufferedReader的read()及readLine()方法的使用心得

BufferedReader的readLine()方法是阻塞式的, 如果到达流末尾, 就返回null, 但如果client的socket末经关闭就销毁, 则会产生IO异常. 正常的方法就是使用socket.close()关闭不需要的socket.从一个有若干行的文件中依次读取各行&#xff0c;处理后输出&#xff0c;如果用以下方法&…

java dfs_Java数据结构与算法 深搜(DFS)的简单使用(一)之排列组合

今天&#xff0c;我们来简单介绍一下深度优先搜索(DFS)的概念和使用。在百度词条中&#xff0c;对深搜的解释是这样的。百度词条中的解释由此&#xff0c;我们可知&#xff0c;深搜是广泛运用到 图 中的搜索方法之一。用深度优先搜索遍历图的基本思路是&#xff1a;(1)访问顶点…

java数组元素是类_Java数组及其常用类

本文由疯狂软件教育中心整理&#xff0c;更多Java等高新技术&#xff0c;疯狂软件期待与你交流。一、JAVA中的数组(1)数组的定义&#xff1a;是有相同类型的、用一个标识符名称封装到一起的一个对象序列或基本数据类型数据序列。数组是一种最简单的复合数据类型。数组可以是一维…

java 数组 equals_java中用equals比较两个内容相同的字符数组

********************************************你在数组上调用函数equals,比较的是c和ch的地址改成if(Arrays.equals(ch,c));就可以比较c和ch的内容了********************************************java.sun.com上说&#xff0c;The equals method for class Object implements…

java ssh pdf_JavaSSH框架技术规范.pdf

航安项目(三期)框架技术规范日期 版本 简述 作者2011年3月1 日 V1.0 指定本系统的技术规范2011年9月25 日 V2.0 指定本系统的技术规范框架技术规范航安项目框架技术规范 目录1、规范配置说明12、系统三层架构规范配置说明12.1 Dao22.2 Entity42.3 Service43、Spring 规范配置说…

java 线程执行结束_Java_如何等待子线程执行结束

本程序的数据有可能是如下:main thread work startsub thread start working.main thread work done.now waiting sub thread done.sub thread stop working.now all done.忽略标号, 当然输出也有可能是1和2调换位置了. 这个我们是无法控制的. 我们看下线程的join操作, 究竟干了…

mysql将时间轴转化为时间_MySQL日期计算及格式转换有关问题

mysql日期计算及格式转换问题2012-06-09 21:08 MySQL日期计算及格式转换问题做开发的时候经常会碰到以下几个问题使用mysql的内置函数将时间轴转成对应的日期方法一&#xff1a;使用from_unixtime(unix_timestamp)函数即可实现&#xff0c;如&#xff1a;SELECT FROM_UNIXTIME(…

java 配置文件加密_Java在配置文件中加密密码?

小编典典一种简单的方法是在Java中使用基于密码的加密。这使你可以使用密码来加密和解密文本。这基本上意味着初始化一个javax.crypto.Cipherwith算法"AES/CBC/PKCS5Padding"并从javax.crypto.SecretKeyFactory该"PBKDF2WithHmacSHA512"算法获取密钥。这是…

java语言特点 字符串不变_面试必问:Java中String类型为什么设计成不可变的?

这几天在各大平台上都看到过这样一些帖子&#xff0c;全都是关于String类型对象不可变的问题&#xff0c;当然现在也是找工作的准备时期&#xff0c;因此花了一部分时间对其进行整理一下。想要完全了解String&#xff0c;在这里我们需要解决以下几个问题(1)什么是不可变对象&am…

java socket android_Android:这是一份很详细的Socket使用攻略

前言Socket的使用在 Android网络编程中非常重要今天我将带大家全面了解 Socket 及 其使用方法目录示意图1.网络基础阅读本文前&#xff0c;请先了解 关于计算机网络基础&#xff0c;如计算机体系结构、TCP、UDP等知识2. Socket定义即套接字&#xff0c;是应用层 与 TCP/IP 协议…

内构函数java_Android JNI参数传递

Java中调用native函数传递的参数是Java数据类型&#xff0c;到了JNI层需进行数据类型转换&#xff0c;基本数据类型是在前面加个j&#xff0c;如int——>jint&#xff0c;应用数据类型除了基本数据类型的数据、Class、String和Throwable外&#xff0c;其余所有Java对象的数据…

java 垃圾回收机制_Java的垃圾回收机制

前言在C语言中, 程序员必须小心谨慎的处理每一项内存分配, 且内存使用完后必须手动释放曾经占用的内存空间。当内存释放不够完全时, 即存在分配但永不释放的内存块, 就会引起"内存泄漏"问题。而在Java语言中, 它给了程序员一个美好的承诺: 程序员无需管理内存, 因为J…

java闹钟程序声音_跪求高手帮忙写一个JAVA手机闹钟程序 实现添加铃声和设置多闹钟...

展开全部import java.util.*;import java.awt.*;import java.applet.*;import java.text.*;public class AlarmClock extends Applet implements Runnable{Thread timernull; //创建线程timerImage clockp,gif1,gif2,clock6,clock7; //clockp:闹钟的外壳&#xff0c;闹铃和e68a…