65.9K
CodeProject 正在变化。 阅读更多。
Home

纯 CSS 菜单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (79投票s)

2003 年 12 月 14 日

11分钟阅读

viewsIcon

413175

downloadIcon

4446

在 IE 中无需 JavaScript 的动态下拉菜单。

引言

您是否曾听说无法为 IE 创建纯 CSS 动态菜单?我敢肯定您听过。您相信吗?最好不要相信……

本文目的

本项目的目的是仅使用 CSS 来构建在 IE 中可以工作的下拉菜单。基于此,我扩展了代码,使其也能在其他一些知名浏览器上工作。

本文的目的——或多或少是教育性的,并对一些“隐藏”且很少使用的浏览器功能进行概述。同时,也为好奇的人们展示一些技巧。此外,它还可以被(不)熟练的开发者用来为他们的项目获取一些想法(代码)。

读者技能要求

实际上,我在考虑是否将其标记为“高级”。但我确信即使技能较低的人也能很好地理解它。所以,您需要具备CSS 和 HTML 的基础知识才能阅读。codeproject.com 上有一些文章可以充分解释,以便您能理解本文。

与其他 CSS 菜单有何不同?

我长时间在网上搜索 CSS 菜单,但没有找到能在 IE 中工作的纯 CSS 解决方案。当然,我在不同的网站上找到了一些有趣的想法。它们引导我找到了这个。它并不完美,代码也不干净,但我没有足够的时间来正确处理所有事情(甚至检查语法)。我找到的最有趣的替代解决方案(使用了一些 JavaScript)是基于向 LI 元素添加 hover 伪类。我从未想过这是可能的……然而,我从未想过完全不可能在 IE 中实现无脚本下拉菜单……

我的 CSS 菜单与其他菜单的主要区别在于我针对 IE 进行了优化。我找到的所有解决方案都使用 LI 作为 :hover 伪类的主要元素,但微软决定仅将其附加到 A 元素上。大多数网站指出,它们的菜单仅在 Opera 7.x 或 Mozilla 中工作。但这些浏览器只有不到 5% 的人使用!纯 CSS 菜单的美感无法在最受欢迎的浏览器中看到?不再是这样了。

那么,我们开始吧……

什么是 CSS 菜单?

好的,将鼠标移到这两个词上...

什么是纯 CSS 菜单?

这是一个动态菜单,它不使用脚本(例如 JavaScript),而仅使用 CSS 样式和一些 HTML。

难以置信?

让我们看看代码:
<STYLE type=text/css id="default" title="default" name="default"> *::-moz-any-link br,*:-moz-any-link br { /* 针对 mozilla 的解决方法 */ display:none; } div#menu * { cursor: pointer; /* 因为 IE 会在链接不激活时显示文本光标 */ } .disabled { color: red !important; background: none !important; } div#menu { background: #F5F5DC; font: 10px Verdana, sans-serif; height: 15px; white-space: nowrap; width: 100%; } div#menu .a { background: #F5F5DC; border: 1px solid #F5F5DC; color: #000000; text-decoration: none; } div#menu .a table { display: block; font: 10px Verdana, sans-serif; white-space: nowrap; } div#menu table, div#menu table a { display: none; } div#menu .a:hover, div#menu div.menuitem:hover { background: #7DA6EE; border: 1px solid #000080; color: #0000FF; margin-right:-1px; /* 解决 Opera 右边框显示不正确的问题 */ } div#menu .a:hover table, div#menu div.menuitem:hover table{ background: #FFFFFF; border: 1px solid #708090; display: block; position: absolute; white-space: nowrap; } div#menu .a:hover table a, div#menu div.menuitem:hover table a { border-left: 10px solid #708090; border-right: 1px solid white; /* 解决跳动问题 */ color: #000000; display: block; padding: 1px 12px; text-decoration: none; white-space: nowrap; z-index: 1000; } div#menu .a:hover table a:hover, div#menu div.menuitem:hover table a:hover { background: #7DA6EE; border: 1px solid #000000; border-left: 10px solid #000000; color: #000000; display: block; padding: 0px 12px; text-decoration: none; z-index: 1000; } td { border-width: 0px; padding: 0px 0px 0px 0px; } .menuitem { float: left; margin: 1px 1px 1px 1px; padding: 1px 1px 1px 1px; } .menuitem * { padding: 0px 0px 0px 0px; } #other { height: auto;visibility: visible; } #moz{ height: 1px;visibility: hidden; } #moz::-moz-cell-content{ height: auto; visibility: visible; } #other::-moz-cell-content{ height: 1px; visibility: hidden; } #holder { width: 100%; } </STYLE> <TABLE id=holder> <TR> <TD id="other"> <DIV id="menu"> <DIV class="menuitem"> <a class="a" href='#'>File<BR> <TABLE> <TR> <TD><a href=#2>Open ili op dulgo</A></TD> </TR> <TR> <TD><a href=#3>Save</A></TD> </TR> <TR> <TD><a href=#4>Close</A></TD> </TR> </TABLE> </DIV> <DIV class="menuitem"> <A class="a" href="#11">Help<BR> <TABLE> <TR> <TD><a class="disabled">..</A></TD> </TR> <TR> <TD><a href=#13>Index</A></TD> </TR> <TR> <TD><a href="#14">About</A></TD> </TR> </TABLE> </DIV> </DIV> </TD> </TR> <TR> <TD id="moz"> Mozilla specific menu! <DIV id="menu"> <DIV class="menuitem"> <a class="a" href='#'>Filezilla</A> <TABLE> <TR> <TD><a href=#2>Open</A></TD> </TR> <TR> <TD><a href=#3>Save</A></TD> </TR> <TR> <TD><a href=#4>Close</A></TD> </TR> </TABLE> </a> </DIV> <DIV class="menuitem"> <A class="a" href="#11">Helpzilla</A> <TABLE> <TR> <TD><a class="disabled">..</A></TD> </TR> <TR> <TD><a href=#13>Index</A></TD> </TR> <TR> <TD><a href="#14">About</A></TD> </TR> </TABLE> </A> </DIV> </DIV> </TD> </TR> </TABLE><BR> 

