仅使用 CSS 在悬停时显示下拉菜单并在单击时关闭

Posted

技术标签:

【中文标题】仅使用 CSS 在悬停时显示下拉菜单并在单击时关闭【英文标题】:Show dropdown-menu on hover and close on click using only CSS 【发布时间】:2016-12-09 14:09:56 【问题描述】:

有人可以帮助我解释为什么当我单击下拉菜单中的链接时它们不起作用?也许是因为指针事件?我试图让一个下拉菜单在单击链接或单击关闭按钮后关闭。我添加了一些很酷的东西,比如点击链接时隐藏父容器。

这样做有很多选择:

    使用:focus,但是当使用焦点时,下拉菜单将不会 在下一次悬停在下拉菜单上触发。

    在容器上使用 :activepointer-events 仅指向 活动链接,但指针事件有问题

    使用:target但和:focus有同样的问题,不会触发 第二个胡佛。

body 
    padding: 20px;

.container 
    border: 1px solid lime;
    padding: 10px;
    width: 200px;

.test1 
    display: none;
    border: 1px dashed orange;
    background: green;
    padding: 10px;
    pointer-events: none;

.container:hover .test1 
    display: inline-block;

.container:hover .test1:active 
    display: none;

a 
    pointer-events: auto;
    color: lime;
    font-weight: bold;
<ul class="container">
	 Drop down menu
	<li class="test1">
	<a class="dropdown" href="#">X Close</a>
	<ul class="content">
		 CLOSE THIS CONTENT
		<li class="link"><a href="http://www.google.com">Go to link 1</a></li>
		<li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
		<li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
	</ul>

【问题讨论】:

@hungerstar 不,不能在 Chrome 上工作。正确的行为应该是在点击链接时将您重定向到谷歌页面。 li 和 ul 结束标记丢失。 您是在说“试图在单击链接后关闭下拉菜单”。链接会有target="blank"吗?否则你怎么知道菜单是否已经关闭,因为你会被重定向到链接? 您需要X Close 还是可选的?实际上,就像关闭按钮或链接一样,因为悬停效果与它们发生冲突。 @pradeep1991singh 我需要一个关闭按钮,因为我原来的下拉菜单实际上很大,所以我需要那个。 【参考方案1】:

快速检查:Working JSFiddle

有人可以帮助我解释为什么当我单击下拉菜单中的链接时它们不起作用?也许是因为指针事件?

解释为什么会出现这种行为: 是的,你是对的,这是因为你使用 :active 选择器逻辑的方式,要详细解释,请考虑你的这个 CSS 规则

.container:hover .test1:active 
    display: none;

您的主li.test1 下有您的菜单链接,并且对内部链接的任何单击也会冒泡到此元素,因此与单击li 一样好。因此,只要按住鼠标(鼠标按下事件),它就会触发:active 事件并且您隐藏了links(即:li.test1),但是只有当鼠标按下时 click 事件才完成向下和向上。所以现在li 被隐藏,mouse up 不再在链接上。因此,如您所见,没有机会触发点击事件。这就是问题所在。


I saw other answers which you seem to be interested in and this really doesn't need any kind of hack, It can be done by just formatting your html and with some CSS changes.


解决方案:您可以使用两个不同的li,而不是将内部菜单链接包裹在 li.test1 中,一个用于 X CLose,另一个用于用于持有menu links。有了这个,我们可以确保li.test1处于活动状态时(即鼠标按下)我们可以隐藏它以及另一个新的li与之相邻。所以这意味着当用户点击X Closeli时,我们会隐藏菜单,如果他点击其他菜单项,您将被重定向。

所以你的 HTML 结构的变化应该是这样的

<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
  </li>
  <li class="MenuLinks">
    <ul class="content">
      <!-- all your links go here-->
    </ul>
  </li>
</ul>

主要的 CSS 规则是

.container:hover .test1:active,
.container:hover .test1:active + .MenuLinks 
  display: none;

