# 使用CSS :target 伪类实现Drawer抽屉弹窗与Modal模态对话框

> Web应用中时常会看到一些弹窗，如抽屉(侧滑弹窗)与模态对话框之类组件，通常我们会通过JavaScript实现其显示与否，下面看看通过CSS伪类:target如何实现。

Author: DeathGhost
Published: 2021-05-10 21:23:50
Category: css
Canonical: https://www.deathghost.cn/article/css/95
Keywords: CSS, :target, 伪类, 抽屉弹窗, 模态对话框, 侧滑弹窗, CSS弹窗, drawer, modal, URL片段匹配

## Drawer抽屉

从父窗体边缘滑入，覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务，操作完成后，可以平滑地回到到原任务。当需要一个附加的面板来控制父窗体内容，这个面板在需要时滑出。比如，控制界面展示样式，往界面中添加内容。

更多常见于后台项目，前台一般会在移动端展示其菜单项。

## Modal对话框

需要用户处理事务，又不希望跳转页面以致打断工作流程时，可以使用 Modal 在当前页面正中打开一个浮层需要一个简洁的确认框询问用户时，承载相应的操作。

![使用CSS :target 伪类实现Drawer抽屉弹窗与Modal模态对话框](https://static.deathghost.cn/post/2021/05/11/1620663447050943.jpg)

使用CSS :target 伪类实现Drawer抽屉弹窗与Modal模态对话框

## JavaScript控制弹窗的显示与隐藏

正常情况下，我们一般会使用JavaScript控制其显示还是隐藏。如同这般:

// ...
function showDrawer() {
    bodyTag.classList.add('overflow-hidden');
    asideMenuWrap.style.display = 'block';
    const asideMenu = document.querySelector('.asideMenu');
    asideMenu.style.transform = 'none';
}
/** close drawer */
function closeDrawer(e) {
    asideMenuWrap.style.display='none';
    bodyTag.classList.remove('overflow-hidden')
}
// ...
这里不做赘述，下面看看通过CSS如何控制其显示隐藏效果。

## CSS伪类:target控制弹窗（drawer与modal）的显示与隐藏

其实方法很简单，只不过这个想法蛮有意思的，故操作一番，就是个玩而已。

我们知道HTML<a>标签可以通过它的 href 属性创建通向其他网页、文件、同一页面内的位置、电子邮件地址或任何其他 URL 的超链接。其中链接到本页的某个部分就是下面所应用的部分。

常见的单页HTML导航菜单与内容会通过锚链接方式进行联系，如：

例如, 以下URL拥有一个片段 (以#标识的) ，该片段指向一个ID为section2的页面元素:
https://www.example.com/index.html#section2
<section id="section2">Example</section>

## 基础示例

点击菜单链接，对应内容高亮显示。

p:target {
  background-color: gold;
}
/* 在目标元素中增加一个伪元素*/
p:target::before {
  content: "❤️";
  margin-right: .25em;
}
<h3>导航</h3>
<ol>
  <li><a href="#p1">定位到第一个段落!</a></li>
  <li><a href="#p2">定位到第二个段落!</a></li>
  <li><a href="#no">未定义的.</a></li>
</ol>

<h3>内容</h3>
<p id="p1">p1内容信息!</p>
<p id="p2">p2内容信息!</p>

![基础示例 效果图](https://static.deathghost.cn/post/2021/05/10/1620655257307794.gif)

基础示例 效果图

而:target CSS 伪类 代表一个唯一的页面元素(目标元素)，其id 与当前URL片段匹配 。

## 语法

:target

## CSS :target 实现Drawer抽屉弹窗

![CSS :target 实现Drawer抽屉弹窗](https://static.deathghost.cn/post/2021/05/10/1620655889778184.gif)

CSS :target 实现Drawer抽屉弹窗 效果图

页面创建一个<a>标签，href链接指向#drawer-open（即ID为drawer-open的抽屉结构），同时，预创建一个遮罩层。

<body>
	<main>
		<a href="#drawer-open" id="sidenav-button" title="打开抽屉">打开抽屉</a>
	</main>
	<aside id="drawer-open">
		<header>
			<div>标题</div>
			<a href="" title="关闭抽屉">&times;</a>
		</header>
		<div class="drawer-content">
			内容...
		</div>
		<footer>
			其他操作
		</footer>
	</aside>
	<div class="mask"></div>
</body>
html,body{margin:0;overflow: hidden;}
main {
	min-height: 100vh;
}
#drawer-open {
	--border: 1px #f2f2f2 solid;
	--size: 50vw;
	position: fixed;
	right:0;
	top: 0;
	bottom: 0;
	width: var(--size);
	visibility: hidden;
	opacity: 0;
	transform: translateX(var(--size));
	background: white;
	display: flex;
	flex-direction: column;
	z-index: 1;
}

#drawer-open header{
	display: flex;
	justify-content: space-between;
	align-items: center;
	height: 48px;
	padding: 0 1em;
	border-bottom: var(--border);
}

#drawer-open footer{
	border-top: var(--border);
	height: 48px;
	display: flex;
	padding: 0 1em;
	align-items: center;
}

#drawer-open .drawer-content {
	flex: 1;
	padding: 1em;
}

#drawer-open:target {
	visibility: visible;
	opacity: 1;
	transform: translateX(0);
	transition: visibility 0s .500ms, opacity 800ms linear;
}

#drawer-open:target ~ .mask {
	display: block;
}
.mask{
	position: absolute;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, .25);
	display: none;
	z-index: 0;
}
这样，我们就实现了一个基础的Drawer抽屉弹窗。那么Modal模态框也是同样，如下所示。

## CSS :target 实现Modal模态对话框

![CSS :target 实现Modal模态对话框 示例图](https://static.deathghost.cn/post/2021/05/10/1620655512285965.gif)

CSS :target 实现Modal模态对话框 示例图

<body>
	<main>
		<a href="#modal-open" title="打开对话框">打开对话框</a>
	</main>
	<aside id="modal-open">
		<header>
			<div>标题</div>
			<a href="" title="关闭">&times;</a>
		</header>
		<div class="modal-content">
			内容...
		</div>
		<footer>
			其他操作
		</footer>
	</aside>
	<div class="mask"></div>
</body>
html,body{margin:0;overflow: hidden;}
main {
	min-height: 100vh;
}
#modal-open {
	--border: 1px #f2f2f2 solid;
	--size: 30;
	position: fixed;
	top: 50%;
	bottom: 0;
	right:0;
	left: 50%;
	width: 30vw;
	height: 30vh;
	background: white;
	opacity: 0;
	transform: translate(-50%, -50%);
	display: flex;
	flex-direction: column;
	z-index: 1;
}

#modal-open header{
	display: flex;
	justify-content: space-between;
	align-items: center;
	height: 48px;
	padding: 0 1em;
	border-bottom: var(--border);
}

#modal-open footer{
	border-top: var(--border);
	height: 48px;
	display: flex;
	padding: 0 1em;
	align-items: center;
}

#modal-open .modal-content {
	flex: 1;
	padding: 1em;
}

#modal-open:target {
	opacity: 1;
	transition: opacity 0s .5s, opacity .5s linear;
}

#modal-open:target ~ .mask {
	display: block;
}
.mask{
	position: absolute;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, .25);
	display: none;
	z-index: 0;
}
总的来说，实际应用中没有多大的作用，只是利用CSS伪类:target实现这个效果的想法还是不错的。

## Related

- Previous: [:fullscreen设置元素在全屏模式下的CSS样式](https://www.deathghost.cn/article/css/93)
- Next: [CSS container容器查询](https://www.deathghost.cn/article/css/112)
