使用 focus-within 显示 CSS 的嵌套列表

Display nested lists with CSS using focus-within

我想尝试创建一个 HTML 列表,其中嵌套的 ul 元素仅在聚焦时显示,使用 CSS 的 focus-within 伪-class.

想法是,仅使用键盘 Tab 键(暂时忽略鼠标交互),您应该能够从一个列表项关注到下一个,当您关注 a 按钮元素时,它会显示下一级列表项。那部分工作正常。但是,当您随后离开按钮元素时,它应该保持下一个 ul 可见,因为焦点 应该 位于嵌套 ul,所以嵌套的ul 应该确定为集中在.

我有它,所以当我在 ol 上设置背景颜色时,它可以作为演示。自然状态是白色背景,但是 'open' 状态是用红色背景演示的。这很好用:

.menu ul ul {
                background: #fff;
            }
            .menu button:focus + ul,
            .menu ul ul:focus-within {
                background: #f00;
            }
<nav class="menu">
            <ul>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li class="has-children">
                    <a href="#">Level 1</a>
                    <button>Show sub-menu for ‘Level 1’</button>
                    <ul>
                        <li class="has-children">
                            <a href="#">Level 2</a>
                            <button>Show sub-menu for ‘Level 2’</button>
                            <ul>
                                <li class="has-children">
                                    <a href="#">Level 3</a>
                                    <button>Show sub-menu for ‘Level 3’</button>
                                    <ul>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">Level 2</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li class="has-children">
                    <a href="#">Level 1</a>
                    <button>Show sub-menu for ‘Level 1’</button>
                    <ul>
                        <li class="has-children">
                            <a href="#">Level 2</a>
                            <button>Show sub-menu for ‘Level 2’</button>
                            <ul>
                                <li class="has-children">
                                    <a href="#">Level 3</a>
                                    <button>Show sub-menu for ‘Level 3’</button>
                                    <ul>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">Level 2</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </nav>

所以当嵌套列表变成红色时,就是它们可见的时候,否则它们是不可见的。

但是,当我用 display: blockdisplay: none 替换背景颜色时,它不起作用:

.menu ul ul {
                display: none;
            }
            .menu button:focus + ul,
            .menu ul ul:focus-within {
                display: block;
            }
<nav class="menu">
            <ul>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li class="has-children">
                    <a href="#">Level 1</a>
                    <button>Show sub-menu for ‘Level 1’</button>
                    <ul>
                        <li class="has-children">
                            <a href="#">Level 2</a>
                            <button>Show sub-menu for ‘Level 2’</button>
                            <ul>
                                <li class="has-children">
                                    <a href="#">Level 3</a>
                                    <button>Show sub-menu for ‘Level 3’</button>
                                    <ul>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">Level 2</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li>
                    <a href="#">Level 1</a>
                </li>
                <li class="has-children">
                    <a href="#">Level 1</a>
                    <button>Show sub-menu for ‘Level 1’</button>
                    <ul>
                        <li class="has-children">
                            <a href="#">Level 2</a>
                            <button>Show sub-menu for ‘Level 2’</button>
                            <ul>
                                <li class="has-children">
                                    <a href="#">Level 3</a>
                                    <button>Show sub-menu for ‘Level 3’</button>
                                    <ul>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                        <li>
                                            <a href="#">Level 4</a>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">Level 2</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </nav>

好像 display: none 状态在焦点移动到嵌套链接之前就开始了。谁能确认我在这里咆哮着一棵不可能的树,或者是否有办法让它工作?

编辑:另一件需要注意的事情是,如果您继续按 Tab 键,它会在第一级列表项中保持正确的位置,因此感觉焦点确实到达了嵌套列表的第一个锚点元素, 但它只是不识别嵌套的 ol 中有一个焦点。

设法在 li 元素而不是 ul 元素上使用 focus-within 来解决它:

    .menu ul li ul {
        display:none;
    }
    .menu button:focus + ul,
    .menu ul li:focus-within > ul {
        display: block;
    }
    .menu ul li:focus-within a:focus ~ ul {
        display: none;
    }

仍然不能 100% 理解为什么原始方案不起作用,但这是一个可行的解决方案。