下面是一个 SO 工作片段

body 
  padding: 20px;

.container 
  border: 1px solid lime;
  padding: 10px;
  width: 200px;
  list-style-type: none;

.test1,
.MenuLinks   
  display: none;
  border-color: orange;
  border-style: dashed;
  background: green;
  pointer-events: none;

.test1 
  padding: 10px;
  border-width: 1px 1px 0px 1px;

.MenuLinks 
  border-width: 0px 1px 1px 1px;

.container:hover li 
  display: block;


/*Rule to hide both test1 and MenuLinks when X Close is clicked*/
.container:hover .test1:active,
.container:hover .test1:active + .MenuLinks 
  display: none;



a 
  pointer-events: auto;
  color: lime;
  font-weight: bold;
<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
  </li>
  <!--seperate li for close-->

  <li class="MenuLinks">
    <!--wrap all your menu items here-->
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
      </li>
    </ul>
    <li>
</ul>

注意:单击链接时出现空白屏幕是由于 google 的跨域安全限制策略导致控制台出现此错误

Refused to display 'https://www.google.co.in/?gfe_rd=cr&amp;ei=x2VWWLL2Ae-K8Qfwx4ngDQ' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.

但是,当您单击链接时,您可以在网络选项卡中看到请求。

希望这会有所帮助!

【讨论】:

@Rajshekar Reddy 你的回答很好,保持 结构非常重要,但是当我点击链接时,什么都没有发生......应该重定向到谷歌页面,我'不知道为什么 @RulerNature 请在 Note 部分查看我的原因。它实际上是在重定向。因为代码在 iframe 中运行,您会看到此错误。创建您自己的 HTML 文件并放置此代码。您可以看到它重定向到指定的链接 @RulerNature 这里我将以上所有代码添加到一个 html 文件中并上传到这里 sendspace.com/file/j1kss3 。您可以下载它并查看所需的行为。如果您还需要什么,请告诉我 @Rajshekar Reddy 非常感谢你,让我测试一下你的工作,我会告诉你:) @RulerNature 给你.. 我更改了 CSS 选择器以使用 ~ jsfiddle.net/RajReddy/DTcHh/28013 选择所有兄弟姐妹【参考方案2】:

我通常会使用 JS 来执行此操作 - 但是使用 CSS 一个 hack:

首先创建一个 ID 为 closelabel 的输入,用于包装我们的关闭按钮:

  <input type="radio" id="close" />
  <li class="test1">
    <label for="close">
      <a class="dropdown" href="#">X Close</a>
    </label>

并添加这种样式而不是当前的.test1:active

.container:hover #close:active + .test1
  display: none;

#close 
  display: none;

请看下面的演示:

body 
  padding: 20px;

.container 
  border: 1px solid lime;
  padding: 10px;
  width: 200px;

.test1 
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;

.container:hover .test1 
  display: inline-block;

#close 
  display: none;

.container:hover #close:active + .test1 
  display: none;

a 
  pointer-events: auto;
  color: lime;
  font-weight: bold;
<ul class="container">
  Drop down menu
  <input type="radio" id="close" />
  <li class="test1">
    <label for="close">
      <a class="dropdown" href="#">X Close</a>
    </label>
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
      </li>
    </ul>
  </li>
</ul>

但是上面的代码在ul 中有一个无效的input 元素 - 以防止您可以稍微编辑标记以为ul 创建另一个包装器(也许您必须调整宽度/填充有点由于标记的变化) - 见下面的代码:

body 
  padding: 20px;

.container 
  border: 1px solid lime;
  padding: 10px;

ul 
  width: 200px;

.test1 
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;

.container:hover .test1 
  display: inline-block;

#close 
  display: none;

.container:hover #close:active + ul > li.test1 
  display: none;

a 
  pointer-events: auto;
  color: lime;
  font-weight: bold;
