Obeta

使用CSS中鲜为人知的element函数创建一个Minimap导航器

W3C的CSS工作组经常为我们提供一些出色的CSS功能来进行实验,比如最近的<strong>element()</strong>CSS函数

需要注意的是,此新特性目前只能在 FireFox 浏览器中使用,具体可以去Caniuse中查看.因此阅读本文章前请使用最新版 FireFox 打开.

先来看一个小例子:

<!-- css -->
<style>
	#container1 {
		background-image: -moz-element(#test1);
	}
</style>

<!-- html -->
<ul id="test-list">
	<li>测试1</li>
	<li>测试2</li>
	<li>测试3</li>
</ul>
<div id="container1"></div>
  • 测试1
  • 测试2
  • 测试3

注意#container1样式必须显式设置高度,否则无法正确显式.

进阶

可以展开联想,这个element()可以实现哪些特性?下一张轮播图预览?下一页内容?又或者 Minimap!

用过 sublime text 编辑器的人都知道有一个小地图模式(vscode 也有),此模式可以预览你当前编辑框中所有代码,那么我们是否可以使用element()来实现这个功能呢?来试试!

<!-- css -->
<style>
	#minimap {
		background: rgba(255, 255, 255, 0.25) -moz-element(#article) no-repeat top /
			contain;
		width: 10vw;
		height: auto;
		max-height: 90vh;
		position: fixed;
		top: 2rem;
		right: 1rem;
	}
</style>

<!-- html -->
<main id="article"></main>
<div id="minimap"></div>

当预览图准备好了后我们可以开始增加一个滑块,拖动滑块可以移动当前页面位置.这时候是需要一点 js 来帮助的:

<style>
	#minimap-range {
		transform: translatey(-100%) rotate(90deg);
		transform-origin: bottom left;
		background-color: transparent;
		opacity: 0;
		transition: opacity 0.2s;
		margin: 0;
		padding: 0;
		max-width: 90vh;
		height: 10vw;
	}
	#minimap-range:hover {
		opacity: 0.7;
	}
	#minimap-range::-moz-range-thumb {
		width: 25px;
		height: 10vw; /* same as #minimap's width */
		background-color: #2ecc71;
		cursor: pointer;
	}
	#minimap-range::-moz-range-track {
		background-color: transparent;
	}
</style>
<div id="minimap">
	<input id="minimap-range" type="range" max="100" value="0" />
</div>
<script>
	const minimapRange = document.querySelector('#minimap-range');
	const article = document.querySelector('#article');
	minimapRange.onchange = evt =>
		scrollTo(0, parseInt($(article).height) * (evt.target.value / 100));
</script>

miniMap 的高度再由 js 计算出来,计算方式很简单,也就是等比例计算而已:

window.onload = () => {
	if (navigator.userAgent.includes('Firefox')) {
		const minimapRange = document.querySelector('#minimap-range');
		const minimap = document.querySelector('#minimap');
		const article = document.querySelector('#article');
		const $ = getComputedStyle.bind();
		minimap.style.display = 'block';
		minimapRange.style.width = minimap.style.height =
			(parseInt($(minimapRange).width) * parseInt($(article).height)) /
				parseInt($(article).width) +
			'px';
		minimapRange.onchange = evt =>
			scrollTo(0, parseInt($(article).height) * (evt.target.value / 100));
	}
};

降级支持

目前element()只有在 FireFox 中受支持,因此我们不想在其他浏览器中显示滑块,处理方案有两种:

  • 一种是使用 css 的supports函数来进行功能检查.
@supports (background: element(#article)) or
	(background: -moz-element(#article)) {
	/* fallback style */
}
  • 使用 js 的CSS.supports来检查.
if (
	!CSS.supports(
		'(background: element(#article)) or (background: -moz-element(#article))'
	)
) {
	/* fallback code */
}

如果你想使用兼容方式,可以考虑pagemap.

你也可以完善这个 miniMap,比如滚动页面也改变滑块位置.

引用

个人随笔记录,内容不保证完全正确,若需要转载,请注明作者和出处.