这里发生了什么?

我不会教你如何使用 CSS,这也不是我文章的重点。因此,我将从这个样式表的要点开始——`:hover` 伪类。是的,它是一个类!它的意思是:一个选择器可以继承另一个包含 `:hover` 的选择器。在我们的例子中,`A:hover TABLE` 选择的是“鼠标悬停在 `<A>` 中的 `<TABLE>`”。技巧的后续部分是我们有一个 `display` 属性设置为 `none` 的表格(意味着不可见)。这个表格位于锚标签(`<A>`,`</A>`)之间。微软表示这可能会导致 IE 出现奇怪的行为,但我没有注意到任何……

为什么我们使用表格? 这是因为它可以成功地将我们要使用的嵌套锚点与主锚点分离。实际上,它在 Mozilla 0.7 中不起作用,而且我还没有找到无 JavaScript 的解决方案。微软不允许直接嵌套锚点,因此表格是 IE 的一种解决方法(或技巧)。据我所知,只有表格才起作用。

那么,我们这里有什么? 2 个表格,其中包含锚点,而这些表格又在另一个锚点中。

        <A class="a" href="#11" >Help<BR>
        <TABLE cellpadding="0" cellspacing="0" border="0">
            <TR>
                <TD><a href="#12">Howto</A></TD>
            </TR>
            <TR>
                <TD><a href="#13">Index</A></TD>
            </TR>
            <TR>
                <TD><a href="#14">About</A></TD>
            </TR>
        </TABLE></A>

它们是隐藏的。

div#menu .a table {
   display: none;
   z-index:-1;
}

当鼠标悬停在锚点上时,浏览器会显示锚点的内容并应用样式

  • 用于链接文本
div#menu .a:hover {
   background: #7DA6EE;
   border: 1px solid black;
   color: black;z-index:0;
}
  • 用于下拉表格,我们用它来显示子菜单:一切的关键——显示下拉菜单。
div#menu .a:hover table{
   background: White;
   display: block;
   position: absolute;
   width: 125px;z-index: 0;
   border: 1px solid #708090;

}
  • 用于子菜单中的链接
div#menu .a:hover table a {
   display: block;
   color: Black;
   text-decoration: none;
   padding: 1px 12px;z-index:1000;
}

如果我们悬停在子菜单中的某个链接上,浏览器会应用

  • 用于子菜单中的链接
div#menu .a:hover table a:hover {
   display: block;
   background: #7DA6EE;
   color: black;
   text-decoration: none;
   padding: 0px 11px;
   border: 1px solid black;z-index:1000;
   visibility: visible;
}
  • 下拉菜单中链接的样式。
div#menu .a:hover table a {
   display: block;
   color: Black;
   text-decoration: none;
   padding: 1px 12px;z-index:1000;
}

也许您已经注意到了一些 `z-index` 属性。它们是我在测试菜单时发现的一些问题的解决方法。

改进

您可以将整个东西扩展到在下拉菜单中拥有子级别。只需在父表格中插入另一个 `div`(包含其内容和相同结构)来代替某个链接。现在您的菜单中就有了子级别。您必须移除 `<BR>` 标签,以使菜单显示在旁边。此外,您必须为每个子级别创建具有相同属性但名称不同的类 `.menuitem` 和 `.a` 的副本。这似乎工作量很大,但您可以简单地将它们的选择器添加到样式表中的适当部分。

我将在稍后添加完整的描述。当然,这是纯 CSS,您可以自定义一切。可能性是无限的——您的想象力不是……

样式切换(皮肤)