<div class="container">
  Drop down menu
  <input type="radio" id="close" />
  <ul>
    <li class="test1">
      <label for="close">
        <a class="dropdown" href="#">X Close</a>
      </label>
      <ul class="content">
        CLOSE THIS CONTENT
        <li class="link"><a href="http://www.google.com">Go to link 1</a>
        </li>
        <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
        </li>
        <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
        </li>
      </ul>
    </li>
  </ul>
</div>

【讨论】:

但链接不会将您重定向到谷歌页面:| sn-p 不起作用,但我根据您的代码创建了一个小提琴,是的,有效。只有一个问题,在该级别的 ul 中不允许输入:) @RulerNature 你是对的,我完全错过了......使用标记中的额外包装器使用更正的代码查看编辑后的答案...... sn-p 永远无法工作,因为重定向在其 iframe 内被阻止(不是你的错,这是堆栈溢出安全性)【参考方案3】:

它似乎不起作用,因为在鼠标按下时,用于保持下拉菜单打开的 :hover-class 消失了。所以鼠标向上事件不会在链接上执行,因为下拉菜单已经再次关闭,所以没有执行点击。您应该使用 javascript 打开和关闭下拉菜单。

【讨论】:

是的,我看到了,但为什么呢?这正常吗? 如果你拿走.container:hover .test1:active display: none; 它似乎有效。 点击关闭顶部按钮或链接时不会关闭容器... 是的,CSS 在交互性方面不是很强大,这就是我建议使用 Javascript 的原因,因为它要么在 CSS 中做起来非常复杂,要么不可能,但我无法证明是否不可能。【参考方案4】:

我建议删除

.container:hover .test1:active 
    display: none;

当您单击“X Close”链接时,找到另一种方法(几行 javascript 即可)关闭面板。 (顺便还修复了一些 html 缺失的标签)。现在链接可以正常工作了:

body 
    padding: 20px;

.container 
    border: 1px solid lime;
    padding: 10px;
    width: 200px;

.test1 
    display: none;
    border: 1px dashed orange;
    background: green;
    padding: 10px;
    pointer-events: none;

.container:hover .test1 
    display: inline-block;

a 
    pointer-events: auto;
    color: lime;
    font-weight: bold;
<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </li>
</ul>

【讨论】:

不是一个选项,我需要它激活才能在访问链接后或单击顶部的“关闭”按钮时关闭容器。【参考方案5】:

您可以在a 上使用labelbutton 来关闭链接,并且可以执行以下操作 -

body 
  padding: 20px;


.container 
  border: 1px solid lime;
  padding: 10px;
  width: 200px;


.test1 
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;


.container:hover .test1 
  display: inline-block;


a, label 
  pointer-events: auto;
  color: lime;
  font-weight: bold;


/* close button */
#xclose:active + .test1 
  display:none;


#xclose 
  display: none;
<ul class="container">
  Drop down menu
  <button id="xclose">X close</button>
  <li class="test1">    
    <label class="dropdown" for="xclose">X Close</label>        
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </li>
</ul>

希望这对您有所帮助(y)。

【讨论】:

【参考方案6】:

为什么将"pointer-events: none;" 添加到列表元素.test1 中?这会覆盖您的pointer-events: auto;。尝试将其删除,因为它会绑定您的点击事件。

【讨论】:

需要那里的指针事件,以便仅在链接上关闭容器,而不是在单击整个容器时关闭容器。因此,使用指针事件可以指示仅在链接上执行此操作;)【参考方案7】:

我建议尝试使用jQuery 来处理仅在按下链接时关闭容器。 pointer-events 有很多问题。因此,他们决定将该功能推迟到 CSS4。

我还认为pointer-events: none; 会阻止任何点击事件被触发,因此仅将 jQuery 用于链接是行不通的。我认为您必须使用 jQuery 修复容器的打开和关闭。

【讨论】:

使用 javascript 可以在一分钟内完成,但我不想使用 js,只有使用 css 才能做到这一点,我看到使用 :target 和 :active 做了类似的事情,但在我的情况下我需要将该行为应用于这些链接。 @RulerNature 但是你不想使用 JS 的原因是什么?为什么要花这么多时间尝试实现他们说直到 CSS4 才能得到很好支持的 CSS 功能。【参考方案8】:

在 CSS 中,您可以将 label 元素绑定到 inputs。鉴于此,您可以将关闭按钮绑定到一个输入,该输入在激活时会再次隐藏列表。

body
  padding: 20px;


a, label
  text-decoration: none;
  cursor: pointer;
  color: lime;
  font-weight: bold;


.container
  border: 1px solid lime;
  padding: 10px;
  width: 200px;


.dropdown
  display: none;
  border: 1px solid orange;
  background: green;
  margin-top: 10px;
  padding: 10px;


#close, #close:active + .dropdown
  display: none;


.container:hover .dropdown
  display: block;


.dropdown > ul
  padding: 0;
  list-style: none;
<div class="container">
  Drop down menu
  <button id="close"></button>
  <div class="dropdown">
    <label for="close">X Close</label>
    <ul>
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </div>
</div>

inputid="close" 插入到列表之前,将由带有for="close" 的标签触发 触发后,以下规则生效:

#close, #close:active + .dropdown
  display: none;

隐藏列表。 但是当您将鼠标悬停在.container 上时,它会再次出现,让您可以重复该过程。 这里不需要不必要的 JavaScript。输入即可。

您的代码也有一些问题。您将文本 Drop down menuCLOSE THIS CONTENT 直接放在 ul 中,这是无法完成的。 ul 只能包含 li,不能包含其他内容。

希望对你有帮助

【讨论】:

【参考方案9】:
.container:hover .test1:active 
display: none;

把这个改成

.container:hover .test1:focus
    display: none;
    

这里发生的情况是,当您的 div 从您的链接点击中获取“活动”伪代码时,它会在 DOM 冒泡到您的链接以提供重定向之前隐藏。将其更改为焦点可能会允许点击实际通过?

【讨论】:

【参考方案10】:

其中一个选项是使用animate。我已经用opacity 给出了您的代码示例。使用visibility:hiddenoverflow:hidden 将增强您的代码。



    body 
        padding: 20px;
    
    .container 
        border: 1px solid lime;
        padding: 10px;
        width: 200px;
    
    .test1 
        display: none;
        border: 1px dashed orange;
        background: green;
        padding: 10px;
        pointer-events: none;
    
    .container:hover .test1 
        display: inline-block;
    
    
    a 
        pointer-events: auto;
        color: lime;
        font-weight: bold;
    


.container .test1 
  -webkit-animation: seconds 1.0s forwards;
  -webkit-animation-iteration-count: 1;
  -webkit-animation-delay: 2s;
  animation: seconds 1.0s forwards;
  animation-iteration-count: 1;
  animation-delay: 2s;
  position: relative;

@-webkit-keyframes seconds 
  0% 
    opacity: 1;
  
  100% 
    opacity: 0;

  

@keyframes seconds 
  0% 
    opacity: 1;
  

  100% 
    opacity: 0;

  
    <ul class="container">
    	 Drop down menu
    	<li class="test1">
    	<a class="dropdown" href="#">X Close</a>
    	<ul class="content">
    		 CLOSE THIS CONTENT
    		<li class="link"><a href="http://www.google.com">Go to link 1</a></li>
    		<li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
    		<li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    	</ul>

【讨论】:

以上是关于仅使用 CSS 在悬停时显示下拉菜单并在单击时关闭的主要内容,如果未能解决你的问题,请参考以下文章

键入时显示下拉菜单[关闭]

悬停时显示/隐藏下拉菜单 Flutter for web

仅使用 CSS 悬停时显示文本

在引导下拉菜单中悬停时显示活动的父菜单项

单击下拉菜单时显示覆盖层

在悬停时制作 Twitter Bootstrap 菜单下拉菜单,而不是轻松点击(解决方案)