乐趣区

突破css选择器的局限,实现一个css地址选择器?

首先看一个效果,注意地址栏的变化

然后思考一下,用 css 如何实现?
css 选择器的局限
选择器是 css 中的一大特色,用于选择需要添加样式的元素。
选择器的种类有很多,比如
元素选择器
p {color:gray;}
类选择器
.box {color:gray;}
ID 选择器
#title {color:gray;}
属性选择器
[title] {color:gray;}
后代选择器
h1 span {color:gray;}
相邻兄弟选择器
h1 + p {margin-top:50px;}
这里只列举了几种,还有很多,不熟悉的可以自行搜索查找。
虽然说 css 选择器有很多种,可以满足绝大部分的需求,不过有时候还是会有一些看似合理,实际上比较棘手的问题。
比如说上面提到了相邻兄弟选择器,不过只能选择后面的兄弟节点,却不能选择前面的。
后代选择器,可以选择子元素,却没法选择父元素。
用另一种思维来突破局限
上面列出了两个我们常见的需求,然而 css 却不支持,如何解决呢?
不要在这里提 js,这完全是两种不同的思维领域
这里以实现前置兄弟选择器为例
寻找关联
首先,我们需要找到和需求有关联的选择器,毕竟要以已有的选择器为基础。
这里说的有关联指的是相近或者相反,比如子选择器 p >span 和后代选择器 p span 就是比较相近的
如果要实现鼠标相关的功能,可能就会联想到:hover、:active 等选择器。
这里要实现前置兄弟选择器很显然需要联系上已有的相邻兄弟选择器 + 和后置选择器~,都属于兄弟节点。
解决思路
其实有一种方式是很常见的。
比如有这样一个布局,我希望 span 前面的 a(也就是标签 1 和标签 2)为红色字体
<div>
<a> 标签 1 </a>
<a> 标签 2 </a>
<span> 说明 </span>
<a> 标签 3 </a>
<a> 标签 4 </a>
</div>
我们用到了后置选择器~,其实这里上述规定的位置关系都是以 html 文档中的位置为准的。
我们可以手动把这些位置颠倒一下
<div>
<a> 标签 4 </a>
<a> 标签 3 </a>
<span> 说明 </span>
<a> 标签 2 </a>
<a> 标签 1 </a>
</div>
然后我们可以采取很多种方式,让页面的顺序恢复过来。
比如
a,span{
float:right
}
这样在页面上看到的顺序还是和之前一样,分别是标签 1、标签 2、说明、标签 3、标签 4
然后就可以直接使用后置选择器~
span ~ a{
color:red
}
这样是不是就做出了在视觉上前置选择器的效果?不过需要提前把 html 里面的结构反过来,通过一些样式看着顺序是正常的即可。
还有一个思路,可以称为逆向思维吧
布局和之前一样
<div>
<a> 标签 1 </a>
<a> 标签 2 </a>
<span> 说明 </span>
<a> 标签 3 </a>
<a> 标签 4 </a>
</div>
我们可以这样来实现,先把所有的 a 都设置为红色,然后把 span 后面的 a 还原,不就达到目的了吗?
div a{
color:red;
}
span ~ a{
color:unset;
}
同样也实现了这样的目的。
当然这只是两个很简单的例子,详细的实例可以参考我之前写过的文章,更接近实际的需求

用纯 css 实现打星星效果
用纯 css 实现打星星效果(二)

css 地址选择器?
这里可以明确的说明,css 是没有关于地址的选择器的。
这里说的地址是指浏览器的地址栏,比如
http://test.com/a

http://test.com/b

或者

http://test.com#a

http://test.com#b
有人可能觉得这是个伪需求,我的地址都变了,都不是同一个页面了,我在不同的页面分别写不同的 css 不就行了?
这个思路再有些情况是是对的,有些情况下有的问题
比如从 http://test.com#a 到 http://test.com#b 这种情况下,一般都还是同一个页面
并且,现在很多单页面应用地址栏的改变并没有引起浏览器页面的刷新,地址的更变完全就是前端路由实现的,比如说我的博客
一个需求
其实我最早想到要这种选择器的时候,是做主题选择的功能。
比如 http://test.com 和 http://test.com#light 表示正常主题,http://test.com#dark 表示黑色主题。
这样做的一个好处就是可以很直观的从地址栏看出主题配色,比如可以直接以 http://test.com#dark 进入黑色主题。
类似的想法就是
下面是伪代码
#light div{
background:#fff;
color:#000;
}
#dark div{
background:#000;
color:#fff;
}
当然现在跟地址栏半毛钱的关系都没有。
那么,这样实现一个地址选择器?
思路
按照上面的思路,我们先考虑跟地址有关联的选择器,乍一看,确实找不到一个合适的
后来突然发现了:target 选择器,这个是用来选择当前活动的 HTML 锚点的。
官方的示例也都很简单,简单来讲就是如果当前地址栏为 #new,那么文档中 id 为 new 的元素就会被选中
下面是 w3school 的示例
http://www.w3school.com.cn/tiy/t.asp?f=css_sel_target
实现
那么怎样实现我们需要的功能呢?
这里有一个简单的布局
<div>
<p> 演示 </p>
</div>
如果想实现 http://test.com#dark 的功能,那么文档中就应该有个 id 为 dark 的元素可以选择到
<div id=”dark”>
<p> 演示 </p>
</div>
加上 id 后,就可以实现类似的功能了
/** 正常主题 **/
p{
background:#fff;
color:#000;
}
/** 黑色主题 **/
#dark:target p{
background:#000;
color:#fff;
}
这么容易?
上面固定了一个,如果有多个,比如红色主题,绿色主题,黄色主题 … 不可能全都写在一个 div 上吧
<!– 错误代码 –>
<div id=” 红色 ” id=” 绿色 ” id=” 黄色 ”>
<p> 演示 </p>
</div>
这里就要区分开来了,我们需要在额外的地方来添加一些 id,比如在页面的最上面
<div id=”red”></div>
<div id=”green”></div>
<div id=”blue”></div>
<div>
<p> 演示 </p>
</div>
然后结合兄弟选择器就可以实现如下效果
#red:target ~ div p{
background:red;
}
#green:target ~ div p{
background:green;
}
#blue:target ~ div p{
background:blue;
}
这里是 demo
效果如文章开头所示。
这里直接做了切换,源码可以右键直接查看
很简洁不是吗,也不需要本地存储,直接根据地址栏来决定主题配色。
小节
以上主要讲解了 css 的一些局限性,但是 css 足够灵活,有些地方可能是设计时候的缺陷,不可避免,但是完全可以通过其灵活性达到我们想要的效果
更先进的 css4 也将会到来,更多有趣的事情等着我们来发掘
插一句
还有一个更为强大的适用场景,就是多语言的适配,可以根据地址栏直接决定页面的语言
#zn:target{
/* 一些逻辑 */
}

#en:target{
/* 一些逻辑 */
}

#jp:target{
/* 一些逻辑 */
}
这个后面会专门有一篇文章来讲解,敬请期待

如果喜欢我的博客,可以多多关注一下,谢谢 ~

退出移动版