如果您希望为同一个菜单添加不同的皮肤供用户切换,您必须将它们添加为不同的 STYLE 表,并为它们命名为 `id='some_name'`(针对 IE)和 `name='some_name'`(针对其他浏览器)。为了不应用所有样式,您必须通过在样式定义标签中添加“disabled”(无论您是链接它还是使用内联语法)来禁用除默认样式之外的所有样式。Mozilla 和 Opera 允许从浏览器内部切换命名样式。通常,这些浏览器不会应用所有用 `name="..."` 定义的样式,并且会忽略 `id="..."`。它们还将 `name='default'` 视为默认样式表,将 `name='alternate'` 视为替代样式表。您可以通过 `title="..."` 属性定义用户将看到的样式的名称。例如:此页面上的实时演示包含了这些定义。

<STYLE type=text/css id="alternate" title="Blue" name="alternate" disabled>
...<STYLE>

<STYLE type=text/css id="default" title="Default" name="default">
...<STYLE>

请注意命名约定和顺序,我强烈建议您遵循。

IE 没有内置的 CSS 样式切换功能,所以我们必须实现一个(别无选择,我们必须使用一些 JavaScript)。

单击一个进行选择,然后向上滚动查看更改。:


它具有这个简单的代码
<ul>
  <li onclick="document.styleSheets('default').disabled=false; 
          document.styleSheets('alternate').disabled=true;">
  <a>Default</a>
  </li>
  <li onclick="document.styleSheets('alternate').disabled=false; 
            document.styleSheets('default').disabled=true;">
  <a>Blue</a>
  </li>
  <li onclick="document.styleSheets('alternate').disabled=true; 
          document.styleSheets('default').disabled=true;">
  <a>No Stylesheet</a>
  </li>
</ul>

警告!这只是一个简要概述!刷新页面将重新加载样式表的默认状态!因此,在实际使用中,您必须使用 cookie 或服务器端脚本来保存用户的选择,但这并非本文的重点。此外,上述代码仅在 IE 中有效。

结论

我强烈建议在您的网站(Web 应用程序)中使用 CSS 菜单,因为这样可以避免 JavaScript 菜单的大多数问题和 bug。这些问题通常是由 IE 奇怪的鼠标事件触发(或不触发)引起的。此外,一些浏览器能够关闭其脚本支持,当然也不支持微软的 JavaScript!

如果浏览器不支持 CSS,它仍然会显示所有链接(您可以尝试上面的样式切换器来关闭样式)。它也会显示 Mozilla 菜单。

“Mozilla 问题”——子菜单中的链接不起作用。无法在同一页面上打开(但按住 Shift+单击可以工作)。请参阅“bug”。

希望以上内容对您有所帮助。祝您有美好的一天。

更新

  1. 通过在样式表中添加此代码来解决 Mozilla 中 `
    ` 的问题
    a br,a:hover br { /*workarround for mozilla*/
     float:left;width:0px;padding:0px 0px 0px 0px;}
    

    主代码也已修正
  2. 主链接被分离,并修正了像素跳动 bug。
  3. 添加了对禁用项的支持。
  4. 添加了针对 Mozilla 的(替代)菜单,第 1 点不再是必需的。请参阅“bug”。
  5. 12 月 21 日:添加了皮肤部分(添加了一个未包含在可见代码中的替代样式)。
  6. 12 月 21 日:几乎完成了 Mozilla 的部分(有一些样式 bug,但可以工作)。
  7. 12 月 21 日:添加/重写了文章的某些部分。
  8. 12 月 21 日:添加了实时演示的源代码,可作为 .zip 文件下载。

已知错误

默认情况下,子菜单中的链接在 Mozilla 中不起作用。但我确实找到了一种解决方案。它基于再次插入一个特定于此浏览器的菜单,无需任何脚本。检查代码中提到 Mozilla(或“moz”)的部分。您会看到 HTML 部分没有嵌套锚点(最后一个 `</a>` 被移到了通常应该在的位置)。在 CSS 部分,我使用了一些未公开的选择器——纯粹的 Mozilla 特有选择器,并为 `div` 添加了 `:hover` 选择器,这得到了 Mozilla 的支持。它仍然有一些轻微的样式错误。

我收到一条评论(来自 Nick Young),说它在 Netscape 中不起作用。我确信问题与 Mozilla 相同。我需要查找更多关于它的信息。可能的修复将需要进行小的更改,因为替代代码应该能在 Netscape 中正常工作。

注释

  • 代码提取可能与主代码略有不同。没有重大更改需要更新它们。
  • 该页面由我在 Internet Explorer 5、5.5、6、Opera7.23 和 Mozilla 0.71 上进行了测试。我认为它也能在这些浏览器的早期版本上工作。
    • 附注:请不要给我发送 CSS 菜单网站的链接,我看过(全部!)Google 找到的。没有一个涉及 IE 的 JavaScript 菜单!
    • 再附注:别忘了投票 :)
© . All rights reserved.